diff --git a/crates/horizon-client/src/font.rs b/crates/horizon-client/src/font.rs index 1903cab7e..d0e8c8499 100644 --- a/crates/horizon-client/src/font.rs +++ b/crates/horizon-client/src/font.rs @@ -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); diff --git a/crates/horizon-client/src/game.rs b/crates/horizon-client/src/game.rs index cdbd72d7b..1bd288bb7 100644 --- a/crates/horizon-client/src/game.rs +++ b/crates/horizon-client/src/game.rs @@ -12995,6 +12995,14 @@ fn build_renderer( ) -> Result { 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,