use std::{path::Path, fs::File, io::{Error, Read}, borrow::Cow};
use super::{Texture, Display};
use glium::texture;
use rusttype;
pub struct DynamicFont {
font: rusttype::Font<'static>,
height: u32
}
impl DynamicFont {
pub fn load(path: &Path, height: u32) -> Result<DynamicFont, Error> {
let mut buf = Vec::new();
File::open(path)?.read_to_end(&mut buf)?;
let font = rusttype::FontCollection::from_bytes(buf)?.into_font()?;
Ok(DynamicFont {font, height})
}
pub fn load_bytes(bytes: Vec<u8>, height: u32) -> Result<DynamicFont, Error> {
let font = rusttype::FontCollection::from_bytes(bytes)?.into_font()?;
Ok(DynamicFont {font, height})
}
pub(crate) fn draw_to_texture(&self, text: &str, display: &Display) -> Texture {
let scale = rusttype::Scale::uniform(self.height as f32);
let v_metrics = self.font.v_metrics(scale);
let offset = rusttype::point(0.0, v_metrics.ascent);
let glyphs: Vec<rusttype::PositionedGlyph> = self.font.layout(text, scale, offset).collect();
let width = glyphs
.iter()
.rev()
.map(|g| g.position().x as f32 + g.unpositioned().h_metrics().advance_width)
.next()
.unwrap_or(0.0)
.ceil() as u32;
let mut pixels = vec![0; (width * self.height) as usize];
for g in glyphs {
if let Some(bb) = g.pixel_bounding_box() {
g.draw(|x, y, v| {
let x = bb.min.x as u32 + x;
let y = bb.min.y as u32 + y;
if x < width && y < self.height {
pixels[(x + y * width) as usize] = (v * 255.0) as u8;
}
});
}
}
Texture::new(
texture::Texture2d::with_format(
display,
texture::RawImage2d {
data: Cow::Owned(pixels),
width,
height: self.height,
format: texture::ClientFormat::U8
},
texture::UncompressedFloatFormat::U8,
texture::MipmapsOption::NoMipmap
).unwrap(),
width,
self.height
)
}
pub(crate) fn load_default(height: u32) -> DynamicFont {
let font = rusttype::FontCollection::from_bytes(include_bytes!("../../font.ttf") as &[u8]).unwrap().into_font().unwrap();
DynamicFont {font, height}
}
}