mirror of
https://github.com/lisk77/comet.git
synced 2025-10-23 21:38:50 +00:00
feat: ttf fonts are now loadable
This commit is contained in:
parent
9e16179df3
commit
0507703284
4 changed files with 136 additions and 54 deletions
|
@ -550,6 +550,11 @@ impl<'a> Renderer2D<'a> {
|
|||
self.graphic_resource_manager.texture_atlas().textures().get(&texture_path).unwrap()
|
||||
}
|
||||
|
||||
pub fn get_glyph_region(&self, glyph: char, font: String) -> &TextureRegion {
|
||||
let font_atlas = self.graphic_resource_manager.fonts().iter().find(|f| f.name() == font).unwrap();
|
||||
font_atlas.get_glyph(glyph).unwrap()
|
||||
}
|
||||
|
||||
fn create_rectangle(&self, width: f32, height: f32) -> Vec<Vertex> {
|
||||
let (bound_x, bound_y) =
|
||||
((width/ self.config.width as f32) * 0.5, (height/ self.config.height as f32) * 0.5);
|
||||
|
@ -564,7 +569,7 @@ impl<'a> Renderer2D<'a> {
|
|||
|
||||
/// A function that allows you to set the texture atlas with a list of paths to the textures.
|
||||
/// The old texture atlas will be replaced with the new one.
|
||||
pub fn set_texture_atlas(&mut self, paths: Vec<String>) {
|
||||
pub fn set_texture_atlas_by_paths(&mut self, paths: Vec<String>) {
|
||||
self.graphic_resource_manager.create_texture_atlas(paths);
|
||||
self.diffuse_texture = Texture::from_image(&self.device, &self.queue, self.graphic_resource_manager.texture_atlas().atlas(), None, false).unwrap();
|
||||
|
||||
|
@ -609,6 +614,95 @@ impl<'a> Renderer2D<'a> {
|
|||
self.diffuse_bind_group = diffuse_bind_group;
|
||||
}
|
||||
|
||||
fn set_texture_atlas(&mut self) {
|
||||
self.diffuse_texture = Texture::from_image(&self.device, &self.queue, self.graphic_resource_manager.texture_atlas().atlas(), None, false).unwrap();
|
||||
|
||||
let texture_bind_group_layout =
|
||||
self.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
entries: &[
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||
ty: wgpu::BindingType::Texture {
|
||||
multisampled: false,
|
||||
view_dimension: wgpu::TextureViewDimension::D2,
|
||||
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 1,
|
||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
|
||||
count: None,
|
||||
},
|
||||
],
|
||||
label: Some("texture_bind_group_layout"),
|
||||
});
|
||||
|
||||
let diffuse_bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &texture_bind_group_layout,
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::TextureView(&self.diffuse_texture.view),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
resource: wgpu::BindingResource::Sampler(&self.diffuse_texture.sampler),
|
||||
},
|
||||
],
|
||||
label: Some("diffuse_bind_group"),
|
||||
});
|
||||
|
||||
self.diffuse_bind_group = diffuse_bind_group;
|
||||
}
|
||||
|
||||
fn set_font_atlas(&mut self, font: String) {
|
||||
let font_atlas = self.graphic_resource_manager.fonts().iter().find(|f| f.name() == font).unwrap();
|
||||
self.diffuse_texture = Texture::from_image(&self.device, &self.queue, font_atlas.glyphs().atlas(), None, false).unwrap();
|
||||
|
||||
let texture_bind_group_layout =
|
||||
self.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
entries: &[
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||
ty: wgpu::BindingType::Texture {
|
||||
multisampled: false,
|
||||
view_dimension: wgpu::TextureViewDimension::D2,
|
||||
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 1,
|
||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
|
||||
count: None,
|
||||
},
|
||||
],
|
||||
label: Some("texture_bind_group_layout"),
|
||||
});
|
||||
|
||||
let diffuse_bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &texture_bind_group_layout,
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::TextureView(&self.diffuse_texture.view),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
resource: wgpu::BindingResource::Sampler(&self.diffuse_texture.sampler),
|
||||
},
|
||||
],
|
||||
label: Some("diffuse_bind_group"),
|
||||
});
|
||||
|
||||
self.diffuse_bind_group = diffuse_bind_group;
|
||||
}
|
||||
|
||||
fn get_project_root() -> std::io::Result<PathBuf> {
|
||||
let path = std::env::current_dir()?;
|
||||
let mut path_ancestors = path.as_path().ancestors();
|
||||
|
@ -634,7 +728,7 @@ impl<'a> Renderer2D<'a> {
|
|||
paths.push(texture_path.clone() + path.unwrap().file_name().to_str().unwrap());
|
||||
}
|
||||
|
||||
self.set_texture_atlas(paths);
|
||||
self.set_texture_atlas_by_paths(paths);
|
||||
}
|
||||
|
||||
/// A function that clears the buffers and sets the vertex and index buffer of the `Renderer2D` with the given data.
|
||||
|
@ -686,13 +780,13 @@ impl<'a> Renderer2D<'a> {
|
|||
self.vertex_buffer = self.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Updated Vertex Buffer"),
|
||||
contents: bytemuck::cast_slice(&self.vertex_data),
|
||||
usage: wgpu::BufferUsages::VERTEX,
|
||||
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
|
||||
});
|
||||
|
||||
self.index_buffer = self.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Updated Index Buffer"),
|
||||
contents: bytemuck::cast_slice(&self.index_data),
|
||||
usage: wgpu::BufferUsages::INDEX,
|
||||
usage: wgpu::BufferUsages::INDEX | BufferUsages::COPY_DST,
|
||||
});
|
||||
|
||||
self.num_indices = self.index_data.len() as u32;
|
||||
|
@ -706,13 +800,13 @@ impl<'a> Renderer2D<'a> {
|
|||
self.vertex_buffer = self.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Updated Vertex Buffer"),
|
||||
contents: bytemuck::cast_slice(&self.vertex_data),
|
||||
usage: wgpu::BufferUsages::VERTEX,
|
||||
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
|
||||
});
|
||||
|
||||
self.index_buffer = self.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Updated Index Buffer"),
|
||||
contents: bytemuck::cast_slice(&self.index_data),
|
||||
usage: wgpu::BufferUsages::INDEX,
|
||||
usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
|
||||
});
|
||||
|
||||
self.num_indices = self.index_data.len() as u32;
|
||||
|
@ -744,35 +838,17 @@ impl<'a> Renderer2D<'a> {
|
|||
}
|
||||
|
||||
/// A function to draw text at a given position.
|
||||
pub fn draw_text_at(&mut self, text: &str, position: Point3) {
|
||||
pub fn draw_text_at(&mut self, text: &str, font: String, position: Point3) {
|
||||
self.set_font_atlas(font.clone());
|
||||
|
||||
let mut x = position.x();
|
||||
let mut y = position.y();
|
||||
|
||||
for c in text.chars() {
|
||||
let region = self.get_texture_region(c.to_string());
|
||||
let (dim_x, dim_y) = region.dimensions();
|
||||
|
||||
let (bound_x, bound_y) =
|
||||
((dim_x as f32/ self.config.width as f32) * 0.5, (dim_y as f32/ self.config.height as f32) * 0.5);
|
||||
|
||||
let vertices: &mut Vec<Vertex> = &mut vec![
|
||||
Vertex :: new ( [-bound_x + x, bound_y + y, 0.0], [region.x0(), region.y0()], [0.0, 0.0, 0.0, 0.0] ),
|
||||
Vertex :: new ( [-bound_x + x, -bound_y + y, 0.0], [region.x0(), region.y1()], [0.0, 0.0, 0.0, 0.0] ),
|
||||
Vertex :: new ( [ bound_x + x, -bound_y + y, 0.0], [region.x1(), region.y1()], [0.0, 0.0, 0.0, 0.0] ) ,
|
||||
Vertex :: new ( [ bound_x + x, bound_y + y, 0.0], [region.x1(), region.y0()], [0.0, 0.0, 0.0, 0.0] )
|
||||
];
|
||||
|
||||
let buffer_size = self.vertex_data.len() as u16;
|
||||
|
||||
let indices: &mut Vec<u16> = &mut vec![
|
||||
0 + buffer_size, 1 + buffer_size, 3 + buffer_size,
|
||||
1 + buffer_size, 2 + buffer_size, 3 + buffer_size
|
||||
];
|
||||
|
||||
self.push_to_buffers(vertices, indices);
|
||||
|
||||
x += dim_x as f32;
|
||||
self.draw_texture_at(font.clone() + &c.to_string(), Point3::new(x, y, position.z()));
|
||||
}
|
||||
|
||||
self.set_texture_atlas();
|
||||
}
|
||||
|
||||
fn find_priority_camera(&self, cameras: Vec<Camera2D>) -> usize {
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
use image::{DynamicImage, Rgba, RgbaImage};
|
||||
use ab_glyph::{FontArc, PxScale, ScaleFont, Glyph, point, Font as AbFont};
|
||||
use crate::texture_atlas::{TextureAtlas, TextureRegion};
|
||||
|
||||
pub struct Font {
|
||||
name: String,
|
||||
glyphs: Vec<DynamicImage>,
|
||||
glyphs: TextureAtlas,
|
||||
}
|
||||
|
||||
impl Font {
|
||||
pub fn new(path: &str, size: f32) -> Self {
|
||||
Font {
|
||||
name: path.to_string(),
|
||||
glyphs: Self::generate_images(path, size),
|
||||
glyphs: Self::generate_atlas(path, size)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,31 +19,22 @@ impl Font {
|
|||
&self.name
|
||||
}
|
||||
|
||||
pub fn names(&self) -> Vec<String> {
|
||||
let mut names = Vec::new();
|
||||
for code_point in 0x0020..=0x007E {
|
||||
if let Some(ch) = std::char::from_u32(code_point) {
|
||||
names.push(ch.to_string());
|
||||
}
|
||||
}
|
||||
names
|
||||
pub fn glyphs(&self) -> &TextureAtlas {
|
||||
&self.glyphs
|
||||
}
|
||||
|
||||
pub fn glyph(&self, index: usize) -> &DynamicImage {
|
||||
&self.glyphs[index]
|
||||
pub fn get_glyph(&self, ch: char) -> Option<&TextureRegion> {
|
||||
self.glyphs.textures().get(&ch.to_string())
|
||||
}
|
||||
|
||||
pub fn glyphs(&self) -> Vec<DynamicImage> {
|
||||
self.glyphs.clone()
|
||||
}
|
||||
|
||||
fn generate_images(path: &str, size: f32) -> Vec<DynamicImage> {
|
||||
fn generate_atlas(path: &str, size: f32) -> TextureAtlas {
|
||||
let font_data = std::fs::read(path).expect("Failed to read font file");
|
||||
let font = FontArc::try_from_vec(font_data).expect("Failed to load font");
|
||||
|
||||
let scale = PxScale::from(size);
|
||||
let scaled_font = font.as_scaled(scale);
|
||||
|
||||
let mut names = Vec::new();
|
||||
let mut images = Vec::new();
|
||||
|
||||
for code_point in 0x0020..=0x007E {
|
||||
|
@ -51,6 +43,8 @@ impl Font {
|
|||
continue;
|
||||
}
|
||||
|
||||
names.push(ch.to_string());
|
||||
|
||||
let glyph = Glyph {
|
||||
id: font.glyph_id(ch),
|
||||
scale,
|
||||
|
@ -80,6 +74,7 @@ impl Font {
|
|||
}
|
||||
}
|
||||
}
|
||||
images
|
||||
|
||||
TextureAtlas::from_textures(names, images)
|
||||
}
|
||||
}
|
|
@ -4,12 +4,14 @@ use std::{
|
|||
|
||||
use wgpu::{naga, Device, FilterMode, Queue, ShaderModule, TextureFormat, TextureUsages};
|
||||
use wgpu::naga::ShaderStage;
|
||||
use comet_log::info;
|
||||
use crate::{font, texture, Texture};
|
||||
use crate::font::Font;
|
||||
use crate::texture_atlas::{TextureAtlas, TextureRegion};
|
||||
|
||||
pub struct GraphicResourceManager {
|
||||
texture_atlas: TextureAtlas,
|
||||
fonts: HashMap<String, TextureAtlas>,
|
||||
fonts: Vec<Font>,
|
||||
data_files: HashMap<String, String>,
|
||||
shaders: HashMap<String, ShaderModule>
|
||||
}
|
||||
|
@ -18,7 +20,7 @@ impl GraphicResourceManager {
|
|||
pub fn new() -> Self {
|
||||
Self {
|
||||
texture_atlas: TextureAtlas::empty(),
|
||||
fonts: HashMap::new(),
|
||||
fonts: Vec::new(),
|
||||
data_files: HashMap::new(),
|
||||
shaders: HashMap::new()
|
||||
}
|
||||
|
@ -36,6 +38,14 @@ impl GraphicResourceManager {
|
|||
&self.data_files
|
||||
}
|
||||
|
||||
pub fn fonts(&self) -> &Vec<Font> {
|
||||
&self.fonts
|
||||
}
|
||||
|
||||
pub fn get_glyph(&self, font: &str, ch: char) -> Option<&TextureRegion> {
|
||||
self.fonts.iter().find(|f| f.name() == font).and_then(|f| f.get_glyph(ch))
|
||||
}
|
||||
|
||||
pub fn set_texture_atlas(&mut self, texture_atlas: TextureAtlas) {
|
||||
self.texture_atlas = texture_atlas;
|
||||
|
||||
|
@ -122,9 +132,10 @@ impl GraphicResourceManager {
|
|||
}
|
||||
|
||||
pub fn load_font(&mut self, path: &str, size: f32) {
|
||||
let font = font::Font::new(path, size);
|
||||
let atlas = TextureAtlas::from_textures(font.glyphs(), font.names());
|
||||
self.fonts.insert(font.name().to_string(), atlas);
|
||||
info!("Loading font: {}", path);
|
||||
let font = Font::new(path, size);
|
||||
info!("Font {} loaded!", font.name());
|
||||
self.fonts.push(font);
|
||||
}
|
||||
|
||||
/*pub async fn load_model(
|
||||
|
|
|
@ -166,8 +166,8 @@ impl TextureAtlas {
|
|||
}
|
||||
|
||||
pub fn from_textures(
|
||||
textures: Vec<DynamicImage>,
|
||||
names: Vec<String>,
|
||||
textures: Vec<DynamicImage>,
|
||||
) -> Self {
|
||||
let mut regions: HashMap<String, TextureRegion> = HashMap::new();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue