Here's my version, which I ported from similar code I had for PyGame.
It draws the rectangle as a polygon to a canvas and returns this, so the rectangle can be reused efficiently. It also allows to set a different foreground (border) and background (fill) color. Both may have alpha ~= 255, but if the foreground color has transparency, it will overlap with the background by half the border width (I deemed this acceptable to avoid having to calculate different polygons for the border and the background).
The code could be optimzed as in the above posts by calculating only one of the rounded corners and transposing/rotating it for the others, but since you only need to calculate the rectangle coordinates once and then just redraw the canvas (unless the shape changes), I didn't think it very important.
Here's a demo .love:
- Rounded rectangles screenshot
- screenshot-20141110-085615.png (110.59 KiB) Viewed 1877 times
(In the screenshot I used the DroidSans font instead of the default font, but did not include it in the .love. Kudos to Triplenox for the
background pic.)
Code: Select all
--- Draw rectangles with rounded corners with LÖVE (http://love2d.org)
local modname = ...
local M = {}
_G[modname] = M
package.loaded[modname] = M
local ipairs = ipairs
local lg = love.graphics
local PI = math.pi
local sin = math.sin
local cos = math.cos
local unpack = unpack
if _ENV then
_ENV = M
else
setfenv(1, M)
end
local TWOPI = PI * 2
local HALFPI = PI * 0.5
local PI32 = PI + HALFPI
function extend(t1, t2)
for _, v in ipairs(t2) do
t1[#t1+1] = v
end
end
--- Return table of coordinates of a circle arc with step resolution
function arc_coords(x, y, radius, start, stop, step)
step = step or (TWOPI * 0.01)
if start > stop then
step = -step
end
local coords = {}
for angle = start, stop, step do
coords[#coords+1] = x + cos(angle) * radius
coords[#coords+1] = y + sin(angle) * radius
end
return coords
end
--- Draw rectangle with rounded corners to a canvas and return it
function draw_rect(mode, w, h, radius, color, bgcolor, linewidth, aa, step)
radius = radius or 0
linewidth = linewidth or 1
local hlw = linewidth * 0.5
local x1 = radius + hlw
local y1 = radius + hlw
local x2 = w - radius - hlw
local y2 = h - radius - hlw
if radius > 0 then
coords = arc_coords(x1, y1, radius, PI, PI32, step)
extend(coords, arc_coords(x2, y1, radius, PI32, TWOPI, step))
extend(coords, arc_coords(x2, y2, radius, 0, HALFPI, step))
extend(coords, arc_coords(x1, y2, radius, HALFPI, PI, step))
else
coords = {x1, hlw, x2, hlw, w - hlw, y2, x1, h - hlw}
end
local canvas = lg.newCanvas(w + linewidth, h + linewidth, "normal", aa)
lg.setCanvas(canvas)
canvas:clear()
lg.setBackgroundColor({255, 255, 255, 0})
lg.setBlendMode('alpha')
lg.setLineStyle("smooth")
if bgcolor then
lg.setLineWidth(0)
lg.setColor(unpack(bgcolor))
lg.polygon("fill", coords)
end
lg.setColor(unpack(color))
lg.setLineWidth(linewidth)
lg.polygon(mode, coords)
lg.setCanvas()
return canvas
end
Also available as a Gist
here.