From 78355c6a15487c8dd42643412b1aa227cd71b02e Mon Sep 17 00:00:00 2001 From: Erin Date: Fri, 18 Aug 2017 22:51:10 -0500 Subject: [PATCH] textium: add face cache --- textium/src/cache.rs | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++ textium/src/lib.rs | 29 +++++++++++++++++- 2 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 textium/src/cache.rs diff --git a/textium/src/cache.rs b/textium/src/cache.rs new file mode 100644 index 0000000..a043740 --- /dev/null +++ b/textium/src/cache.rs @@ -0,0 +1,83 @@ +use std::rc::Rc; +use std::error::Error; +use std::collections::HashMap; + +use ::rasterizer::Font; +use ::{FontAtlas, Scale}; +use ::texture::{Buffer2d, Bitmap}; + +#[derive(PartialEq, Eq, Hash)] +struct FaceKey { + name: String, + scale: Scale, +} + +pub struct CachedFaceData where B: Buffer2d { + buffer: B, + atlas: FontAtlas, + line_height: f32, +} + +#[derive(Debug)] +pub enum CacheError { + NoSuchFont(String) +} + +pub struct Cache<'a, B> where B: Buffer2d { + fonts: HashMap>, + faces: HashMap>, + upload_queue: Vec, +} + +impl<'a, B> Cache<'a, B> where B: Buffer2d { + pub fn new() -> Cache<'a, B> { + Cache { + fonts: HashMap::new(), + faces: HashMap::new(), + upload_queue: Vec::new(), + } + } + + pub fn add_font(&mut self, name: S, font: Font<'a>) where S: Into { + self.fonts.insert(name.into(), font); + } + + pub fn build_face(&mut self, name: &str, scale: f32, + chars: I, buffer_transform: F) -> Result<(), CacheError> + where I: Iterator, + F: Fn(Bitmap) -> Result + { + let key = FaceKey {name: String::from(name), scale: Scale(scale)}; + if self.faces.contains_key(&key) { + return Ok(()); + } + + match self.fonts.get(name) { + Some(font) => { + let face_data = CachedFaceData::new(font, scale, chars, buffer_transform)?; + self.faces.insert(key, face_data); + + Ok(()) + }, + None => Err(CacheError::NoSuchFont(name.into())), + } + } +} + +impl CachedFaceData where B: Buffer2d { + pub fn new(font: &Font, scale: f32, chars: I, buffer_transform: F) + -> Result, CacheError> + where I: Iterator, + F: Fn(Bitmap) -> Result + { + let (atlas, bitmap, line_height): (FontAtlas, Bitmap, f32) = font.make_atlas(chars, scale, 1, 256, 256); + + let bitmap = buffer_transform(bitmap)?; + + Ok(CachedFaceData { + buffer: bitmap, + atlas: atlas, + line_height: line_height, + }) + } +} diff --git a/textium/src/lib.rs b/textium/src/lib.rs index 090887b..83b9740 100644 --- a/textium/src/lib.rs +++ b/textium/src/lib.rs @@ -14,8 +14,10 @@ pub mod texture; pub mod geometry; pub mod rasterizer; pub mod packer; +pub mod cache; use std::collections::HashMap; +use std::hash::{Hash, Hasher}; use glium::texture::Texture2d; pub use error::Error; @@ -23,7 +25,7 @@ pub use geometry::Rect; pub use rasterizer::Font; /// Information used to render a glyph in a font. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct GlyphMetadata { /// Bounding box in the packed texture bounding_box: Rect, @@ -41,10 +43,17 @@ pub struct GlyphMetadata { } /// Maps glyphs to their size, location, and rendering properties in a glyph atlas. +#[derive(Debug)] pub struct FontAtlas { pub glyph_metadata: HashMap } +impl FontAtlas { + pub fn info(&self, chr: char) -> Option { + self.glyph_metadata.get(&chr).cloned() + } +} + /// A GPU-backed font texture, plus a [`FontAtlas`]. /// /// [`FontAtlas`]: struct.FontAtlas.html @@ -56,3 +65,21 @@ pub struct FontTexture { pub atlas: FontAtlas, } +#[derive(Debug, Clone, Copy)] +struct Scale(f32); +impl Scale { + fn canonicalize(&self) -> i64 { + (self.0 * 1024.0 * 1024.0).round() as i64 + } +} +impl PartialEq for Scale { + fn eq(&self, other: &Self) -> bool { + self.canonicalize() == other.canonicalize() + } +} +impl Eq for Scale {} +impl Hash for Scale { + fn hash(&self, state: &mut H) where H: Hasher { + self.canonicalize().hash(state); + } +}