1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use std::path::Path;
use std::collections::HashMap;
use graphics::character::{ CharacterCache, Character };
use graphics::types::FontSize;
use glium::Texture2d;
use glium::backend::Facade;
use glium::texture::RawImage2d;
use image::{ Rgba, ImageBuffer };
use freetype::{ self, Face };
use Texture;
fn load_character<F: Facade>(face: &Face, facade: &F, font_size: FontSize,
character: char)
-> Character<Texture>
{
face.set_pixel_sizes(0, font_size).unwrap();
face.load_char(character as usize, freetype::face::DEFAULT).unwrap();
let glyph = face.glyph().get_glyph().unwrap();
let bitmap_glyph = glyph.to_bitmap(freetype::render_mode::RenderMode::Normal, None).unwrap();
let bitmap = bitmap_glyph.bitmap();
let texture =
if bitmap.width() != 0 {
let image = ImageBuffer::<Rgba<u8>, _>::from_raw(
bitmap.width() as u32, bitmap.rows() as u32,
bitmap.buffer().iter()
.flat_map(|&pix| vec![255, 255, 255, pix].into_iter())
.collect::<Vec<_>>()
).expect("failed to create glyph texture");
let image_dimensions = image.dimensions();
Texture2d::new(
facade,
RawImage2d::from_raw_rgba_reversed(
image.into_raw(), image_dimensions
)
)
} else { Texture2d::empty(facade, 1, 1) };
let glyph_size_x = glyph.advance_x();
let glyph_size_y = glyph.advance_y();
Character {
offset: [
bitmap_glyph.left() as f64,
bitmap_glyph.top() as f64
],
size: [
(glyph_size_x >> 16) as f64,
(glyph_size_y >> 16) as f64
],
texture: Texture::new(texture.unwrap()),
}
}
pub struct GlyphCache<F> {
face: Face<'static>,
data: HashMap<FontSize, HashMap<char, Character<Texture>>>,
facade: F,
}
impl<F> GlyphCache<F> {
pub fn new(font: &Path, facade: F) -> Result<Self, freetype::error::Error> {
let freetype = try!(freetype::Library::init());
let face = try!(freetype.new_face(font, 0));
Ok(GlyphCache {
face: face,
data: HashMap::new(),
facade: facade,
})
}
}
impl<F: Facade> CharacterCache for GlyphCache<F> {
type Texture = Texture;
fn character<'a>(&'a mut self, font_size: FontSize, character: char)
-> &'a Character<Texture>
{
use std::collections::hash_map::Entry::{Vacant, Occupied};
let size_cache: &'a mut HashMap<char, _> = match self.data.entry(font_size) {
Vacant(entry) => entry.insert(HashMap::new()),
Occupied(entry) => entry.into_mut(),
};
match size_cache.entry(character) {
Vacant(entry) => entry.insert(load_character(&self.face, &self.facade, font_size, character)),
Occupied(entry) => entry.into_mut(),
}
}
}