From 85221b5e4e2c767c40fa15ea841a04ff49614533 Mon Sep 17 00:00:00 2001 From: Erin Date: Tue, 15 Aug 2017 12:24:06 -0500 Subject: [PATCH] Start work on rasterizer --- textium/src/error.rs | 14 +++++++ textium/src/lib.rs | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 textium/src/error.rs create mode 100644 textium/src/lib.rs diff --git a/textium/src/error.rs b/textium/src/error.rs new file mode 100644 index 0000000..e32c0d7 --- /dev/null +++ b/textium/src/error.rs @@ -0,0 +1,14 @@ +use glium; + +#[derive(Debug)] +pub enum Error { + TextureCreationError(glium::texture::TextureCreationError), + PackingError, + NotAGlyph(char), +} + +impl From for Error { + fn from(err: glium::texture::TextureCreationError) -> Error { + Error::TextureCreationError(err) + } +} diff --git a/textium/src/lib.rs b/textium/src/lib.rs new file mode 100644 index 0000000..bfc69a5 --- /dev/null +++ b/textium/src/lib.rs @@ -0,0 +1,111 @@ +//! Textium is a small library that wires Rusttype up to Glium. + +extern crate rusttype; +#[macro_use] +extern crate glium; + +mod texture; +mod geometry; +mod error; + +use std::iter::Iterator; +use std::collections::HashMap; +use glium::backend::Facade; +use glium::texture::Texture2d; +use rusttype::Font; + +use texture::{Texture2dData, get_nearest_pow2}; +pub use error::Error; +pub use geometry::Rect; + +/// Information used to render a glyph in a font. +#[derive(Debug)] +pub struct GlyphMetadata { + /// Coordinates of the top left of this glyph in the font's texture + texture_coord: (f32, f32), + + /// Width and height of the glyph's texture. + texture_size: (f32, f32), + + /// Size of the glyph, in ems. + em_size: (f32, f32), + + /// Distance between the bottom of the glyph and the baseline, in ems. + baseline_distance: f32, + + /// Left padding on the glyph, in ems. + left_padding: f32, + + /// Left padding on the glyph, in ems. + right_padding: f32, +} + +pub struct FontAtlas { + glyph_data: HashMap +} + +pub struct FontTexture { + /// The GPU texture of packed glyphs. + texture: Texture2d, + + /// Atlas describing where glyphs are. + atlas: FontAtlas, +} + +pub trait FontPacker { + fn pack(&self, font: Font, characters: C, font_size: u32) -> Result<(Texture2dData, HashMap), Error> + where C: Iterator; +} + +pub struct NaiveFontPacker; +impl FontPacker for NaiveFontPacker { + fn pack(&self, font: Font, characters: C, font_size: u32) -> Result<(Texture2dData, HashMap), Error> + where C: Iterator + { + // Margin around each character in the texture + const MARGIN: u32 = 2; + + let invalid_char_width = font_size / 2; + + let estimated_glyphs = characters.size_hint().1.unwrap_or(0); + + let mut texture_data: Vec = Vec::with_capacity( + estimated_glyphs * (font_size as usize).pow(2)); + + let texture_width = get_nearest_pow2(std::cmp::max(font_size * 2, + (((estimated_glyphs as u32) * font_size.pow(2)) as f32).sqrt() as u32)); + + let mut cursor = (0u32, 0u32); + let mut skip_rows = 0u32; + + // let glyph_metadata = characters.map(|character| { + // let scaled_glyph = font.glyph(character) + // .ok_or_else(|| Error::NotAGlyph(character))? + // .scaled(rusttype::Scale::uniform(font_size as f32)); + + // // let h_metrics = + // }).collect::, Error>>()?; + + + Err(Error::PackingError) + } +} + +// TODO: make this an actual From once TryFrom is stabilized. +impl FontTexture { + /// Load a font from a Rusttype font into a Textium font texture, and upload it to Glium. + pub fn from_font(font: Font, font_size: u32, facade: &Facade, packer: T) -> Result + where T: FontPacker + { + let characters: Vec = (0..255).filter_map(|c| ::std::char::from_u32(c)).collect(); + + let (texture_data, meta) = packer.pack(font, characters.into_iter(), font_size)?; + + let texture = Texture2d::new(facade, &texture_data)?; + + Ok(FontTexture { + texture: texture, + glyph_metadata: meta, + }) + } +}