So - I want a rectangle with rounded corners. Before I write my own nasty version with lines and quarter ellipses and such - is there some more elegant way to do it I’m missing? Or has someone perhaps already done this?
Nasty way is the only way, for now. (Or custom sprites.)
Once the image class is available you could compute them in an image. Though it would be nice to have them available as a primitive shape.
FWIW - after futzing around a bit, a rectangle with a circle on either end is close enough to a rounded rectangle for my purposes (ie. it looks good and can be an extended key).
now to figure out a better/faster way to do the math.
I did this by filling a rectangle and then drawing the edges (one by one) with the line end mode set to ROUND.
That’s a pretty good solution.
I really liked Andrew’s idea. So I wrote a function to draw them:
function roundRect(x, y, w, h, r)
pushStyle()
insetPos = vec2(x+r,y+r)
insetSize = vec2(w-2*r,h-2*r)
rectMode(CORNER)
rect(insetPos.x,insetPos.y,insetSize.x,insetSize.y)
if r > 0 then
smooth()
lineCapMode(ROUND)
strokeWidth(r*2)
line(insetPos.x, insetPos.y,
insetPos.x + insetSize.x, insetPos.y)
line(insetPos.x, insetPos.y,
insetPos.x, insetPos.y + insetSize.y)
line(insetPos.x, insetPos.y + insetSize.y,
insetPos.x + insetSize.x, insetPos.y + insetSize.y)
line(insetPos.x + insetSize.x, insetPos.y,
insetPos.x + insetSize.x, insetPos.y + insetSize.y)
end
popStyle()
end
Here’s a sample use. (Parameter to adjust the corner radius.)
-- Main
function setup()
parameter("CornerRadius",0,50)
end
function draw()
-- This sets the background color to black
background(0, 0, 0)
-- Stroke and fill must be the same
stroke(255,0,0)
fill(255,0,0)
roundRect(0, 0, 100, 100, CornerRadius)
end
Cute! It suffers the “balls!” issue a bit, but that’s me being nitpicky - this is, dare I say, elegant.
It does, we hope to resolve the ‘balls’ issue on the line shader itself.
It suffers the what issue a bit?
Hah. BALLS.
\cleans out ears\
Nope, still not any the wiser. Will it become obvious if I run that code?
Thin smooth() lines with ROUND end caps look like they have balls on either end. It’s due to the way the line shader draws lines (the caps are something like half a pixel bigger than the line itself, or using a different antialiasing width, to be determined).
Ah, now I understand. Thanks.
In Codea 1.3 you can retrieve the style information from all style functions by calling without arguments. So I’ve updated this code to correctly use only the fill colour, as a normal rect would.
It could even be updated to respect the current rectMode.
function roundRect(x, y, w, h, r)
pushStyle()
insetPos = vec2(x+r,y+r)
insetSize = vec2(w-2*r,h-2*r)
rectMode(CORNER)
rect(insetPos.x,insetPos.y,insetSize.x,insetSize.y)
r,g,b,a = fill()
stroke(r,g,b,a)
if r > 0 then
smooth()
lineCapMode(ROUND)
strokeWidth(r*2)
line(insetPos.x, insetPos.y,
insetPos.x + insetSize.x, insetPos.y)
line(insetPos.x, insetPos.y,
insetPos.x, insetPos.y + insetSize.y)
line(insetPos.x, insetPos.y + insetSize.y,
insetPos.x + insetSize.x, insetPos.y + insetSize.y)
line(insetPos.x + insetSize.x, insetPos.y,
insetPos.x + insetSize.x, insetPos.y + insetSize.y)
end
popStyle()
end
Here’s a sample use. (Parameter to adjust the corner radius.)
-- Main
function setup()
parameter("CornerRadius",0,50)
end
function draw()
-- This sets the background color to black
background(0, 0, 0)
-- Set the fill color
fill(255,0,0)
roundRect(0, 0, 100, 100, CornerRadius)
end
Here’s my version of it (I had to rewire clip()
for this)
_clip = clip
function clip(x, y, w, h)
if x ~= nil then
local m = modelMatrix()
x = x * m[1] + m[13]
y = y * m[6] + m[14]
w = w * m[1]
h = h * m[6]
_clip(x, y, w, h)
else
_clip()
end
end
function roundRect(x, y, w, h, r)
r = r or math.min(w, h) / 8
pushStyle()
noSmooth()
ellipseMode(RADIUS)
if rectMode() == CORNERS then
w = w - x
h = h - y
elseif rectMode() == CENTER then
x = x - w / 2
y = y - h / 2
elseif rectMode() == RADIUS then
x = x - w
y = y - h
w = w * 2
h = h * 2
end
if r > math.min(w, h) / 2 then
r = math.min(w, h) / 2
end
rectMode(CORNER)
pushMatrix()
translate(x, y)
clip(r, 0, w - r * 2, h)
rect(0, 0, w, h)
clip(0, r, w, h - r * 2)
rect(0, 0, w, h)
r = r + .25
if strokeWidth() + .25 > r then
fill(stroke())
noStroke()
end
clip(0, 0, r + 1, r + 1)
ellipse(r, r, r + 1)
clip(w - r - 1, 0, r + 2, r + 1)
ellipse(w - r, r, r + 1)
clip(0, h - r - 1, r + 1, r + 2)
ellipse(r, h - r, r + 1)
clip(w - r - 1, h - r - 1, r + 2, r + 2)
ellipse(w - r, h - r, r + 1)
clip()
popMatrix()
popStyle()
end
function draw()
rectMode(CORNER)
fill(255, 0, 0, 255)
stroke(255, 255, 255, 255)
strokeWidth(20)
roundRect(10, 10, WIDTH / 2 - 20, HEIGHT / 2 - 20, 100)
fill(0, 255, 0, 255)
stroke(255, 127, 0, 255)
strokeWidth(55)
rectMode(CORNERS)
roundRect(WIDTH / 2 + 10, 10, WIDTH - 10, HEIGHT / 2 - 10, 50)
fill(0, 0, 255, 255)
noStroke()
rectMode(CENTER)
roundRect(WIDTH / 4, HEIGHT * .75, WIDTH / 2 - 20, HEIGHT / 2 - 20, 75)
strokeWidth(10)
stroke(127, 0, 127, 255)
noFill()
rectMode(RADIUS)
translate(WIDTH * .75, HEIGHT * .75)
roundRect(0, 0, WIDTH / 4 - 10, HEIGHT / 4 - 10)
end
Anyone notice that when drawing with an aplha channel, that the line caps draw the alpha channel twice? The “caps” look like they have twice the density inside of the line than outside of the line.
Yep, it looks like a rect with two ellipses drawn on the end, right? I was thinking about rewriting it in a shader to make it smooth, but I got side tracked…
I have a mesh version of rounded rectangles if anyone would like it.
sure!