hal/shader/slug.lisp
--------------------------------------------------------------------- Tunable values.
Each special is one number the shaders would otherwise carry as a
literal. A shader body names it by the unstarred symbol; the parser
folds that name to a literal through shader-source-value and remembers
it did, so a live pipeline rebuilds when the special moves. A game that
owns a session wraps these in knobs (luvcraft::define-knob in
luvcraft/text.lisp); here they are only the values.
The box filter's width in pixels. One is the reference's exact pixel coverage; wider softens (and, past the dilation, clips) the edge.
The exponent applied to coverage. 1 is linear coverage; the reference's SLUG_WEIGHT is 0.5, a square root that boosts thin strokes.
How the pixel footprint in em space is measured from the coordinate derivatives: 0 is the gradient length (L2), 1 is fwidth (L1), which is what the reference uses.
1 leaves a band's sorted curve list at the first curve wholly behind the sample; 0 walks every curve (the reference without its break).
Below this |a| a curve's polynomial is solved as linear; also the floor of every division in the coverage combination.
0 renders ink; 1 paints each glyph's quad with its band loads (red the horizontal band's curve count, green the vertical's, over sixteen).
How far a glyph's bounding quad grows past its outline, in filter widths (pixels when the filter is one pixel wide), so the filter's half-width and a little more always lie inside the quad. The reference dilates exactly half a pixel; a hair more forgives the per-vertex approximation of the pixel size across a perspective quad.
A constant dilation of every glyph quad in em, added on the CPU when the quads are laid out. Zero leaves the work to the per-vertex dilation; the value luv used before dynamic dilation was 0.035.
The em distance a glyph quad laid out at pixels-per-em should grow on
each side: the live dilation in filter widths, plus the static padding.
For a stage that cannot dilate per vertex (a flat screen quad, whose pixel
scale is known when it is laid out).
font-loader's sCapHeight from its OS/2 table, in font units, or NIL when
the font has no OS/2 table or one too old (version < 2) to carry it.
ZPB-TTF does not read OS/2, so this seeks the table itself.
The font size nearest size (in pixels per em) at which font-loader's cap
height lands on a whole number of pixels, so the tops of most capitals
share the pixel grid: the reference's substitute for hinting. Falls back
to size when the font declares no cap height.
Return the two Slug root-eligibility bits as numeric masks.
Only strict positivity matters. The arithmetic form is Table 1 of Lengyel's 2017 paper without an integer lookup, and is the form generated into the proof pixel shader. #S2F8SA
FSign makes zero exactly "not positive", matching the eligibility table without epsilon classification at shared control points.
Turn an unbounded signed WINDING estimate into a fill by the fill rule, then boost it by the optical weight.
The nonzero rule saturates; even-odd folds the winding number back and forth between zero and one, as the reference's SLUG_EVENODD does. The optical weight is an exponent: one leaves coverage linear, the reference's SLUG_WEIGHT is one half.
The pixel scale of the em square along each axis, from the sample coordinate's screen derivatives, already divided by the filter width so the rest of the pipeline works in filter widths rather than pixels.
The footprint norm chooses between the gradient length and fwidth.
Fold one horizontal-band curve into STATE = (xcov, xweight, done).
CURVE holds p1 and p2, NEXT's first two lanes p3. DONE becomes one when the curve lies wholly more than half a filter width left of the sample: the band is sorted by descending maximum x, so nothing after it can contribute and the fold's :UNTIL leaves the loop. #3YHNO3
Fold one vertical-band curve into STATE = (ycov, yweight, done); the band is sorted by descending maximum y.
Whether a band fold with STATE = (cov, weight, done) may stop: the last curve was wholly behind the sample and the early exit is on.
Render one connected four-quadratic contour with Slug's two-ray pixel math.
This is a typed shader function: its LET* bindings and nested calls are parsed directly into shader objects. The fixed curve count remains an atelier proof, not the band-texture font renderer. #OWR8OZ
One band per axis is the complete correctness path for an outline: every serialized curve participates. Subdividing the same lists into spatial bands is the subsequent culling optimization, not a different algorithm.
The reference's SlugRender: pick the pixel's horizontal and vertical band, walk each band's sorted curve list until a curve is wholly behind the sample, and combine the two rays' coverage by their weights. The glyph's data lives at ATLAS-BASE inside shared band and curve atlases; every address below is relative to it.
The debug view paints the whole quad with the two bands' loads, so the banding of a glyph -- and what the band count buys -- can be seen at a glance.
Division of two represented quantities.
(name)The live value NAME stands for in shader source, or NIL when NAME names none. Returns (VALUES VALUE DECLARATION FOUND-P): VALUE is a real, and DECLARATION, when given, is a represented-value declaration whose quantity the literal takes on.
The interactive block world built on luv.
(name (&key label (group :grading) documentation
(class ''scalar-knob)
quantity (type 'single-float)
unit-label minimum maximum step)
place)Define NAME as a knob of CLASS over the setf-able PLACE. PLACE may refer to SESSION, so a knob can live on the session -- its sky clock, its player -- as well as in a special. QUANTITY is a quantity plist as DEFINE-QUANTITY-CONSTANT takes, (:quantity ... :unit ...); it and TYPE make the knob's declaration, which…
The box filter's width in pixels. One is the reference's exact pixel coverage; wider softens (and, past the dilation, clips) the edge.
0 fills by the nonzero winding rule, 1 by even-odd; fractions blend.
The exponent applied to coverage. 1 is linear coverage; the reference's SLUG_WEIGHT is 0.5, a square root that boosts thin strokes.
How the pixel footprint in em space is measured from the coordinate derivatives: 0 is the gradient length (L2), 1 is fwidth (L1), which is what the reference uses.
1 leaves a band's sorted curve list at the first curve wholly behind the sample; 0 walks every curve (the reference without its break).
Below this |a| a curve's polynomial is solved as linear; also the floor of every division in the coverage combination.
0 renders ink; 1 paints each glyph's quad with its band loads (red the horizontal band's curve count, green the vertical's, over sixteen).
How far a glyph's bounding quad grows past its outline, in filter widths (pixels when the filter is one pixel wide), so the filter's half-width and a little more always lie inside the quad. The reference dilates exactly half a pixel; a hair more forgives the per-vertex approximation of the pixel size across a…
A constant dilation of every glyph quad in em, added on the CPU when the quads are laid out. Zero leaves the work to the per-vertex dilation; the value luv used before dynamic dilation was 0.035.
(name special)(pixels-per-em)The em distance a glyph quad laid out at PIXELS-PER-EM should grow on each side: the live dilation in filter widths, plus the static padding. For a stage that cannot dilate per vertex (a flat screen quad, whose pixel scale is known when it is laid out).
Addition over compatible quantities.
Multiplication and scalar scaling.
(font-loader)FONT-LOADER's sCapHeight from its OS/2 table, in font units, or NIL when the font has no OS/2 table or one too old (version < 2) to carry it. ZPB-TTF does not read OS/2, so this seeks the table itself.
A simple Org table without formulas.
Logical conjunction of tests and raw truth values.
Test whether one compatible scalar is at least another.
(font-loader size)The font size nearest SIZE (in pixels per em) at which FONT-LOADER's cap height lands on a whole number of pixels, so the tops of most capitals share the pixel grid: the reference's substitute for hinting. Falls back to SIZE when the font declares no cap height.
The maximum of compatible quantities.
(y1 y2 y3)Return the two Slug root-eligibility bits as numeric masks. Only strict positivity matters. The arithmetic form is Table 1 of Lengyel's 2017 paper without an integer lookup, and is the form generated into the proof pixel shader. #S2F8SA
(name parameters &body body)Subtraction or unary negation.
(name parameters &body body)Define a reusable typed shader expression with ordinary source syntax. The body is parsed at each call site, so argument types and quantity meanings flow through the same operator protocol as handwritten shader expressions. LET* is lexical inside the function. The definition macro records source; its body does not…
Compare compatible quantities and produce dimensionless values.
The componentwise absolute value of a raw value.
Interpolate compatible quantities by a scalar amount.
The componentwise square root of a raw value.
Constrain a quantity between compatible bounds.
Select and reorder vector components by a designator such as :XYZ or :RGB.
Turn an unbounded signed WINDING estimate into a fill by the fill rule, then boost it by the optical weight. The nonzero rule saturates; even-odd folds the winding number back and forth between zero and one, as the reference's SLUG_EVENODD does. The optical weight is an exponent: one leaves coverage linear, the…
The minimum of compatible quantities.
Raise a dimensionless value to a dimensionless power.
The pixel scale of the em square along each axis, from the sample coordinate's screen derivatives, already divided by the filter width so the rest of the pipeline works in filter widths rather than pixels. The footprint norm chooses between the gradient length and fwidth.
The inner product of two vectors.
Fold one horizontal-band curve into STATE = (xcov, xweight, done). CURVE holds p1 and p2, NEXT's first two lanes p3. DONE becomes one when the curve lies wholly more than half a filter width left of the sample: the band is sorted by descending maximum x, so nothing after it can contribute and the fold's :UNTIL…
Fold one vertical-band curve into STATE = (ycov, yweight, done); the band is sorted by descending maximum y.
Whether a band fold with STATE = (cov, weight, done) may stop: the last curve was wholly behind the sample and the early exit is on.
Test whether one compatible scalar is greater than another.
The non-negative remainder of integer division.
Convert one scalar float or unsigned value to a 32-bit unsigned integer.
Render one connected four-quadratic contour with Slug's two-ray pixel math. This is a typed shader function: its LET* bindings and nested calls are parsed directly into shader objects. The fixed curve count remains an atelier proof, not the band-texture font renderer. #OWR8OZ
(name options &body body)(name options &body body)Define NAME as a function that reparses its shader source on every call. Where DEFINE-SHADER parses once at load, this parses each time it is asked, so live named values (SHADER-SOURCE-VALUE) folded into the body are read afresh -- and noted in *SHADER-SOURCE-VALUE-REFERENCES* -- by every pipeline build, exactly as a…
Load one exact two-dimensional texel at an unsigned integer coordinate.
Convert one scalar float or unsigned value to a 32-bit float.
Test whether one compatible scalar is less than another.
Testing whether a computed root lies in [0,1] is numerically unstable at shared endpoints. Slug instead classifies the signs of the three control coordinates before calculating roots. Let s1, s2, and s3 be one only when the corresponding coordinate is strictly positive; zero is non-positive. The exact eligibility…
Read against the 2026 reference shaders and the retrospective, luv's Slug had the algorithm -- eligibility, two rays, weighted combination, sorted bands -- but not the reference's shape around it. This figure closes the gaps and names what the reference hard-codes. – Early exit. The reference leaves a band's loop at…
Intent: prove that luv's shader DSL can state, lower, compile, and actually draw the numerically important pixel-stage core before designing texture and font-data machinery. Evidence: – slug-quadratic-outline is now a typed shader function over the eight points of a connected four-curve contour. It composes ordinary…
Slug's quadratic outline calculation, first as a fixed proof and then as the data-driven band texture path used by real outlines.
The shape of the shaders follows Lengyel's open reference implementation (github.com/EricLengyel/Slug, 2017-2026): sorted bands with an early exit, a nonzero or even-odd fill, an optional optical-weight boost, and a bounding polygon dilated per vertex rather than by a constant. The constants the reference bakes in are named values here, so a live pipeline can be retuned from a knob without editing shader source.