Vixen
02b45cc4
csharp
public sealed class IconAtlas

Turns 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 Atlas

    The atlas the fields live in.

  • public int Resolution

    The most texels a path's longer side may be encoded at.

  • public float Range

    How many pixels either side of the edge the field spans.

  • public float MaxSize

    The largest a path may be, in document pixels, and still be worth a field.

  • public float Feather

    How wide the coverage ramp along an edge is, in document pixels.

  • public long Generated

    How many paths have had a field generated for them.

  • public int Count

    How many distinct paths have an entry, whether or not the atlas still holds one.

  • public long Refused

    How 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