font cache!

This commit is contained in:
griffi-gh 2023-11-24 17:54:23 +01:00
parent c986e36f88
commit 921b9fbb75
4 changed files with 70 additions and 46 deletions

3
Cargo.lock generated
View file

@ -548,7 +548,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0793f5137567643cf65ea42043a538804ff0fbf288649e2141442b602d81f9bc" checksum = "0793f5137567643cf65ea42043a538804ff0fbf288649e2141442b602d81f9bc"
dependencies = [ dependencies = [
"hashbrown 0.13.2", "hashbrown 0.13.2",
"rayon",
"ttf-parser 0.15.2", "ttf-parser 0.15.2",
] ]
@ -774,7 +773,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
dependencies = [ dependencies = [
"ahash", "ahash",
"rayon",
] ]
[[package]] [[package]]
@ -1048,7 +1046,6 @@ dependencies = [
"kubi-logging", "kubi-logging",
"log", "log",
"nohash-hasher", "nohash-hasher",
"rayon",
"rect_packer", "rect_packer",
"winit", "winit",
] ]

View file

@ -10,9 +10,8 @@ nohash-hasher = "0.2"
glam = "0.24" glam = "0.24"
glium = { git = "https://github.com/glium/glium", rev = "968fc92378caf", optional = true } glium = { git = "https://github.com/glium/glium", rev = "968fc92378caf", optional = true }
fontdue = "0.7" fontdue = "0.7"
rect_packer = { version = "0.2.1", optional = true } rect_packer = "0.2"
log = "0.4" log = "0.4"
rayon = { version = "1.8", optional = true }
[dev-dependencies] [dev-dependencies]
kubi-logging = { path = "../kubi-logging" } kubi-logging = { path = "../kubi-logging" }
@ -20,8 +19,8 @@ glium = { git = "https://github.com/glium/glium", rev = "968fc92378caf" }
winit = "0.29" winit = "0.29"
[features] [features]
default = ["builtin_elements", "builtin_font", "backend_glium", "parallel"] default = ["builtin_elements", "builtin_font", "backend_glium"]
backend_glium = ["dep:glium"] backend_glium = ["dep:glium"]
builtin_font = [] builtin_font = []
builtin_elements = [] builtin_elements = []
parallel = ["dep:rayon", "fontdue/parallel"] #parallel = ["dep:rayon", "fontdue/parallel"]

View file

@ -43,7 +43,7 @@ impl KubiUi {
draw_commands: UiDrawCommands::default(), draw_commands: UiDrawCommands::default(),
draw_plan: UiDrawPlan::default(), draw_plan: UiDrawPlan::default(),
draw_plan_modified: false, draw_plan_modified: false,
font_renderer: TextRenderer::new(), font_renderer: TextRenderer::default(),
} }
} }

View file

@ -1,59 +1,87 @@
use std::sync::Arc;
use fontdue::{Font, Metrics}; use fontdue::{Font, Metrics};
use glam::{IVec2, UVec2, uvec2, ivec2};
use hashbrown::HashMap; use hashbrown::HashMap;
use nohash_hasher::BuildNoHashHasher; use rect_packer::DensePacker;
#[cfg(feature = "parallel")]
use rayon::prelude::*;
#[cfg(feature = "builtin_font")] #[cfg(feature = "builtin_font")]
const BIN_FONT: &[u8] = include_bytes!("../assets/font/ProggyTiny.ttf"); const BIN_FONT: &[u8] = include_bytes!("../assets/font/ProggyTiny.ttf");
// pub struct Glyph { #[derive(Clone, Copy, PartialEq, Eq, Hash)]
// pub metrics: Metrics, pub struct FontHandle(pub(crate) usize);
// pub data: Box<[u8]>
// }
// pub struct FontData { #[derive(PartialEq, Eq, Hash)]
// font: Font, struct GlyphCacheKey {
// cache: HashMap<(u8, char), Glyph, BuildNoHashHasher<u8>> font_index: usize,
// } character: char,
size: u8,
}
// impl FontData { struct GlyphCacheEntry {
// pub fn new() -> Self { pub data: Vec<u8>,
// FontData { pub metrics: Metrics,
// font: Font::from_bytes(BIN_FONT, fontdue::FontSettings::default()).unwrap(), pub texture_position: IVec2,
// cache: HashMap::default() pub texture_size: UVec2,
// } }
// }
// fn prebake(&mut self, size: u8) {
// self.cache = (33..=126).par_bridge().map(|c| {
// let (metrics, data) = self.font.rasterize(
// char::from(c),
// c as f32,
// );
// Glyph { metrics, data: data.into_boxed_slice() }
// }).collect();
// }
// }
pub struct TextRenderer { pub struct TextRenderer {
font_stack: Vec<Font>, fonts: Vec<Font>,
cache: () glyph_cache: HashMap<GlyphCacheKey, Arc<GlyphCacheEntry>>,
packer: DensePacker,
font_texture: Vec<u8>,
font_texture_size: UVec2,
} }
impl TextRenderer { impl TextRenderer {
pub fn new() -> Self { pub fn new(size: UVec2) -> Self {
let font = Font::from_bytes(BIN_FONT, fontdue::FontSettings::default()).unwrap(); let mut renderer = TextRenderer {
TextRenderer { fonts: Vec::new(),
font_stack: vec![font], glyph_cache: HashMap::new(),
cache: () packer: DensePacker::new(size.x as i32, size.y as i32),
font_texture: vec![0; (size.x * size.y) as usize],
font_texture_size: size,
};
#[cfg(feature = "builtin_font")]
{
let font = Font::from_bytes(BIN_FONT, fontdue::FontSettings::default()).unwrap();
renderer.add_font(font);
} }
renderer
}
/// Add a (fontdue) font to the renderer.
pub fn add_font(&mut self, font: Font) -> FontHandle {
self.fonts.push(font);
FontHandle(self.fonts.len() - 1)
}
/// Either looks up the glyph in the cache or renders it and adds it to the cache.
pub fn glyph(&mut self, font: FontHandle, character: char, size: u8) -> Arc<GlyphCacheEntry> {
let key = GlyphCacheKey {
font_index: font.0,
character,
size,
};
if let Some(entry) = self.glyph_cache.get(&key) {
return Arc::clone(entry);
}
let font = &self.fonts[key.font_index];
let (metrics, bitmap) = font.rasterize(character, size as f32);
let texture_position = self.packer.pack(metrics.width as i32, metrics.height as i32, false).unwrap();
let texture_size = uvec2(metrics.width as u32, metrics.height as u32);
let entry = Arc::new(GlyphCacheEntry {
data: bitmap,
metrics,
texture_position: ivec2(texture_position.x, texture_position.y),
texture_size,
});
self.glyph_cache.insert_unique_unchecked(key, Arc::clone(&entry));
entry
} }
} }
impl Default for TextRenderer { impl Default for TextRenderer {
fn default() -> Self { fn default() -> Self {
Self::new() Self::new(uvec2(2048, 2048))
} }
} }