120 lines
5.7 KiB
Rust
120 lines
5.7 KiB
Rust
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<Vec<TextVertex>>, game_objects: &mut Vec<GameObject>) {
|
|
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<T>() -> GlyphBrush<T> {
|
|
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<Vec<TextVertex>>, 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<TextureHandle>, renderer: &mut VulkanRenderer, rect: Rectangle<u32>, text_data: &[u8]) -> Option<TextureHandle> {
|
|
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<Vec<TextVertex>>, texture_index: usize, mesh_index: Option<usize>, renderer: &mut VulkanRenderer) -> Option<MeshHandle> {
|
|
let mut final_vertices = vec![];
|
|
let mut final_indices: Vec<u32> = 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<TextVertex> {
|
|
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
|
|
} |