This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Data Format
What the two textures hold, texel by texel: for writing your own shaders, porting them to another shading language, or checking data by hand. It is the format of Eric Lengyel's reference shaders. A program that uses slug-coverage and write-shape-data needs none of this.
Both textures are 4096 texels wide. Rows are counted from 0 at the top, and a place is (x, y): column, row. A linear position is x + 4096 × y.
Below, max-x is the index of a shape's last vertical band, shape-vertical-band-count − 1, and max-y that of its last horizontal band, shape-horizontal-band-count − 1.
Curve texture
:rgba16-float: four half-precision floats a texel, red, green, blue, alpha.
A quadratic curve with control points p1 (start), p2 (control) and p3 (end), relative to its shape's em origin:
| Texel | red | green | blue | alpha |
|---|---|---|---|---|
The curve's place (x, y) |
p1.x | p1.y | p2.x | p2.y |
(x + 1, y) |
p3.x | p3.y | (next curve's p2.x) | (next curve's p2.y) |
A run is curves that each start where the one before ended. The second texel of a curve is then the first texel of the next, so a run of N curves takes N + 1 texels:
texel: x x+1 x+2 ... x+N
p1 c1 p2 c2 p3 c3 pN+1 0
└ curve 0 ┘
└ curve 1 ┘
The last texel's blue and alpha are 0. The shader reads a curve's second texel at x + 1 of the same row without wrapping, so a run never crosses the end of a row: a run that does not fit in what is left of a row starts the next one, and a run of more than 4095 curves is split into runs that each fit a row.
A straight line is stored with p2 = p3. Shapes never share texels.
Band texture
:rg16-uint: two 16-bit unsigned integers a texel, red and green.
At a shape's place, (shape-data-x, shape-data-y), its band headers, one texel per band, in one row:
| Texel | red | green |
|---|---|---|
place + 0 … place + max-y |
Curves in horizontal band 0 … max-y, bottom first | Offset of its list |
place + max-y + 1 … place + max-y + 1 + max-x |
Curves in vertical band 0 … max-x, left first | Offset of its list |
The headers never cross the end of a row.
A band's offset is the linear distance from the shape's place to the start of its list. The shader finds the list by adding it to the place's x and carrying into y: x' = (x + offset) mod 4096, y' = y + (x + offset) div 4096. Offsets are 16-bit, so a shape's lists start within 65536 texels of its place.
A list is one texel per curve, the curve's place in the curve texture:
| Texel | red | green |
|---|---|---|
list + i |
x of curve i's first texel | y of curve i's first texel |
Lists never cross the end of a row, since the shader reads them without wrapping. Bands holding the same curves share one list. An empty band has a count of 0.
Order within a list
- A horizontal band's curves are sorted by their greatest x, greatest first. The shader casts its ray to the right and stops at the first curve whose greatest x is more than half a pixel left of the pixel: every curve after it is further left.
- A vertical band's curves are sorted by their greatest y, greatest first, for the ray up.
A curve whose control points all have the same y, a horizontal line, is in no horizontal band; one whose points all have the same x, in no vertical band.
Bands and the band transform
A shape's bounds, from xmin to xmax and ymin to ymax, are cut into max-x + 1 vertical bands of equal width and max-y + 1 horizontal bands of equal height. A curve is in a band if its control points reach into the band widened by the store's epsilon on both sides.
A pixel at (u, v) in ems is in vertical band clamp(int(u × scale-x + offset-x), 0, max-x) and horizontal band clamp(int(v × scale-y + offset-y), 0, max-y), with
scale-x = (max-x + 1) / (xmax - xmin) offset-x = -xmin × scale-x
scale-y = (max-y + 1) / (ymax - ymin) offset-y = -ymin × scale-y
A shape with no width has a scale-x of 0, and one with no height a scale-y of 0: one band.
What write-shape-data writes
Eight single-floats, from start:
start+0 scale-x start+4 shape-data-x
start+1 scale-y start+5 shape-data-y
start+2 offset-x start+6 max-x
start+3 offset-y start+7 max-y, plus 4096 for the even-odd rule
The first four are slug-coverage's banding, a vec4; the last four its data, an ivec4. The last four are whole numbers below 2²⁴, so single-floats hold them exactly. Bit 12 of data's fourth component, the 4096, is the even-odd flag; the shader masks it off with & 0xFF to get max-y. At most 32 bands are made each way, so max-y fits in those 8 bits.
The glyph words
The reference vertex shader's tex.zw, as shape-glyph-words returns them:
tex.z bits 31–16: data y bits 15–0: data x
tex.w bit 28: even-odd bits 23–16: max-y bits 15–0: max-x
The reference vertex shader unpacks them into the same ivec4 as data: (data-x, data-y, max-x, max-y + 4096 × even-odd).
Half floats
The curve texture's floats are IEEE 754 binary16: a sign bit, 5 bits of exponent biased by 15, 10 of fraction; subnormals below 2⁻¹⁴; at most 65504. half-float-bits converts a real to them, rounding to nearest with ties to even, and half-float-value converts back.