luv

Workshop wiki

slug-outline.lisp

hal/shader/slug-outline.lisp

system luv · 25 definitions · on GitHub

CPU-owned quadratic outline and Slug band preprocessing.

in-package#:luv.slug
define-conditionslug-outline-error
error
reason:initarg:reason:readerslug-outline-error-reason
details:initarg:details:initformnil:readerslug-outline-error-details
:report
lambda
conditionstream
formatstream"Cannot pack Slug outline: ~A~@[ (~S)~]."
slug-outline-error-reasoncondition
slug-outline-error-detailscondition
defparameter*slug-maximum-band-count*16

The most bands an axis may be cut into when the count is chosen automatically. The reference's format allows 256; more bands cost header texels and, past a point, only overlap epsilon.

defparameter*slug-band-epsilon*1/1024

How far, in em, a band reaches past its edges when deciding which curves it holds, so a curve grazing a boundary is in both bands. The reference suggests 1/1024.

defstructslug-pointxy
defstructslug-quadraticstartcontrolend
defstructslug-outlinecontours
defstructslug-bandcurve-indicesascending-curve-indices
defstructslug-packed-outlinecurvesmin-xmin-ymax-xmax-yhorizontal-bandsvertical-bands
defunmake-slug-line
startend

Encode a straight segment in Slug's {p1,p2,p2} quadratic form.

make-slug-quadratic:startstart:controlend:endend
defunslug-point=
leftright
and
=
slug-point-xleft
slug-point-xright
=
slug-point-yleft
slug-point-yright
defunvalidate-slug-contour
contourcontour-index
unlesscontour
error'slug-outline-error:reason:empty-contour:detailscontour-index
loopforcurveincontourfornextin
append
restcontour
list
firstcontour
forcurve-indexfrom0unless
slug-point=
slug-quadratic-endcurve
slug-quadratic-startnext
do
error'slug-outline-error:reason:disconnected-contour:details
listcontour-indexcurve-index
contour
defunslug-outline-curves
outline

Return outline's validated curves in contour order.

loopforcontourin
slug-outline-contoursoutline
forcontour-indexfrom0append
validate-slug-contourcontourcontour-index
defunslug-quadratic-signed-area
curve
let*
p0
slug-quadratic-startcurve
p1
slug-quadratic-controlcurve
p2
slug-quadratic-endcurve
c
slug-point-xp0
f
slug-point-yp0
b
*2
-
slug-point-xp1
c
e
*2
-
slug-point-yp1
f
a
+c
-
*2
slug-point-xp1
slug-point-xp2
d
+f
-
*2
slug-point-yp1
slug-point-yp2
*1/2
+
-
*ce
*fb
-
*cd
*fa
/
-
*bd
*ae
3
defunslug-contour-signed-area
contour

Return the exact signed area swept by a connected quadratic contour.

reduce#'+contour:key#'slug-quadratic-signed-area:initial-value0
defunslug-contour-orientation
contour
let
cond
plusparea
:counterclockwise
minusparea
:clockwise
t:degenerate
defunslug-curve-coordinate-values
curveaxis
let
reader
ecaseaxis
:x#'slug-point-x
:y#'slug-point-y
mapcarreader
list
slug-quadratic-startcurve
slug-quadratic-controlcurve
slug-quadratic-endcurve
defunslug-band-range
curveaxisminimummaximumband-count&key
epsilon1/1024
let
span
-maximumminimum
if
zeropspan
values00
let
size
/spanband-count
values
max0
floor
-
/size
epsilon
min
1-band-count
floor
+
/size
epsilon
defunslug-index-order-p
curvesaxisdirectionleftright
let*
key
ecasedirection
:descending#'slug-curve-max
:ascending#'slug-curve-min
left-value
funcallkey
arefcurvesleft
axis
right-value
funcallkey
arefcurvesright
axis
or
ecasedirection
:descending
>left-valueright-value
:ascending
<left-valueright-value
and
=left-valueright-value
<leftright
defunmake-slug-bands
curvesmembership-axissort-axisminimummaximumband-count
let
members
make-arrayband-count:initial-elementnil
loopforcurveacrosscurvesforindexfrom0unless
slug-curve-axis-parallel-pcurvemembership-axis
do
multiple-value-bind
lowhigh
slug-band-rangecurvemembership-axisminimummaximumband-count:epsilon*slug-band-epsilon*
loopforbandfromlowtohighdo
pushindex
arefmembersband
loopforindicesacrossmemberscollect
make-slug-band:curve-indices
sort
copy-listindices
lambda
leftright
slug-index-order-pcurvessort-axis:descendingleftright
:ascending-curve-indices
sort
copy-listindices
lambda
leftright
slug-index-order-pcurvessort-axis:ascendingleftright
defunslug-band-load
curvesmembership-axisminimummaximumband-count

Return the largest number of curves any of band-count bands cut along membership-axis holds, and the total over all bands.

let
loads
make-arrayband-count:initial-element0
loopforcurveacrosscurvesunless
slug-curve-axis-parallel-pcurvemembership-axis
do
multiple-value-bind
lowhigh
slug-band-rangecurvemembership-axisminimummaximumband-count:epsilon*slug-band-epsilon*
loopforbandfromlowtohighdo
incf
arefloadsband
values
reduce#'maxloads
reduce#'+loads
defunchoose-slug-band-count
curvesmembership-axisminimummaximum&optional

The fewest bands in [1, maximum-count] that minimize the most curves any one band holds: the reference's advice for choosing a glyph's band counts, with ties going to the cheaper header block.

let
best-count1
best-loadnil
loopforcountfrom1to
max1
minmaximum-count
lengthcurves
do
let
load
slug-band-loadcurvesmembership-axisminimummaximumcount
when
or
nullbest-load
<loadbest-load
setfbest-countcountbest-loadload
best-count
defunpack-slug-outline
outline&keyhorizontal-band-countvertical-band-count

Build conservative, sorted horizontal and vertical Slug curve bands.

A band count left unspecified is chosen per axis by choose-slug-band-count.

let*
curve-list
curves
coercecurve-list'vector
curve-count
lengthcurves
when
zeropcurve-count
error'slug-outline-error:reason:empty-outline
let*
min-x
loopforcurveacrosscurvesminimize
min-y
loopforcurveacrosscurvesminimize
max-x
loopforcurveacrosscurvesmaximize
max-y
loopforcurveacrosscurvesmaximize
horizontal-count
orhorizontal-band-count
choose-slug-band-countcurves:ymin-ymax-y
vertical-count
orvertical-band-count
choose-slug-band-countcurves:xmin-xmax-x
unless
and
<=1horizontal-count255
<=1vertical-count255
error'slug-outline-error:reason:invalid-band-count:details
listhorizontal-countvertical-count
make-slug-packed-outline:curvescurves:min-xmin-x:min-ymin-y:max-xmax-x:max-ymax-y:horizontal-bands
make-slug-bandscurves:y:xmin-ymax-yhorizontal-count
:vertical-bands
make-slug-bandscurves:x:ymin-xmax-xvertical-count