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
90
91
92
93
use std::path::Path;
use std::collections::HashMap;
use graphics::character::{ CharacterCache, Character };
use graphics::types::{ FontSize, Scalar };
use glium::texture::srgb_texture2d::SrgbTexture2d;
use glium::backend::Facade;
use glium::texture::RawImage2d;
use image::{ Rgba, ImageBuffer };
use freetype::{ self, Face };
use Texture;
pub struct GlyphCache<F> {
face: Face<'static>,
data: HashMap<(FontSize, char), ([Scalar; 2], [Scalar; 2], Texture)>,
facade: F,
}
impl<F> GlyphCache<F> where F: Facade {
pub fn new<P>(font: P, facade: F) -> Result<Self, freetype::error::Error>
where P: AsRef<Path>
{
let freetype = try!(freetype::Library::init());
let face = try!(freetype.new_face(font.as_ref(), 0));
Ok(GlyphCache {
face: face,
data: HashMap::new(),
facade: facade,
})
}
fn get(&mut self, font_size: FontSize, character: char)
-> &([Scalar; 2], [Scalar; 2], Texture)
{
fn create_character<F: Facade>(
facade: &F,
face: &freetype::Face,
font_size: FontSize,
character: char
) -> ([Scalar; 2], [Scalar; 2], 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();
SrgbTexture2d::new(
facade,
RawImage2d::from_raw_rgba_reversed(
image.into_raw(), image_dimensions
)
)
} else { SrgbTexture2d::empty(facade, 1, 1) };
let glyph_size_x = glyph.advance_x();
let glyph_size_y = glyph.advance_y();
(
[bitmap_glyph.left() as f64, bitmap_glyph.top() as f64],
[(glyph_size_x >> 16) as f64, (glyph_size_y >> 16) as f64],
Texture::new(texture.unwrap())
)
}
let face = &self.face;
let facade = &self.facade;
self.data.entry((font_size, character))
.or_insert_with(|| create_character(facade, face, font_size, character) )
}
}
impl<F: Facade> CharacterCache for GlyphCache<F> {
type Texture = Texture;
fn character<'a>(&'a mut self, size: FontSize, ch: char) -> Character<'a, Texture> {
let &(offset, size, ref texture) = self.get(size, ch);
return Character {
offset: offset,
size: size,
texture: texture
}
}
}