Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
226 commits
Select commit Hold shift + click to select a range
b41b253
add sdfy
elcritch Jun 8, 2025
9c0cef0
refactor
elcritch Jun 8, 2025
0dba5bc
refactor
elcritch Jun 8, 2025
ee6887e
adding in sdfy
elcritch Jun 8, 2025
43d0a3e
adding in sdfy
elcritch Jun 8, 2025
9612de4
adding in sdfy
elcritch Jun 8, 2025
dd00368
adding in sdfy
elcritch Jun 8, 2025
c8dbd8c
adding in sdfy
elcritch Jun 8, 2025
f712ec3
adding in sdfy
elcritch Jun 8, 2025
c0b0ad2
adding in sdfy
elcritch Jun 8, 2025
b340893
update sdfy
elcritch Jun 9, 2025
1d15cdc
revert back draw extras
elcritch Jun 10, 2025
6b07682
update sdfy
elcritch Jun 10, 2025
670e5ce
update sdfy
elcritch Jun 10, 2025
091c27d
update sdfy
elcritch Jun 10, 2025
ab13e57
update sdfy
elcritch Jun 10, 2025
7f59623
update sdfy
elcritch Jun 10, 2025
81b576a
update sdfy
elcritch Jun 10, 2025
2b273d0
update sdfy
elcritch Jun 10, 2025
bf35058
update sdfy
elcritch Jun 10, 2025
f3b421e
update sdfy
elcritch Jun 10, 2025
df72a7d
update sdfy
elcritch Jun 10, 2025
5e7e57b
update sdfy
elcritch Jun 10, 2025
bb8ae34
update sdfy
elcritch Jun 10, 2025
874d333
update sdfy
elcritch Jun 10, 2025
4bfb2b2
update sdfy
elcritch Jun 10, 2025
f81ec1a
update sdfy
elcritch Jun 10, 2025
5579b90
update sdfy
elcritch Jun 10, 2025
071eaed
update sdfy
elcritch Jun 10, 2025
5e3df9d
update sdfy
elcritch Jun 10, 2025
03e4f2b
update sdfy
elcritch Jun 10, 2025
f8119cd
update sdfy
elcritch Jun 10, 2025
591f192
update sdfy
elcritch Jun 10, 2025
e1d77eb
update sdfy
elcritch Jun 10, 2025
539af94
update sdfy
elcritch Jun 10, 2025
e9d36ee
update sdfy
elcritch Jun 10, 2025
0b0f378
update sdfy
elcritch Jun 10, 2025
94efe7d
update sdfy
elcritch Jun 10, 2025
b7fccb1
update sdfy
elcritch Jun 10, 2025
c9c3bf3
update sdfy
elcritch Jun 10, 2025
7b97218
update sdfy
elcritch Jun 10, 2025
f57a3fa
update sdfy
elcritch Jun 10, 2025
3c9c580
update sdfy
elcritch Jun 10, 2025
6d696ad
update sdfy
elcritch Jun 11, 2025
80969a9
update sdfy
elcritch Jun 11, 2025
d3df867
update sdfy
elcritch Jun 11, 2025
7ba5cb2
update sdfy
elcritch Jun 11, 2025
1297881
update sdfy
elcritch Jun 11, 2025
561e7ed
update sdfy
elcritch Jun 11, 2025
4bb98d0
update sdfy
elcritch Jun 11, 2025
60299eb
update sdfy
elcritch Jun 11, 2025
ae09537
update sdfy
elcritch Jun 11, 2025
f719cf2
update sdfy
elcritch Jun 11, 2025
12342a1
update sdfy
elcritch Jun 11, 2025
69ed7e3
update sdfy
elcritch Jun 11, 2025
230b460
update sdfy
elcritch Jun 11, 2025
42f9db9
fix simd rgbx
elcritch Jun 11, 2025
92ea9da
fix simd rgbx
elcritch Jun 11, 2025
613242a
fix simd rgbx
elcritch Jun 11, 2025
f2ca366
fix simd rgbx
elcritch Jun 11, 2025
d0562cb
update sdfy
elcritch Jun 11, 2025
f5b7913
fix inset shadow insets - sse
elcritch Jun 12, 2025
68cf9e7
fix inset shadow insets - sse
elcritch Jun 12, 2025
07cdb6e
fix inset shadow insets - sse
elcritch Jun 12, 2025
ad6ba5a
css update
elcritch Jun 12, 2025
b5144aa
renderer update
elcritch Jun 12, 2025
1742676
updates
elcritch Jun 16, 2025
7e5d159
updates
elcritch Jun 16, 2025
99427cf
updates
elcritch Jun 16, 2025
00e2011
refactor to enum loops
elcritch Jun 16, 2025
d68c95e
change to non-transform offset
elcritch Jun 16, 2025
f21025d
reuse sides
elcritch Jun 16, 2025
24893e6
reuse sides
elcritch Jun 16, 2025
c0611d9
reuse sides
elcritch Jun 16, 2025
43dd36a
reuse sides
elcritch Jun 16, 2025
b73d0d0
reuse sides
elcritch Jun 16, 2025
15005e1
reuse sides
elcritch Jun 16, 2025
0042264
reuse sides
elcritch Jun 16, 2025
052adaa
reuse sides
elcritch Jun 16, 2025
2d3bd67
reuse sides
elcritch Jun 16, 2025
c1ccd1a
reuse sides
elcritch Jun 16, 2025
fe4b7df
reuse sides
elcritch Jun 16, 2025
414df90
change corners order
elcritch Jun 16, 2025
53111f5
change corners order
elcritch Jun 16, 2025
6af424c
change corners order
elcritch Jun 16, 2025
ba02d69
change corners order
elcritch Jun 16, 2025
9ee6a8a
change corners order
elcritch Jun 16, 2025
1f4839f
change corners order
elcritch Jun 16, 2025
b7f94c0
cleanup
elcritch Jun 16, 2025
40abdb3
cleanup
elcritch Jun 16, 2025
13be31d
cleanup
elcritch Jun 16, 2025
9fa5f14
cleanup
elcritch Jun 16, 2025
de2ab96
cleanup
elcritch Jun 16, 2025
ef8d36e
cleanup
elcritch Jun 16, 2025
007ede0
cleanup
elcritch Jun 16, 2025
8e7292e
cleanup
elcritch Jun 16, 2025
fce0fd3
cleanup
elcritch Jun 16, 2025
5b2accb
cleanup
elcritch Jun 16, 2025
03f9c9f
cleanup
elcritch Jun 16, 2025
8e2c817
cleanup
elcritch Jun 16, 2025
824e739
cleanup
elcritch Jun 16, 2025
ed3d98d
cleanup
elcritch Jun 16, 2025
89f21be
cleanup
elcritch Jun 16, 2025
8fe23ae
rename
elcritch Jun 17, 2025
6affc33
rename
elcritch Jun 17, 2025
84b70bf
refactor
elcritch Jun 17, 2025
1de329c
refactor
elcritch Jun 17, 2025
e088be6
refactor
elcritch Jun 17, 2025
441b99c
refactor
elcritch Jun 17, 2025
9ad9d6f
refactor
elcritch Jun 17, 2025
dcfece5
refactor
elcritch Jun 17, 2025
d54489f
refactor
elcritch Jun 17, 2025
a17fb47
trying independently generated corners
elcritch Jun 17, 2025
dda5935
trying independently generated corners
elcritch Jun 17, 2025
db61a24
trying independently generated corners
elcritch Jun 17, 2025
dc2ba13
trying independently generated corners
elcritch Jun 17, 2025
36b7aaf
trying independently generated corners
elcritch Jun 17, 2025
bfc5bc9
trying independently generated corners
elcritch Jun 17, 2025
ad32afd
trying independently generated corners
elcritch Jun 17, 2025
1af9900
trying independently generated corners
elcritch Jun 17, 2025
156a045
trying independently generated corners
elcritch Jun 17, 2025
03a23e9
trying independently generated corners
elcritch Jun 17, 2025
71bd8f6
perfect corners same radii
elcritch Jun 17, 2025
cbe1a10
perfect corners same radii
elcritch Jun 17, 2025
d9918a5
perfect corners same radii
elcritch Jun 17, 2025
12a25e7
perfect corners same radii
elcritch Jun 17, 2025
a684fbe
perfect corners same radii
elcritch Jun 17, 2025
d7b5ad7
perfect corners same radii
elcritch Jun 17, 2025
e7a93b8
perfect corners same radii
elcritch Jun 17, 2025
1285f3a
perfect corners same radii
elcritch Jun 17, 2025
1913473
perfect corners same radii
elcritch Jun 17, 2025
f8cda48
perfect corners same radii
elcritch Jun 17, 2025
ee4ccf6
change to loop
elcritch Jun 17, 2025
fb2df93
change to loop
elcritch Jun 17, 2025
0e81adc
change to loop
elcritch Jun 17, 2025
650e695
change to loop
elcritch Jun 17, 2025
5c8378e
change to loop
elcritch Jun 17, 2025
3d285ea
change to loop
elcritch Jun 17, 2025
f3c5bbd
fixing 21 patch setup
elcritch Jun 18, 2025
b0bb357
shadow patch21 setup
elcritch Jun 18, 2025
f2ba1d5
shadow patch21 setup
elcritch Jun 18, 2025
2791657
shadow patch21 setup
elcritch Jun 18, 2025
a360922
shadow patch21 setup
elcritch Jun 18, 2025
6b2cc5a
shadow patch21 setup
elcritch Jun 18, 2025
2af1d86
shadow patch21 setup
elcritch Jun 18, 2025
1e3a88f
shadow patch21 setup
elcritch Jun 18, 2025
cecdf4d
shadow patch21 setup
elcritch Jun 18, 2025
0cbcc78
shadow patch21 setup
elcritch Jun 18, 2025
807ad2d
shadow patch21 setup
elcritch Jun 18, 2025
64766d0
shadow patch21 setup
elcritch Jun 18, 2025
03b216e
shadow patch21 setup
elcritch Jun 18, 2025
6b9a2ac
shadow patch21 setup
elcritch Jun 18, 2025
b940a04
shadow patch21 setup
elcritch Jun 18, 2025
93b27a3
shadow patch21 setup
elcritch Jun 18, 2025
250c124
shadow patch21 setup
elcritch Jun 18, 2025
4caa58e
shadow patch21 setup
elcritch Jun 18, 2025
e7e2ee0
shadow patch21 setup
elcritch Jun 18, 2025
3d48a11
shadow patch21 setup
elcritch Jun 18, 2025
3cb6ff2
shadow patch21 setup
elcritch Jun 18, 2025
fee01f9
shadow patch21 setup
elcritch Jun 18, 2025
5906ddc
shadow patch21 setup
elcritch Jun 18, 2025
03167f6
shadow patch21 setup
elcritch Jun 18, 2025
69bdfa3
shadow patch21 setup
elcritch Jun 18, 2025
741b5ac
shadow patch21 setup
elcritch Jun 18, 2025
4f819f6
shadow patch21 setup
elcritch Jun 18, 2025
7f95bff
shadow patch21 setup
elcritch Jun 18, 2025
e3fd1f2
shadow patch21 setup
elcritch Jun 18, 2025
24c4f4b
shadow patch21 setup
elcritch Jun 18, 2025
9de873c
shadow patch21 setup
elcritch Jun 18, 2025
7496c94
shadow patch21 setup
elcritch Jun 18, 2025
3028b8f
shadow patch21 setup
elcritch Jun 18, 2025
f606993
shadow patch21 setup
elcritch Jun 18, 2025
5ba84c9
shadow patch21 setup
elcritch Jun 18, 2025
2ebcfed
shadow patch21 setup
elcritch Jun 18, 2025
d6eb0bd
fix ci
elcritch Jun 18, 2025
155541f
re-add clips
elcritch Jun 18, 2025
240c9c8
fixes
elcritch Jun 18, 2025
7ffa345
fixes
elcritch Jun 18, 2025
f0c2dbc
fixes
elcritch Jun 18, 2025
abfe22e
fixes
elcritch Jun 18, 2025
515daf5
fixes
elcritch Jun 18, 2025
37b1c59
fixes
elcritch Jun 18, 2025
bc97857
fix prs
elcritch Jun 19, 2025
3f58393
fix prs
elcritch Jun 19, 2025
b6ab4d3
fix prs
elcritch Jun 19, 2025
0f0d088
fix prs
elcritch Jun 19, 2025
56a5dd8
fix prs
elcritch Jun 19, 2025
e21eca4
fix tbutton
elcritch Jun 20, 2025
ea2cfcc
fix tbutton
elcritch Jun 20, 2025
88a1aa2
fix tbutton
elcritch Jun 20, 2025
7d17ed9
fix inner
elcritch Jun 20, 2025
30ca101
fix inner
elcritch Jun 20, 2025
beb16cf
fix inner
elcritch Jun 20, 2025
f65e401
fix inner
elcritch Jun 20, 2025
3bd8a64
fix inner
elcritch Jun 20, 2025
cc0a07c
fix inner
elcritch Jun 20, 2025
b2814a8
fix inner
elcritch Jun 20, 2025
dd9b724
fix inner
elcritch Jun 20, 2025
f4cc331
fix inner
elcritch Jun 20, 2025
ce91410
fix inner
elcritch Jun 20, 2025
5a0e330
fix inner
elcritch Jun 20, 2025
dd3d10c
fix inner
elcritch Jun 20, 2025
8157ae6
fix inner
elcritch Jun 20, 2025
d88e57e
fix inner
elcritch Jun 20, 2025
dfb95f1
fix inner
elcritch Jun 20, 2025
fbfa9db
fix inner
elcritch Jun 20, 2025
b171038
fix inner
elcritch Jun 20, 2025
0afb8a4
fix inner
elcritch Jun 20, 2025
00e1818
fix inner
elcritch Jun 20, 2025
afabad7
fix inner
elcritch Jun 20, 2025
6cb82e9
fix inner
elcritch Jun 20, 2025
8c12026
fix inner
elcritch Jun 20, 2025
ca6d4d3
fix inner
elcritch Jun 20, 2025
81383e2
fix inner
elcritch Jun 20, 2025
6398ca3
fix inner
elcritch Jun 20, 2025
68578c8
fix inner
elcritch Jun 20, 2025
22ef734
fix inner
elcritch Jun 20, 2025
3ff6d0f
fix inner
elcritch Jun 20, 2025
ba69bca
fix inner
elcritch Jun 20, 2025
9b2bd76
fix inner
elcritch Jun 20, 2025
4b5c710
fix inner
elcritch Jun 20, 2025
d7b1ed0
fix inner
elcritch Jun 20, 2025
e318607
fix inner
elcritch Jun 20, 2025
18085ba
fix inner
elcritch Jun 20, 2025
b1fe12e
Merge remote-tracking branch 'origin/main' into add-sdfy-symmetric-co…
elcritch Jun 20, 2025
557b4a9
fix inner
elcritch Jun 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion figuro.nimble
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version = "0.16.0"
version = "0.16.1"
author = "Jaremy Creechley"
description = "UI Engine for Nim"
license = "MIT"
Expand Down
3 changes: 3 additions & 0 deletions src/figuro/renderer/opengl/glcontext.nim
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ export drawextras
logScope:
scope = "opengl"

proc round*(v: Vec2): Vec2 =
vec2(round(v.x), round(v.y))

const quadLimit = 10_921

type Context* = ref object
Expand Down
168 changes: 95 additions & 73 deletions src/figuro/renderer/utils/drawboxes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ proc drawOuterBox*[R](ctx: R, rect: Rect, padding: float32, color: Color) =
ctx.drawRect(rectBottom, color)
ctx.drawRect(rectRight, color)

proc toHex*(h: Hash): string =
const HexChars = "0123456789ABCDEF"
result = newString(sizeof(Hash) * 2)
var h = h
for i in countdown(result.high, 0):
result[i] = HexChars[h and 0xF]
h = h shr 4


proc drawRoundedRect*[R](
ctx: R,
rect: Rect,
Expand All @@ -45,106 +54,119 @@ proc drawRoundedRect*[R](
bw = cbs.sideSize.float32
bh = cbs.sideSize.float32

let hash = hash((6217, int(cbs.sideSize), int(cbs.maxRadius), int(weight), doStroke, outerShadowFill))
# let hash = hash((6217, int(cbs.sideSize), int(cbs.maxRadius), int(weight), doStroke, outerShadowFill))
let hash = hash((6217, doStroke, outerShadowFill, cbs.padding, cbs.weightSize))
let cornerCbs = cbs.roundedBoxCornerSizes(radii, innerShadow = false)

block drawCorners:
var cornerHashes: array[DirectionCorners, Hash]
for corner in DirectionCorners:
cornerHashes[corner] = hash((hash, 41, int(radii[corner])))

var missingAnyCorner = false
let fill = rgba(255, 255, 255, 255)
let clear = rgba(0, 0, 0, 0)

for corner in DirectionCorners:
if cornerHashes[corner] notin ctx.entries:
# echo "missing corner: ", corner, " hash: ", cornerHashes[corner], " radius: ", radii[corner], " sideSize: ", cbs.sideSize, " maxRadius: ", cbs.maxRadius, " weight: ", weight, " doStroke: ", doStroke, " outerShadowFill: ", outerShadowFill
missingAnyCorner = true
break

if missingAnyCorner:
let fill = rgba(255, 255, 255, 255)
let clear = rgba(0, 0, 0, 0)
var center = vec2(bw, bh)
let wh = vec2(2*bw+1, 2*bh+1)
let corners = radii.cornersToSdfRadii()
var circle = newImage(int(2*bw), int(2*bh))
if cornerHashes[corner] in ctx.entries:
continue

let cornerCbs = cornerCbs[corner]
let corners = vec4(cornerCbs.radius.float32)
var image = newImage(cornerCbs.sideSize, cornerCbs.sideSize)
let wh = vec2(2*cornerCbs.sideSize.float32, 2*cornerCbs.sideSize.float32)

if doStroke:
drawSdfShape(circle,
center = center,
drawSdfShape(image,
center = vec2(cornerCbs.center.float32),
wh = wh,
params = RoundedBoxParams(r: corners),
pos = fill.to(ColorRGBA),
neg = clear.to(ColorRGBA),
factor = weight + 0.5,
factor = cbs.weightSize.float32,
spread = 0.0,
mode = sdfModeAnnular)
else:
drawSdfShape(circle,
center = center,
drawSdfShape(image,
center = vec2(cornerCbs.center.float32, cornerCbs.center.float32),
wh = wh,
params = RoundedBoxParams(r: corners),
pos = fill.to(ColorRGBA),
neg = clear.to(ColorRGBA),
mode = sdfModeClipAA)

let patches = sliceToNinePatch(circle)
# Store each piece in the atlas
let cornerImages: array[DirectionCorners, Image] = [
dcTopLeft: patches.topLeft,
dcTopRight: patches.topRight,
dcBottomLeft: patches.bottomLeft,
dcBottomRight: patches.bottomRight,
]

for corner in DirectionCorners:
let cornerHash = cornerHashes[corner]
if cornerHash notin ctx.entries:
let image = cornerImages[corner]
case corner:
of dcTopLeft:
discard
of dcTopRight:
image.flipHorizontal()
of dcBottomRight:
image.flipHorizontal()
image.flipVertical()
of dcBottomLeft:
image.flipVertical()
ctx.putImage(toKey(cornerHash), image)
if color.a != 1.0 and false:
var msg = "corner"
msg &= (if doStroke: "-stroke" else: "-noStroke")
msg &= "-weight" & $weight
msg &= "-radius" & $cornerCbs.radius
msg &= "-sideSize" & $cornerCbs.sideSize
msg &= "-wh" & $wh.x
msg &= "-padding" & $cbs.padding
msg &= "-center" & $cornerCbs.center
msg &= "-doStroke" & (if doStroke: "true" else: "false")
msg &= "-outerShadowFill" & (if outerShadowFill: "true" else: "false")
msg &= "-corner-" & $corner
msg &= "-hash" & toHex(cornerHashes[corner])
echo "generating corner: ", msg
image.writeFile("examples/" & msg & ".png")

ctx.putImage(toKey(cornerHashes[corner]), image)

let
xy = rect.xy
zero = vec2(0, 0)
cornerSize = vec2(bw, bh)
topLeft = xy + vec2(0, 0)
topRight = xy + vec2(w - bw, 0)
bottomLeft = xy + vec2(0, h - bh)
bottomRight = xy + vec2(w - bw, h - bh)

ctx.saveTransform()
ctx.translate(topLeft)
ctx.drawImage(cornerHashes[dcTopLeft], zero, color)
ctx.restoreTransform()

ctx.saveTransform()
ctx.translate(topRight + cornerSize / 2)
ctx.rotate(-Pi/2)
ctx.translate(-cornerSize / 2)
ctx.drawImage(cornerHashes[dcTopRight], zero, color)
ctx.restoreTransform()

ctx.saveTransform()
ctx.translate(bottomLeft + cornerSize / 2)
ctx.rotate(Pi/2)
ctx.translate(-cornerSize / 2)
ctx.drawImage(cornerHashes[dcBottomLeft], zero, color)
ctx.restoreTransform()

ctx.saveTransform()
ctx.translate(bottomRight + cornerSize / 2)
ctx.rotate(Pi)
ctx.translate(-cornerSize / 2)
ctx.drawImage(cornerHashes[dcBottomRight], zero, color)
ctx.restoreTransform()

cpos = [
dcTopLeft: xy + vec2(0, 0),
dcTopRight: xy + vec2(w - bw, 0),
dcBottomLeft: xy + vec2(0, h - bh),
dcBottomRight: xy + vec2(w - bw, h - bh)
]

coffset = [
dcTopLeft: vec2(0, 0),
dcTopRight: vec2(cornerCbs[dcTopRight].sideDelta.float32, 0),
dcBottomLeft: vec2(0, cornerCbs[dcBottomLeft].sideDelta.float32),
dcBottomRight: vec2(cornerCbs[dcBottomRight].sideDelta.float32, cornerCbs[dcBottomRight].sideDelta.float32)
]

ccenter = [
dcTopLeft: vec2(0.0, 0.0),
dcTopRight: vec2(cornerCbs[dcTopRight].sideSize.float32, cornerCbs[dcTopRight].sideSize.float32),
dcBottomLeft: vec2(cornerCbs[dcBottomLeft].sideSize.float32, cornerCbs[dcBottomLeft].sideSize.float32),
dcBottomRight: vec2(cornerCbs[dcBottomRight].sideSize.float32, cornerCbs[dcBottomRight].sideSize.float32)
]

darkGrey = rgba(50, 50, 50, 255).to(Color)

angles = [dcTopLeft: 0.0, dcTopRight: -Pi/2, dcBottomLeft: Pi/2, dcBottomRight: Pi]

# if color.a != 1.0:
# echo "drawing corners: ", "BL: " & toHex(cornerHashes[dcBottomLeft]) & " color: " & $color & " hasImage: " & $ctx.hasImage(cornerHashes[dcBottomLeft]) & " cornerSize: " & $blCornerSize & " blPos: " & $(bottomLeft + blCornerSize / 2) & " delta: " & $cornerCbs[dcBottomLeft].sideDelta & " doStroke: " & $doStroke

for corner in DirectionCorners:
ctx.saveTransform()
ctx.translate(cpos[corner] + coffset[corner] + ccenter[corner] / 2)
ctx.rotate(angles[corner])
ctx.translate(-ccenter[corner] / 2)
ctx.drawImage(cornerHashes[corner], zero, color)

if cornerCbs[corner].sideDelta > 0:
let inner = cornerCbs[corner].inner.float32
let sideDelta = cornerCbs[corner].sideDelta.float32
let sideSize = cornerCbs[corner].sideSize.float32
# inner patch left, right, and then center
if doStroke:
ctx.drawRect(rect(0, inner, cbs.weightSize.float32, sideDelta), color)
ctx.drawRect(rect(inner, 0, sideDelta, cbs.weightSize.float32), color)
else:
ctx.drawRect(rect(0, inner, inner, sideDelta), color)
ctx.drawRect(rect(inner, 0, sideDelta, sideSize), color)
# we could do two boxes, but this matches our shadow needs
ctx.drawRect(rect(inner, inner, sideDelta, sideDelta), color)

ctx.restoreTransform()

block drawEdgeBoxes:
let
Expand Down
140 changes: 0 additions & 140 deletions src/figuro/renderer/utils/drawextras.nim
Original file line number Diff line number Diff line change
Expand Up @@ -73,143 +73,3 @@ proc sliceToNinePatch*(img: Image): tuple[
bottom: fbottom,
left: fleft
)

proc generateCircleBox*(
radii: array[DirectionCorners, float32],
offset = vec2(0, 0),
spread: float32 = 0.0'f32,
blur: float32 = 0.0'f32,
stroked: bool = true,
lineWidth: float32 = 0.0'f32,
fillStyle: ColorRGBA = rgba(255, 255, 255, 255),
shadowColor: ColorRGBA = rgba(255, 255, 255, 255),
outerShadow = true,
innerShadow = true,
innerShadowBorder = true,
outerShadowFill = false,
): Image =

# Additional size for spread and blur
let lw = lineWidth.ceil()
let (maxRadius, sideSize, totalSize, padding, inner) = getCircleBoxSizes(radii, blur, spread, lineWidth)

# Create a canvas large enough to contain the box with all effects
let img = newImage(totalSize, totalSize)
let bxy = newContext(img)

# Calculate the inner box dimensions
let innerWidth = inner.float32
let innerHeight = inner.float32

# Create a path for the rounded rectangle with the given dimensions and corner radii
proc createRoundedRectPath(
width, height: float32,
radii: array[DirectionCorners, float32],
padding: float32,
lw: float32
): pixie.Path =
# Start at top right after the corner radius
let hlw = lw / 2.0
let padding = padding + hlw
let width = width - lw
let height = height - lw

result = newPath()
let topRight = vec2(width - radii[dcTopRight], 0)
result.moveTo(topRight + vec2(padding, padding))

# Top right corner
let trControl = vec2(width, 0)
result.quadraticCurveTo(
trControl + vec2(padding, padding),
vec2(width, radii[dcTopRight]) + vec2(padding, padding)
)

# Right side
result.lineTo(vec2(width, height - radii[dcBottomRight]) + vec2(padding, padding))

# Bottom right corner
let brControl = vec2(width, height)
result.quadraticCurveTo(
brControl + vec2(padding, padding),
vec2(width - radii[dcBottomRight], height) + vec2(padding, padding)
)

# Bottom side
result.lineTo(vec2(radii[dcBottomLeft], height) + vec2(padding, padding))

# Bottom left corner
let blControl = vec2(0, height)
result.quadraticCurveTo(
blControl + vec2(padding, padding),
vec2(0, height - radii[dcBottomLeft]) + vec2(padding, padding)
)

# Left side
result.lineTo(vec2(0, radii[dcTopLeft]) + vec2(padding, padding))

# Top left corner
let tlControl = vec2(0, 0)
result.quadraticCurveTo(
tlControl + vec2(padding, padding),
vec2(radii[dcTopLeft], 0) + vec2(padding, padding)
)

# Close the path
result.lineTo(topRight + vec2(padding, padding))

# Create the path for our rounded rectangle
let path = createRoundedRectPath(innerWidth, innerHeight, radii, padding.float32, lw)

# Draw the box
if stroked:
bxy.strokeStyle = fillStyle
bxy.lineWidth = lineWidth
bxy.stroke(path)
else:
bxy.fillStyle = fillStyle
bxy.fill(path)

# Apply inner shadow if requested
if innerShadow or outerShadow or outerShadowFill:
let spath = createRoundedRectPath(innerWidth, innerHeight, radii, padding.float32, lw)

let ctxImg = newContext(img)
if outerShadowFill:
let spath = spath.copy()
spath.rect(0, 0, totalSize.float32, totalSize.float32)
ctxImg.saveLayer()
ctxImg.clip(spath, EvenOdd)
ctxImg.fillStyle = fillStyle
ctxImg.rect(0, 0, totalSize.float32, totalSize.float32)
ctxImg.fill()
ctxImg.restore()

let shadow = img.shadow(
offset = offset,
spread = spread,
blur = blur,
color = shadowColor
)

let combined = newImage(totalSize, totalSize)
let bxy = newContext(combined)
if innerShadow:
bxy.saveLayer()
bxy.clip(spath, EvenOdd)
bxy.drawImage(shadow, pos = vec2(0, 0))
bxy.drawImage(shadow, pos = vec2(0, 0))
bxy.drawImage(shadow, pos = vec2(0, 0))
bxy.restore()
if outerShadow:
let spath = spath.copy()
spath.rect(0, 0, totalSize.float32, totalSize.float32)
bxy.saveLayer()
bxy.clip(spath, EvenOdd)
bxy.drawImage(shadow, pos = vec2(0, 0))
bxy.restore()
if innerShadowBorder:
bxy.drawImage(img, pos = vec2(0, 0))
return combined
else:
return img
Loading