You could eliminate 3/4 of the trig calls.
If you time one million calls (without the love.graphics.polygon call), the times I get are 7.35 seconds for Robin's function versus 4.57 seconds for the modified code.
Really not too important because most of the time is actually spent filling the rectangle.
Think the code is OK but could contain some unfound bugs.
Plugged it into Robin's demo and got the same figures.
Rounded Rectangles
Re: Rounded Rectangles
- Attachments
-
- radiusRectangle.love
- slightly modified Robin's code
- (840 Bytes) Downloaded 157 times
- Robin
- The Omniscient
- Posts: 6506
- Joined: Fri Feb 20, 2009 4:29 pm
- Location: The Netherlands
- Contact:
Re: Rounded Rectangles
I'd like to update my Gist with your changes, is that okay?
Help us help you: attach a .love.
Re: Rounded Rectangles
I have some reservations about my modifications.
Not overly confident that the code is 100% but you are welcome to do what ever you want with it.
Best
Edit: As expected, an error.
Have to add 'equal' to avoid the problem with gaps forming when 'line' mode is used with love.polygon on polygons containing redundant points.
The code now is:
(Not really sure why you used clockwise point order???)
Not overly confident that the code is 100% but you are welcome to do what ever you want with it.
Best
Edit: As expected, an error.
Code: Select all
rx = rx >= w / 2 and w / 2 - 1 or rx
ry = ry >= h / 2 and h / 2 - 1 or ry
The code now is:
Code: Select all
function radiusRectangle( mode, x, y, w, h, rx, ry )
ry = ry or rx
local pts = {}
local precision = math.floor( 0.2 * ( rx + ry ) )
local hP = math.pi / 2
rx = rx >= w / 2 and w / 2 - 1 or rx
ry = ry >= h / 2 and h / 2 - 1 or ry
local sin, cos = math.sin, math.cos
for i = 0, precision do -- upper right
local a = ( i / precision - 1 ) * hP
pts[#pts+1] = x + w - rx * ( 1 - cos(a) )
pts[#pts+1] = y + ry * ( 1 + sin(a) )
end
for i = 2 * precision + 2 , 1, -2 do -- lower right
pts[#pts+1] = pts[i-1]
pts[#pts+1] = 2 * y - pts[i] + h
end
for i = 1, 2 * precision + 2, 2 do -- lower left
pts[#pts+1] = -pts[i] + 2 * x + w
pts[#pts+1] = 2 * y - pts[i+1] + h
end
for i = 2 * precision+2 , 1, -2 do -- upper left
pts[#pts+1] = -pts[i-1] + 2 * x + w
pts[#pts+1] = pts[i]
end
love.graphics.polygon( mode, pts )
end
- SpotlightKid
- Prole
- Posts: 6
- Joined: Mon Nov 10, 2014 7:57 am
- Location: Cologne, Germany
Re: Rounded Rectangles
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:
(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.)
Also available as a Gist here.
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:
(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
Who is online
Users browsing this forum: No registered users and 2 guests