fix(render): environment-aware atlas drift guard, pinned text scale, shipped-atlas coverage

This commit is contained in:
Martino Ferrari committed 2026-09-28 10:54:00 +02:00
1 parent 5ca3587325
commit 1cb5970757
6 files changed
+257 -31

No files matched your search

+13 -12
View File
@@ -3,6 +3,7 @@
#include <plot/gl/api.hpp>
#include <plot/gl/caps.hpp>
#include <plot/gl/loader.hpp>
#include <plot/render/detail/text_scale.hpp>
#include <algorithm>
#include <cmath>
@@ -97,15 +98,12 @@ void warn_replaced_text_backend(const render::TextBackend* previous) noexcept {
void Renderer::AxisFont::reset(const render::TextBackend& font, f32 requested_px) noexcept {
font_ = &font;
// The requested size is an em size, exactly as `em_px()` reports the size the
// atlas was baked at, so the ratio between them is all the scaling there is:
// an anti-aliased face is legible at any ratio, and a style asking for 12 px
// from a 13 px bake gets 12/13 rather than a snapped whole multiple. A backend
// that cannot say (`em_px()` at or below zero, or NaN) keeps a 1:1 scale rather
// than dividing by it.
const f32 baked = font.em_px();
const f32 ratio = requested_px / baked;
scale_ = (baked > 0.0f && ratio > 0.0f) ? ratio : 1.0f;
// An anti-aliased face is legible at any ratio, so a style asking for 12 px
// from a 13 px bake is drawn at 12/13 rather than snapped to a whole multiple
// of the cell. `detail::text_scale` owns that rule, including the 1:1 fallback
// for a backend that cannot state an em -- it is one function, and the test
// suite asserts it without a GL context.
scale_ = render::detail::text_scale(requested_px, font.em_px());
cell_px_ = font.height() * scale_;
}
@@ -122,9 +120,12 @@ f32 Renderer::AxisFont::ascent() const {
}
f32 Renderer::AxisFont::em_px() const {
// The em is the one metric that does not scale: it is the face's own unit, and
// it is what the scale above was computed from.
return font_ != nullptr ? font_->em_px() : 0.0f;
// Scaled with the rest of the metrics, not forwarded raw: `TextBackend::em_px()`
// is documented to be in the same units as `height()` and `ascent()`, and this
// wrapper's are all screen pixels. A caller that reads the backend back off the
// plot and draws at `requested_px / em_px()` therefore gets 1:1 rather than
// scaling a second time (see the base-class contract).
return font_ != nullptr ? font_->em_px() * scale_ : 0.0f;
}
const render::Glyph* Renderer::AxisFont::glyph(u32 codepoint) const {