replace pre-baked bitmap fonts with a runtime glyph atlas - #559
Conversation
Reviewer's GuideReplaces fixed Latin-1 Cantarell BMFont atlases with a runtime, UTF-8-aware glyph pipeline: QTextLayout shapes text, worker threads populate a synchronized shelf-packed glyph atlas, and the GL thread uploads incremental changes while shaders support both tinted monochrome and color glyphs. Font family, point size, DPI, and device pixel ratio are configurable inputs that trigger font and mesh rebuilding. Sequence diagram for streaming glyph rasterization and uploadsequenceDiagram
participant Worker as Worker thread
participant Atlas as GlyphAtlas
participant GL as GL thread
participant Texture as Font texture
participant Shader as Font shader
Worker->>Atlas: shape(utf8)
Atlas->>Atlas: QTextLayout shaping
Atlas->>Atlas: rasterizeLocked(rawFont, glyphIndex)
Atlas-->>Worker: ShapedText
GL->>Atlas: takePendingUpload()
Atlas-->>GL: AtlasUpload dirty region
GL->>Texture: setData(region)
GL->>Shader: createFontMesh(vertices)
Shader->>Texture: sample normalized atlas texels
Shader-->>GL: Render tinted or color glyphs
State diagram for font and glyph atlas lifecyclestateDiagram-v2
[*] --> Uninitialized
Uninitialized --> Initialized: init()
Initialized --> Streaming: shape(utf8)
Streaming --> Streaming: new glyph rasterized
Streaming --> TextureSynced: takePendingUpload()
TextureSynced --> Streaming: shape(utf8)
Initialized --> Stale: isStale()
TextureSynced --> Stale: font spec or DPI changed
Stale --> Uninitialized: cleanup()
Stale --> Initialized: init() and rebuild meshes
Streaming --> Full: atlas reaches max size
Full --> Full: further glyphs omitted
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="src/opengl/Font.cpp" line_range="335-339" />
<code_context>
+ return family.isEmpty() ? QStringLiteral("Cantarell") : family;
+}
+
+NODISCARD static float getLogicalDpi()
+{
+ if (const QScreen *const screen = QGuiApplication::primaryScreen()) {
+ return static_cast<float>(screen->logicalDotsPerInchY());
}
+ return 96.f;
+}
</code_context>
<issue_to_address>
**issue (bug_risk):** `getLogicalDpi()` always reads the primary screen's DPI rather than the screen displaying the map window, so moving the application to a monitor with a different logical DPI leaves glyphs rasterized at the wrong physical size.
**Triggers:** When the application window is moved to a secondary monitor with different logical DPI.
**Suggested fix:** Read the DPI from the map window or OpenGL surface's current screen and update the font when that screen changes.
</issue_to_address>Sourcery assessment
Approval pending. 1 finding to address first.
Blocking findings: src/opengl/Font.cpp:339
c33e3bc to
5fb7dad
Compare
4990ba0 to
2232c78
Compare
b9ac49b to
c1edc02
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #559 +/- ##
==========================================
+ Coverage 27.24% 27.91% +0.66%
==========================================
Files 559 563 +4
Lines 45893 46169 +276
Branches 4879 4884 +5
==========================================
+ Hits 12505 12889 +384
+ Misses 33388 33280 -108 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
The map font was three pre-baked Cantarell BMFont atlases (18/27/36px), picked by device pixel ratio, limited to Latin-1. Replace them with a streaming glyph cache (src/font/GlyphAtlas) that rasterizes glyphs on demand from any installed QFont at the exact physical pixel size they are drawn at. - Text is shaped with QTextLayout, so kerning, ligatures and font fallback (color emoji, non-Latin scripts) come for free; callers now pass UTF-8. - Glyphs are rasterized with full hinting via QPainter::drawGlyphRun into a shelf-packed RGBA8 atlas; monochrome glyphs store coverage in alpha and color glyphs (detected per glyph) store straight RGBA in the same texture, discriminated by a per-vertex flag. - The atlas starts at 256^2 and doubles on demand up to min(2048, GL_MAX_TEXTURE_SIZE). Texture coordinates are atlas texels normalized in the vertex shader, so growing the texture in place never invalidates cached text meshes. Dirty regions are uploaded with glTexSubImage2D before a mesh is created or drawn; worker threads only touch the CPU-side image under a mutex. - The font is re-initialized (and text meshes rebuilt) whenever its spec goes stale: family/point size from the preferences, logical DPI, or device pixel ratio. - "Map font point size" is a real point size (default 11pt, matching the old Cantarell18 look); the embedded Cantarell-Regular.ttf remains the default family. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The map font was three pre-baked Cantarell BMFont atlases (18/27/36px), picked by device pixel ratio, limited to Latin-1. Replace them with a streaming glyph cache (src/font/GlyphAtlas) that rasterizes glyphs on demand from any installed QFont at the exact physical pixel size they are drawn at.
Summary by Sourcery
Replace pre-baked map font atlases with a configurable, DPI-aware runtime glyph atlas that supports modern Unicode text rendering.
New Features:
Bug Fixes:
Enhancements:
Build:
Tests:
Chores: