|
|
@ -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<B> 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<String, Font<'a>>,
|
|
|
|
faces: HashMap<FaceKey, CachedFaceData<B>>,
|
|
|
|
upload_queue: Vec<FaceKey>,
|
|
|
|
}
|
|
|
|
|
|
|
|
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<S>(&mut self, name: S, font: Font<'a>) where S: Into<String> {
|
|
|
|
self.fonts.insert(name.into(), font);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn build_face<I, F>(&mut self, name: &str, scale: f32,
|
|
|
|
chars: I, buffer_transform: F) -> Result<(), CacheError>
|
|
|
|
where I: Iterator<Item=char>,
|
|
|
|
F: Fn(Bitmap<u8>) -> Result<B, CacheError>
|
|
|
|
{
|
|
|
|
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<B> CachedFaceData<B> where B: Buffer2d {
|
|
|
|
pub fn new<I, F>(font: &Font, scale: f32, chars: I, buffer_transform: F)
|
|
|
|
-> Result<CachedFaceData<B>, CacheError>
|
|
|
|
where I: Iterator<Item=char>,
|
|
|
|
F: Fn(Bitmap<u8>) -> Result<B, CacheError>
|
|
|
|
{
|
|
|
|
let (atlas, bitmap, line_height): (FontAtlas, Bitmap<u8>, f32) = font.make_atlas(chars, scale, 1, 256, 256);
|
|
|
|
|
|
|
|
let bitmap = buffer_transform(bitmap)?;
|
|
|
|
|
|
|
|
Ok(CachedFaceData {
|
|
|
|
buffer: bitmap,
|
|
|
|
atlas: atlas,
|
|
|
|
line_height: line_height,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|