public sealed class IconAtlasTurns a filled path into a distance field in the glyph atlas, so that an icon costs four vertices instead of a tessellation.
No guide page documents this yet — the page shows what the code says about itself.
Remarks
An icon is a glyph that is not in a font. Both are small vector art drawn at whatever size a layout gives them, both are asked for again every frame, and both are wanted in one colour at a time. Text has been drawn from a distance field since there was text here; icons were tessellated, and the difference is not small — a hand-drawn editor glyph whose strokes are pre-expanded into quads measured 13,419 vertices, where the same picture out of the atlas is four.
⚠ The same texture as the glyphs, and it has to be. UiRenderer binds one atlas descriptor for the whole frame; a second texture would be a second set, a second pipeline and a batch break between every icon and the label beside it. Sharing means an icon draws through the pipeline that is already bound — so a row of an outliner is one draw for its glyph and its text together rather than three.
⚠ A path must arrive in its own local space, and this is the invariant the whole thing rests on. Encoding a field costs milliseconds; a key that separated two instances of one icon would re-encode per icon per frame and be far slower than the tessellation it replaces. A draw list is rebuilt every frame from wherever things are, so a tree scrolled by a fraction of a pixel moves every icon in it — and the answer is the one DrawCommandKind.Text already uses: a glyph run carries where the line starts and each glyph's offset along it, so two identical labels in different places hold identical runs. A field path carries its position on the command and its geometry from its own corner, so two identical icons in different places hold identical segments and hash to one entry.
⚠ Rounding the coordinates instead does not work, and it is worth saying why so nobody tries it again. Quantising to a fraction of a pixel looks like it should absorb the float error between one scrolled frame and the next, and it does — for one coordinate. An icon has of the order of a thousand of them, so on any given frame one of them is within its own error of a bucket boundary and flips; measured, that was 199 re-encodings in 200 scrolled frames. A tolerance cannot fix a problem that is a thousand independent chances to differ.
⚠ An entry is still per size. A glyph's field is size-independent because a font's outline arrives in design units; a path reaches the draw list already fitted to the box the layout produced. That costs an entry per size actually used, which for an editor is a few dozen — and it is the one way this is weaker than the glyph cache.
⚠ Non-zero winding only. GlyphRasterizer fills by non-zero — a counter in an o is a contour wound the other way and every font relies on it — so an even-odd path would be encoded as the shape it is not. Refused here rather than approximated, and the caller tessellates it instead.
Fields and properties (8)
public GlyphAtlas AtlasThe atlas the fields live in.
public int ResolutionThe most texels a path's longer side may be encoded at.
public float RangeHow many pixels either side of the edge the field spans.
public float MaxSizeThe largest a path may be, in document pixels, and still be worth a field.
public float FeatherHow wide the coverage ramp along an edge is, in document pixels.
public long GeneratedHow many paths have had a field generated for them.
public int CountHow many distinct paths have an entry, whether or not the atlas still holds one.
public long RefusedHow many paths were refused — too large, the wrong rule, or bigger than the atlas.
Methods (2)
public IconAtlas(GlyphAtlas atlas, int resolution = 48, float range = 4)Creates a cache over an atlas.
public bool TryGet(IReadOnlyList<PathSegment> segments, int offset, int length, PathFillRule rule, out IconField field)Finds a path's field, encoding it first if it is not there.
Used by (2)
- IconAtlasTestsVixen.Ui.Tests
- UiGeometryBuilderVixen.Ui