darkengine 0.1.0

2D game engine written in Rust
use std::{path::Path, fs::File, io::{Error, Read}, borrow::Cow};
use super::{Texture, Display};
use glium::texture;
use rusttype;

/// A TTF font.
pub struct DynamicFont {
	font: rusttype::Font<'static>,
	height: u32
}

impl DynamicFont {
	/// Load a font from a file.
	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})
	}

	/// Load a font from a byte array.
	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}
	}
}