diff --git a/crates/bevy_text/src/font_atlas.rs b/crates/bevy_text/src/font_atlas.rs index 24c67d53cbdca..9c39fcf89eede 100644 --- a/crates/bevy_text/src/font_atlas.rs +++ b/crates/bevy_text/src/font_atlas.rs @@ -39,15 +39,16 @@ impl FontAtlas { texture_atlases: &mut Assets, character: char, texture: &Texture, - ) { + ) -> bool { let texture_atlas = texture_atlases.get_mut(&self.texture_atlas).unwrap(); if let Some(index) = self.dynamic_texture_atlas_builder .add_texture(texture_atlas, textures, texture) { self.glyph_to_index.insert(character, index); + true } else { - panic!("ran out of space in font atlas"); + false } } } diff --git a/crates/bevy_text/src/font_atlas_set.rs b/crates/bevy_text/src/font_atlas_set.rs index 581877d110774..a38e3aaacf58f 100644 --- a/crates/bevy_text/src/font_atlas_set.rs +++ b/crates/bevy_text/src/font_atlas_set.rs @@ -13,7 +13,7 @@ type FontSizeKey = FloatOrd; #[derive(Default)] pub struct FontAtlasSet { font: Handle, - font_atlases: HashMap, + font_atlases: HashMap>, } #[derive(Debug)] @@ -30,7 +30,7 @@ impl FontAtlasSet { } } - pub fn iter(&self) -> impl Iterator { + pub fn iter(&self) -> impl Iterator)> { self.font_atlases.iter() } @@ -38,7 +38,9 @@ impl FontAtlasSet { self.font_atlases .get(&FloatOrd(font_size)) .map_or(false, |font_atlas| { - font_atlas.get_char_index(character).is_some() + font_atlas + .iter() + .any(|atlas| atlas.get_char_index(character).is_some()) }) } @@ -52,10 +54,16 @@ impl FontAtlasSet { ) -> f32 { let font = fonts.get(&self.font).unwrap(); let scaled_font = ab_glyph::Font::as_scaled(&font.font, font_size); - let font_atlas = self + let font_atlases = self .font_atlases .entry(FloatOrd(font_size)) - .or_insert_with(|| FontAtlas::new(textures, texture_atlases, Vec2::new(512.0, 512.0))); + .or_insert_with(|| { + vec![FontAtlas::new( + textures, + texture_atlases, + Vec2::new(512.0, 512.0), + )] + }); let mut last_glyph: Option = None; let mut width = 0.0; @@ -67,10 +75,30 @@ impl FontAtlasSet { if let Some(last_glyph) = last_glyph.take() { width += scaled_font.kern(last_glyph.id, glyph.id); } - if font_atlas.get_char_index(character).is_none() { + if !font_atlases + .iter() + .any(|atlas| atlas.get_char_index(character).is_some()) + { if let Some(outlined_glyph) = scaled_font.outline_glyph(glyph.clone()) { let glyph_texture = Font::get_outlined_glyph_texture(outlined_glyph); - font_atlas.add_char(textures, texture_atlases, character, &glyph_texture); + let add_char_to_font_atlas = |atlas: &mut FontAtlas| -> bool { + atlas.add_char(textures, texture_atlases, character, &glyph_texture) + }; + if !font_atlases.iter_mut().any(add_char_to_font_atlas) { + font_atlases.push(FontAtlas::new( + textures, + texture_atlases, + Vec2::new(512.0, 512.0), + )); + if !font_atlases.last_mut().unwrap().add_char( + textures, + texture_atlases, + character, + &glyph_texture, + ) { + panic!("could not add character to newly created FontAtlas"); + } + } } } width += scaled_font.h_advance(glyph.id); @@ -85,9 +113,14 @@ impl FontAtlasSet { .get(&FloatOrd(font_size)) .and_then(|font_atlas| { font_atlas - .get_char_index(character) - .map(|char_index| GlyphAtlasInfo { - texture_atlas: font_atlas.texture_atlas, + .iter() + .find_map(|atlas| { + atlas + .get_char_index(character) + .map(|char_index| (char_index, atlas.texture_atlas)) + }) + .map(|(char_index, texture_atlas)| GlyphAtlasInfo { + texture_atlas, char_index, }) }) diff --git a/examples/ui/font_atlas_debug.rs b/examples/ui/font_atlas_debug.rs index cb30d82e3a2ab..d1d8022203229 100644 --- a/examples/ui/font_atlas_debug.rs +++ b/examples/ui/font_atlas_debug.rs @@ -12,7 +12,7 @@ fn main() { } struct State { - added: bool, + atlas_count: u32, handle: Handle, timer: Timer, } @@ -20,7 +20,7 @@ struct State { impl Default for State { fn default() -> Self { Self { - added: false, + atlas_count: 0, handle: Handle::default(), timer: Timer::from_seconds(0.05, true), } @@ -34,20 +34,23 @@ fn atlas_render_system( font_atlas_sets: Res>, texture_atlases: Res>, ) { - if state.added { - return; - } if let Some(set) = font_atlas_sets.get(&state.handle.as_handle::()) { if let Some((_size, font_atlas)) = set.iter().next() { - state.added = true; - let texture_atlas = texture_atlases.get(&font_atlas.texture_atlas).unwrap(); + let x_offset = state.atlas_count as f32; + if state.atlas_count == font_atlas.len() as u32 { + return; + } + let texture_atlas = texture_atlases + .get(&font_atlas[state.atlas_count as usize].texture_atlas) + .unwrap(); + state.atlas_count += 1; commands.spawn(ImageComponents { material: materials.add(texture_atlas.texture.into()), style: Style { position_type: PositionType::Absolute, position: Rect { top: Val::Px(0.0), - left: Val::Px(0.0), + left: Val::Px(512.0 * x_offset), ..Default::default() }, ..Default::default() @@ -61,8 +64,9 @@ fn atlas_render_system( fn text_update_system(mut state: ResMut, time: Res