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
use std::{collections::HashMap, error};
use graphics::{
character::{Character, CharacterCache},
types::{FontSize, Scalar},
};
use rusttype::{point, Error, Font, GlyphId, Rect, Scale};
use super::*;
#[derive(Clone)]
struct CharacterDef {
offset: [Scalar; 2],
size: [Scalar; 2],
texture: RenderBuffer,
}
impl CharacterDef {
fn as_character(&self) -> Character<'_, RenderBuffer> {
Character {
offset: self.offset,
size: self.size,
texture: &self.texture,
}
}
}
#[derive(Clone)]
pub struct BufferGlyphs<'f> {
characters: HashMap<(char, u32), CharacterDef>,
font: Font<'f>,
}
impl<'f> BufferGlyphs<'f> {
pub fn from_bytes(bytes: &'f [u8]) -> Result<BufferGlyphs<'f>, Error> {
Ok(BufferGlyphs {
characters: HashMap::new(),
font: Font::from_bytes(bytes)?,
})
}
pub fn from_font(font: Font<'f>) -> BufferGlyphs<'f> {
BufferGlyphs {
characters: HashMap::new(),
font,
}
}
}
impl<'f> CharacterCache for BufferGlyphs<'f> {
type Texture = RenderBuffer;
type Error = Box<dyn error::Error>;
fn character(
&mut self,
font_size: FontSize,
ch: char,
) -> Result<Character<'_, Self::Texture>, Self::Error> {
let font = &self.font;
Ok(self
.characters
.entry((ch, font_size))
.or_insert_with(|| {
let scale = Scale::uniform(font_size as f32);
let glyph = font.glyph(ch).scaled(scale);
let glyph = if glyph.id() == GlyphId(0) && glyph.shape().is_none() {
font.glyph('\u{FFFD}').scaled(scale)
} else {
glyph
};
let h_metrics = glyph.h_metrics();
let bounding_box = glyph.exact_bounding_box().unwrap_or(Rect {
min: point(0.0, 0.0),
max: point(0.0, 0.0),
});
let glyph = glyph.positioned(point(0.0, 0.0));
let pixel_bounding_box = glyph.pixel_bounding_box().unwrap_or(Rect {
min: point(0, 0),
max: point(0, 0),
});
let pixel_bb_width = pixel_bounding_box.width() + 2;
let pixel_bb_height = pixel_bounding_box.height() + 2;
let mut texture = RenderBuffer::new(pixel_bb_width as u32, pixel_bb_height as u32);
glyph.draw(|x, y, v| {
texture.set_pixel(x, y, [1.0, 1.0, 1.0, v]);
});
CharacterDef {
offset: [
Scalar::from(bounding_box.min.x) - 1.0,
Scalar::from(-pixel_bounding_box.min.y) + 1.0,
],
size: [Scalar::from(h_metrics.advance_width), Scalar::from(0)],
texture,
}
})
.as_character())
}
}