Expand description
Grid-packed glyph atlas layout shared by the GPU backends.
A GPU backend uploads every glyph of a FontChain once and then addresses one by a flat
slot index that goes straight into an instance buffer. This module owns both halves of that:
AtlasData is the CPU-side coverage buffer to upload, and GlyphAtlas is the
char -> slot map to look up.
§Why a grid, not one glyph per layer
The obvious packing (one glyph per array-texture layer) caps a chain at the array-layer limit,
which is 256 on the OpenGL 3.3 / GL ES 3.0 floor and on wgpu’s downlevel defaults. Packing a
fixed ATLAS_COLSxATLAS_ROWS grid of glyphs into each layer instead means N glyphs need
only ceil(N / 256) layers, which lifts the cap to MAX_SLOTS glyphs while still fitting
inside that 256-layer minimum. A shader turns a slot back into its (layer, column, row)
sub-rect.
§Coverage, not colour
AtlasData::coverage is one byte per texel: 0xFF where the glyph’s bit is set and 0 where
it isn’t, meant for a single-channel (R8) texture. A backend samples it with nearest filtering
and blends the cell’s foreground over its background by that coverage, so glyphs stay crisp at
any integer scale and take the cell’s colours like any other glyph.
Those two values are the only ones that ever appear, and that is load-bearing rather than incidental. Coverage used as an alpha is the usual place text rendering goes wrong on colour space: a rasterizer’s partial coverage is a linear quantity, so interpolating between an sRGB-encoded foreground and background by it produces text that is too thin or too fat, and correcting for that is fiddly. The question does not arise for a bitmap font, because a blend factor of exactly 0 or exactly 1 selects one endpoint outright and every colour space agrees on the result.
Those two values being the only ones is an invariant of this module, not an accident of the
current font sources, and every backend is entitled to rely on it. coverage_is_strictly_binary
enforces it.
Anything that introduces partial coverage (an antialiased or grayscale-AA font source,
multisampling, a non-integer render scale) reopens the colour-space question for all three
backends simultaneously, and has to be a deliberate decision rather than a side effect. See
docs/references/core/color-space.md.
§Examples
use retroglyph_window::atlas::GlyphAtlas;
use retroglyph_window::font::{FontChain, unscii16};
let atlas = GlyphAtlas::new(FontChain::from(unscii16::FONT), (8, 16));
// Unscii 16 is 256 CP437 glyphs, so it occupies exactly one 16x16 layer.
assert_eq!(atlas.slot_count(), 256);
assert_eq!(atlas.data().geometry.layers, 1);
// A character resolves to the slot its coverage was written to.
assert_eq!(atlas.resolve('A'), Some(u16::from(b'A')));Structs§
- Atlas
Data - The CPU-side coverage buffer for a whole atlas, grid-packed per
AtlasGeometry. - Atlas
Geometry - The packing of glyph cells into an array texture: a fixed
ATLAS_COLSxATLAS_ROWSgrid ofcell_wxcell_hglyph cells per layer, acrosslayerslayers. - Glyph
Atlas - A static
FontChainplus thechar-> slot map for its grid-packed atlas.
Constants§
- ATLAS_
COLS - Glyph columns packed into one array layer.
- ATLAS_
ROWS - Glyph rows packed into one array layer.
- MAX_
SLOTS - The number of slots the atlas can address, set by the
u16slot id an instance buffer carries. - SLOTS_
PER_ LAYER - Glyph slots per array layer (
ATLAS_COLS * ATLAS_ROWS).
Functions§
- addressable_
glyphs - The number of atlas slots
fontoccupies: its glyph count, capped at the 256 au8glyph index can address (seeBitmapFont::rows).