diff --git a/hui/src/draw.rs b/hui/src/draw.rs index afc411b..6acd061 100644 --- a/hui/src/draw.rs +++ b/hui/src/draw.rs @@ -97,6 +97,32 @@ impl UiDrawCall { pub(crate) fn build(draw_commands: &UiDrawCommandList, atlas: &mut TextureAtlasManager, text_renderer: &mut TextRenderer) -> Self { let mut trans_stack = Vec::new(); let mut draw_call = UiDrawCall::default(); + + //HACK: atlas may get resized while creating new glyphs, + //which invalidates all uvs, causing corrupted-looking texture + //so we need to pregenerate font textures before generating any vertices + //we are doing *a lot* of double work here, but it's the easiest way to avoid the issue + for comamnd in &draw_commands.commands { + if let UiDrawCommand::Text { text, font: font_handle, size, .. } = comamnd { + let mut layout = Layout::new(CoordinateSystem::PositiveYDown); + layout.append( + &[text_renderer.internal_font(*font_handle)], + &TextStyle::new(text, *size as f32, 0) + ); + let glyphs = layout.glyphs(); + for layout_glyph in glyphs { + if !layout_glyph.char_data.rasterize() { continue } + text_renderer.glyph(atlas, *font_handle, layout_glyph.parent, layout_glyph.key.px as u8); + } + } + } + + //note to future self: + //RESIZING OR ADDING STUFF TO ATLAS AFTER THIS POINT IS A BIG NO-NO, + //DON'T DO IT EVER AGAIN UNLESS YOU WANT TO SPEND HOURS DEBUGGING + + atlas.lock_atlas = true; + for command in &draw_commands.commands { match command { UiDrawCommand::PushTransform(trans) => { @@ -328,10 +354,14 @@ impl UiDrawCall { } } } + + atlas.lock_atlas = false; + #[cfg(feature = "pixel_perfect")] draw_call.vertices.iter_mut().for_each(|v| { v.position = v.position.round() }); + draw_call } } diff --git a/hui/src/draw/atlas.rs b/hui/src/draw/atlas.rs index 15aa428..812ebe4 100644 --- a/hui/src/draw/atlas.rs +++ b/hui/src/draw/atlas.rs @@ -59,6 +59,10 @@ pub(crate) struct TextureAtlasManager { /// True if the atlas has been modified in a way which requires a texture reupload /// since the beginning of the current frame modified: bool, + + /// If true, attempting to modify the atlas in a way which invalidates UVs will cause a panic\ + /// Used internally to ensure that the UVs do not become invalidated mid-render + pub(crate) lock_atlas: bool, } impl TextureAtlasManager { @@ -73,11 +77,15 @@ impl TextureAtlasManager { allocations: HashMap::default(), remove_queue: Vec::new(), modified: true, + lock_atlas: false, } } /// Resize the texture atlas to the new size in-place, preserving the existing data pub fn resize(&mut self, new_size: UVec2) { + if self.lock_atlas { + panic!("Attempted to resize the texture atlas while the atlas is locked"); + } log::trace!("resizing texture atlas to {:?}", new_size); if self.size == new_size { log::warn!("Texture atlas is already the requested size");