Font: menus keep their run-time glyphs when the renderer rebuilds its atlas

Menu text drawn with characters the bitmap sheets lack (Chinese, Japanese,
Korean) is rasterized into a reserve of the shared atlas at run time, and the
font caches the atlas rect it got. The loading screen hands over to the game
about two seconds after the title shows by building a new renderer, whose
atlas texture is made from HudAtlas.pixels alone: those never hold a
run-time glyph, while the cache still answers with the old rects, so every
such character already drawn went blank. Latin text, straight from the
sheets, stayed. build_renderer and loading_renderer now forget the cache
before the new texture exists, so the characters that are drawn again are
placed into it, as ui_theme clears its own cache when the atlas changes.

Fixes #1824, fixes #2040.
This commit is contained in:
kohad1ck
2026-10-26 16:47:07 +08:00
committed by Ludovic Marie
parent 6ff335eacf
commit 5ec21ff5f1
2 changed files with 39 additions and 0 deletions
+25
View File
@@ -1201,6 +1201,31 @@ mod tests {
assert!(!font.take_patches().is_empty());
}
/// A renderer rebuilt over the same font (the loading screen's handoff)
/// makes its atlas texture from the textures alone, so the glyphs it had
/// rasterized into the previous texture must be placed into the new one.
#[test]
fn a_rebuilt_atlas_gets_its_glyphs_again() {
let sheet = png(16, 8, |x, _| x < 2 || (8..14).contains(&x));
let default = br#"{"providers":[{"type":"bitmap","file":"minecraft:font/a.png","ascent":7,"chars":["ab"]}]}"#;
let root = root(
"rebuild",
&[
("assets/minecraft/font/default.json", default),
("assets/minecraft/textures/font/a.png", &sheet),
],
);
let font = load(&root);
let _ = std::fs::remove_dir_all(&root);
let first = font.glyph('a');
assert_eq!(font.take_patches().len(), 1);
font.reset_cache();
// Nothing is left over: drawing the character again places its pixels.
assert!(font.take_patches().is_empty());
assert_eq!(font.glyph('a').advance, first.advance);
assert_eq!(font.take_patches().len(), 1);
}
#[test]
fn provider_filters_follow_the_font_options() {
let sheet = png(8, 8, |x, _| x < 4);
+14
View File
@@ -12995,6 +12995,14 @@ fn build_renderer(
) -> Result<Renderer> {
let assets = &pack.render;
let atlas = &gui.atlas;
// The new renderer's atlas texture starts from `HudAtlas.pixels`, which
// holds the textures but never a glyph rasterized at run time. The font's
// cache still answers with the rects it drew into the previous renderer's
// texture, so forget them: the glyphs that are drawn again are placed into
// this texture (as `ui_theme` does when its atlas changes). Without this,
// Chinese and Japanese menu labels go blank when the loading screen hands
// over to the game.
atlas.font.reset_cache();
let mut renderer = pollster::block_on(Renderer::new(
window,
offscreen,
@@ -13041,6 +13049,12 @@ fn loading_renderer(
Some(atlas) => (atlas.pixels.as_slice(), atlas.width, atlas.height),
None => (EMPTY_HUD.as_slice(), 1, 1),
};
// A glyph rasterized into an earlier texture is not in these pixels; the
// new texture gets it again when the character is drawn (see
// `build_renderer`).
if let Some(atlas) = atlas {
atlas.font.reset_cache();
}
let mut renderer = pollster::block_on(Renderer::new(
window,
offscreen,