use glyph_brush::{BrushAction, BrushError, GlyphBrush, GlyphBrushBuilder, GlyphVertex, Rectangle, Section, Text, ab_glyph::FontArc}; use vulkano::{format::Format, image::ImageDimensions, sampler::{Filter, SamplerAddressMode}}; use crate::vulkan::{MeshHandle, TextVertex, TextureHandle, VulkanRenderer, gameobject::{GameObject, GameObjectHandle}, mesh::{CPUMesh, CPUVertexList}}; pub fn update_text(game_object_handle: GameObjectHandle, new_text: &str, new_size: f32, renderer: &mut VulkanRenderer, brush: &mut GlyphBrush>, game_objects: &mut Vec) { brush.queue(Section::default() .add_text(Text::new(new_text).with_scale(new_size)) .with_bounds((renderer.game_data.dimensions[0] as f32, renderer.game_data.dimensions[1] as f32))); let go = &mut game_objects[game_object_handle]; let mesh_index = go.mesh_index; match brush.process_queued(|rect, text_data| { debug_assert!(go.textures.len() == 1); update_text_texture(Some(go.textures[0]), renderer, rect, text_data); }, convert_vertices) { Ok(BrushAction::Draw(quads)) => { update_text_quads(quads, 420, Some(mesh_index), renderer); }, Ok(BrushAction::ReDraw) => {}, Err(BrushError::TextureTooSmall { suggested }) => { let size = ImageDimensions::Dim2d { width: suggested.0, height: suggested.1, array_layers: 1 }; debug_assert!(go.textures.len() == 1); renderer.resize_texture(go, go.textures[0], size); brush.resize_texture(suggested.0, suggested.1); update_text(game_object_handle, new_text, new_size, renderer, brush, game_objects); }, } } pub fn create_brush() -> GlyphBrush { let font = FontArc::try_from_slice(include_bytes!("../models/FiraCode-Regular.ttf")).unwrap(); GlyphBrushBuilder::using_font(font).build() } pub fn create_text_object(brush: &mut GlyphBrush>, renderer: &mut VulkanRenderer, text: &str, size: f32) -> MeshHandle { let mut uploaded_texture = None; let mut uploaded_mesh = None; brush.queue(Section::default() .add_text(Text::new(text).with_scale(size)) .with_bounds((renderer.game_data.dimensions[0] as f32, renderer.game_data.dimensions[1] as f32)) ); match brush.process_queued(|rect, text_data| { uploaded_texture = update_text_texture(None, renderer, rect, text_data); }, convert_vertices) { Ok(BrushAction::Draw(quads)) => { let t = if let Some(tex) = uploaded_texture { tex } else { let brush_size = brush.texture_dimensions(); update_text_texture(None, renderer, Rectangle { min: [0, 0], max: [brush_size.0, brush_size.1] }, &[]).unwrap() }; uploaded_mesh = update_text_quads(quads, t, None, renderer); }, Ok(BrushAction::ReDraw) => {}, Err(BrushError::TextureTooSmall { suggested }) => { brush.resize_texture(suggested.0, suggested.1); }, }; uploaded_mesh.unwrap() } pub fn update_text_texture(old_texture: Option, renderer: &mut VulkanRenderer, rect: Rectangle, text_data: &[u8]) -> Option { let size = u32::max(rect.width(), rect.height()); if let Some(tex_handle) = old_texture { renderer.update_texture(tex_handle, text_data, [rect.width(), rect.height(), 1], [rect.min[0], rect.min[1], 0], renderer.device.clone()); None } else { let tex = renderer.upload_texture(text_data, size, size, Format::R8_UNORM, Filter::Nearest, SamplerAddressMode::ClampToEdge, renderer.device.clone()); renderer.game_data.textures.push(tex.clone()); Some(renderer.game_data.textures.len() - 1) } } pub fn update_text_quads(quads: Vec>, texture_index: usize, mesh_index: Option, renderer: &mut VulkanRenderer) -> Option { let mut final_vertices = vec![]; let mut final_indices: Vec = vec![]; let mut index_offset = 0; for mut quad in quads { let len = quad.len(); final_vertices.append(&mut quad); final_indices.append(&mut [0, 2, 3, 0, 3, 1].iter().map(|x| *x + index_offset).collect()); index_offset += len as u32; } if let Some(idx) = mesh_index { renderer.update_mesh(idx, CPUVertexList::VertexText(final_vertices), final_indices); None } else { let mesh = CPUMesh { vertices: CPUVertexList::VertexText(final_vertices), indices: final_indices, local_texture_index: Some(texture_index), local_normal_map_index: None, name: Some("font_texture".to_string()), }; let mesh_index = renderer.upload_mesh(mesh, None); Some(MeshHandle { index: mesh_index, textures: vec![texture_index], original_path: None, pipeline_index: 1 }) } } fn convert_vertices(vertex_data: GlyphVertex) -> Vec { let result = vec![ TextVertex { position: [vertex_data.pixel_coords.min.x, vertex_data.pixel_coords.min.y, 0.], uv: [vertex_data.tex_coords.min.x, vertex_data.tex_coords.min.y] }, TextVertex { position: [vertex_data.pixel_coords.min.x, vertex_data.pixel_coords.max.y, 0.], uv: [vertex_data.tex_coords.min.x, vertex_data.tex_coords.max.y] }, TextVertex { position: [vertex_data.pixel_coords.max.x, vertex_data.pixel_coords.min.y, 0.], uv: [vertex_data.tex_coords.max.x, vertex_data.tex_coords.min.y] }, TextVertex { position: [vertex_data.pixel_coords.max.x, vertex_data.pixel_coords.max.y, 0.], uv: [vertex_data.tex_coords.max.x, vertex_data.tex_coords.max.y] }, ]; result }