Commit Graph
8 Commits
Author SHA1 Message Date
Martino Ferrari 1cb5970757 fix(render): environment-aware atlas drift guard, pinned text scale, shipped-atlas coverage 2026-09-28 10:54:00 +02:00
Martino Ferrari 5ca3587325 feat(render): anti-aliased embedded Adwaita Mono atlas, generated and committed 2026-09-28 10:40:23 +02:00
Martino Ferrari 3ff7b9c978 fix(render): gate TextAtlas::sync on the loader, and cover three review findings
Review of the atlas refactor found one Important and three Minor issues:

- Important: TextAtlas::sync called glGetIntegerv before any available() check,
  so a host that synced before plot::gl::load() -- which is legal for a public
  class Tasks 2 and 8 build backends on -- segfaulted on a null entry point
  instead of receiving the Status the interface promises. It now follows the
  handle-constructor convention (available(), then the entry point itself) and
  reports Unsupported.
- empty() no longer means "a GL name exists": releasing one is a
  glDeleteTextures call, so the no-atlas path forgets the atlas and only resets
  the texture when there is a table to release it with.
- end_frame's comment still claimed the frame hands back the unpack alignment
  init() set, contradicting the code below it and renderer.hpp.
- The orientation case's texel probe mapped the atlas' u along the cell's +v
  axis and vice versa, which is a no-op for its two diagonal probes -- so it
  could not fail on a transposed UV mapping, and its own comment misstated the
  rule. Probes now follow the shader's rule and include an off-diagonal pair.
- The null-glyph path of add_text (and its twin in walk_text_clipped) was
  unreached by any case.

Cases: text_atlas_reports_a_status_when_the_entry_points_are_missing,
add_text_skips_a_codepoint_the_backend_cannot_draw.
2026-09-28 10:22:38 +02:00
Martino Ferrari ffc060d6ca refactor(render): the atlas is a declared fixed-cell grid, and staging checks it
The text pipeline stages a glyph's rect *origin* per instance and carries the
rect's *size* once per draw, so a backend whose glyphs have differing rect sizes
-- a TrueType packing trimmed to ink, which is Task 8's shape -- would have drawn
every glyph at whichever size it happened to be told, with nothing downstream
able to tell. Make that constraint structural rather than documented:

- TextBackend::cell_uv() declares the one cell size, and the contract (an atlas
  is a fixed-cell grid; a proportional face draws its glyphs *into* a uniform
  cell instead of trimming each rect to its ink, and why the pipeline needs it)
  is stated on the atlas accessors.
- glyph_is_cell() is the check; add_text()/set_cell() declare the cell from the
  backend, and the staging path asserts it for every glyph in a debug build.
  A release build draws on with the cell it was told, as before.
- Renderer::flush_text() takes u_glyph_uv from the backend, not from the batch,
  so the draw's one rect size can never come from whichever glyph was staged
  first.
2026-09-28 10:09:50 +02:00
Martino Ferrari e074f57ddf refactor(render): TextBackend owns its atlas, and staged glyphs carry a rotation basis 2026-09-28 09:57:28 +02:00
Martino Ferrari 3555ab63d7 feat(render): Renderer with LOD selection, 3.3 and 4.3+ upload paths, headless smoke test 2026-09-27 23:03:08 +02:00
Martino Ferrari b4e88fe0c1 fix(render): give degenerate segments area, pin font bit order, clarify vertex_count 2026-09-27 22:10:53 +02:00
Martino Ferrari 7cbc1c9955 feat(render): style, GLSL line/text pipelines, staging batches, bitmap font 2026-09-27 22:03:56 +02:00