feat(render): anti-aliased embedded Adwaita Mono atlas, generated and committed
This commit is contained in:
1 parent
3ff7b9c978
commit
5ca3587325
17 files changed
+3422
-627
No files matched your search
+24
-16
@@ -88,23 +88,25 @@ f32 walk_text_clipped(Vec2 pen, const char* utf8, f32 budget_px, const render::T
|
||||
void warn_replaced_text_backend(const render::TextBackend* previous) noexcept {
|
||||
std::fprintf(stderr,
|
||||
"plot::Renderer::draw: replacing the Plot's TextBackend (%p) with the renderer's "
|
||||
"own bitmap font; a plot drawn by a Renderer measures the labels it draws.\n",
|
||||
"own embedded font; a plot drawn by a Renderer measures the labels it draws.\n",
|
||||
static_cast<const void*>(previous));
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
void Renderer::AxisFont::reset(const render::BitmapFont& font, f32 requested_px) noexcept {
|
||||
void Renderer::AxisFont::reset(const render::TextBackend& font, f32 requested_px) noexcept {
|
||||
font_ = &font;
|
||||
const f32 native = static_cast<f32>(render::BitmapFont::kGlyphPx);
|
||||
// Whole multiples of the native cell only: a 1-bit glyph drawn at 1.5x lands
|
||||
// its strokes on uneven pixel counts, and the layout has to agree with what the
|
||||
// pipeline draws, so the requested size picks the nearest multiple.
|
||||
f32 steps = std::round(requested_px / native);
|
||||
if (!(steps >= 1.0f)) steps = 1.0f; // also catches NaN
|
||||
cell_px_ = steps * native;
|
||||
scale_ = cell_px_ / native;
|
||||
// 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;
|
||||
cell_px_ = font.height() * scale_;
|
||||
}
|
||||
|
||||
f32 Renderer::AxisFont::measure(const char* utf8) const {
|
||||
@@ -119,6 +121,12 @@ f32 Renderer::AxisFont::ascent() const {
|
||||
return font_ != nullptr ? font_->ascent() * scale_ : 0.0f;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
const render::Glyph* Renderer::AxisFont::glyph(u32 codepoint) const {
|
||||
if (font_ == nullptr) {
|
||||
return nullptr; // nothing to draw with, so nothing to describe
|
||||
@@ -169,7 +177,7 @@ bool Renderer::init(Status* st) noexcept {
|
||||
const render::UploadMode mode =
|
||||
persistent ? render::UploadMode::PersistentMapped : render::UploadMode::Orphan;
|
||||
|
||||
font_backend_.reset(font_, style_.axis_font_px);
|
||||
font_backend_.reset(default_font_, style_.axis_font_px);
|
||||
|
||||
// The atlas is the backend's: `sync()` uploads whatever it exposes, at whatever
|
||||
// size it says, and restores the host's unpack alignment around the upload
|
||||
@@ -263,7 +271,7 @@ void Renderer::draw(Plot& plot) {
|
||||
// The plot reserves its label strips from TextBackend metrics, so it must
|
||||
// measure with the size the text pipeline draws with, and re-read the style
|
||||
// each frame so a changed axis_font_px takes effect on the next one.
|
||||
font_backend_.reset(font_, style_.axis_font_px);
|
||||
font_backend_.reset(default_font_, style_.axis_font_px);
|
||||
// The cell every glyph staged this frame is drawn in, declared from the backend
|
||||
// rather than left to whichever glyph is staged first: the instances carry rect
|
||||
// origins, and the draw carries this size (see TextBackend::cell_uv).
|
||||
@@ -280,7 +288,7 @@ void Renderer::draw(Plot& plot) {
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
// The renderer owns the text of the frames it draws: every label goes through
|
||||
// the text pipeline in `font_`, so the plot is handed this font's metrics
|
||||
// the text pipeline in `default_font_`, so the plot is handed this backend's metrics
|
||||
// whatever a host installed. A host backend is therefore replaced on the first
|
||||
// draw -- said out loud in a debug build, since its disappearance is otherwise
|
||||
// silent -- and a Plot nobody draws keeps it (see Plot::set_text_backend()).
|
||||
@@ -456,17 +464,17 @@ void Renderer::stage_xy(const f32* xy, u32 n, bool log_x, bool log_y) {
|
||||
|
||||
Vec2 Renderer::stage_text(Vec2 pos_px, const char* utf8) {
|
||||
// Text is staged in viewport pixels: the text program has no offset uniform.
|
||||
return glyphs_.add_text(utf8, to_viewport(pos_px), font_backend_.scale(), font_);
|
||||
return glyphs_.add_text(utf8, to_viewport(pos_px), font_backend_.scale(), default_font_);
|
||||
}
|
||||
|
||||
f32 Renderer::clipped_text_width(const char* utf8, f32 budget_px) const {
|
||||
return walk_text_clipped(Vec2{}, utf8, budget_px, font_, font_backend_.scale(),
|
||||
return walk_text_clipped(Vec2{}, utf8, budget_px, default_font_, font_backend_.scale(),
|
||||
[](Vec2, const render::Glyph&) {});
|
||||
}
|
||||
|
||||
f32 Renderer::stage_text_clipped(Vec2 pos_px, const char* utf8, f32 budget_px) {
|
||||
const f32 scale = font_backend_.scale();
|
||||
return walk_text_clipped(to_viewport(pos_px), utf8, budget_px, font_, scale,
|
||||
return walk_text_clipped(to_viewport(pos_px), utf8, budget_px, default_font_, scale,
|
||||
[this, scale](Vec2 pen, const render::Glyph& glyph) {
|
||||
glyphs_.add_glyph(pen, glyph, scale);
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user