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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use { freetype, graphics, Texture, TextureSettings };
use std::collections::HashMap;
use graphics::types::Scalar;
extern crate fnv;
use self::fnv::FnvHasher;
use std::hash::BuildHasherDefault;
use std::path::Path;
use error::Error;
pub use graphics::types::FontSize;
pub type Character<'a> = graphics::character::Character<'a, Texture>;
pub struct GlyphCache<'a> {
pub face: freetype::Face<'a>,
data: HashMap<(FontSize, char),
([Scalar; 2], [Scalar; 2], Texture),
BuildHasherDefault<FnvHasher>>,
}
impl<'a> GlyphCache<'a> {
pub fn new<P>(font: P) -> Result<GlyphCache<'static>, Error>
where P: AsRef<Path>
{
let fnv = BuildHasherDefault::<FnvHasher>::default();
freetype::Library::init()
.and_then(|freetype| freetype.new_face(font.as_ref(), 0) )
.map_err( Error::FreetypeError )
.map(|face| GlyphCache {
face: face,
data: HashMap::with_hasher(fnv),
} )
}
pub fn from_bytes(font: &'a [u8]) -> Result<GlyphCache<'a>, Error> {
let fnv = BuildHasherDefault::<FnvHasher>::default();
freetype::Library::init()
.and_then(|freetype| freetype.new_memory_face(font, 0) )
.map_err( Error::FreetypeError )
.map(|face| GlyphCache {
face: face,
data: HashMap::with_hasher(fnv),
} )
}
fn get(&mut self, size: FontSize, ch: char)
-> &([Scalar; 2], [Scalar; 2], Texture) {
fn create_character(face: &freetype::Face, size: FontSize, ch: char)
-> ([Scalar; 2], [Scalar; 2], Texture) {
face.set_pixel_sizes(0, size).unwrap();
face.load_char(ch 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 = Texture::from_memory_alpha(bitmap.buffer(),
bitmap.width() as u32,
bitmap.rows() as u32,
&TextureSettings::new()).unwrap();
(
[bitmap_glyph.left() as f64, bitmap_glyph.top() as f64],
[(glyph.advance_x() >> 16) as f64, (glyph.advance_y() >> 16) as f64],
texture,
)
}
let face = &self.face;
self.data.entry((size, ch))
.or_insert_with(|| create_character(face, size, ch) )
}
pub fn preload_chars<I>(
&mut self,
size: FontSize,
chars: I
)
where
I: Iterator<Item = char>
{
for ch in chars {
self.get(size, ch);
}
}
pub fn preload_printable_ascii(&mut self, size: FontSize) {
self.preload_chars(size, (0x20u8 .. 0x7F).map(|ch| ch as char));
}
pub fn opt_character(&self, size: FontSize, ch: char) -> Option<Character> {
self.data.get(&(size, ch)).map(|&(offset, size, ref texture)| {
Character {
offset: offset,
size: size,
texture: texture
}
})
}
}
impl<'b> graphics::character::CharacterCache for GlyphCache<'b> {
type Texture = Texture;
fn character<'a>(&'a mut self, size: FontSize, ch: char) -> Character<'a> {
let &(offset, size, ref texture) = self.get(size, ch);
return Character {
offset: offset,
size: size,
texture: texture
}
}
}