1include!(concat!(env!("OUT_DIR"), "/generated_ascii_3x5.rs"));
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq)]
4pub struct PackedFont {
5 pub first_char: u8,
6 pub advance: u8,
7 pub line_height: u8,
8 pub glyphs: &'static [[u8; 5]],
9}
10
11pub static ASCII_3X5_FONT: PackedFont = PackedFont {
12 first_char: 32,
13 advance: 4,
14 line_height: 6,
15 glyphs: &ASCII_3X5_GLYPHS,
16};
17
18pub static ASCII_4X7_FONT: PackedFont = PackedFont {
19 first_char: 32,
20 advance: 5,
21 line_height: 8,
22 glyphs: &ASCII_4X7_GLYPHS,
23};
24
25#[derive(Clone, Copy, Debug, PartialEq)]
26pub enum FontId {
27 Tiny3x5,
28 Medium4x7,
29 Scaled6x10,
30 Vector(u8),
31 Custom(&'static PackedFont),
32 #[cfg(feature = "embedded-graphics")]
33 MonoFont(&'static embedded_graphics::mono_font::MonoFont<'static>),
34}
35
36impl Eq for FontId {}
37
38impl FontId {
39 pub const fn advance(self) -> u32 {
40 match self {
41 Self::Tiny3x5 => 4,
42 Self::Medium4x7 => 5,
43 Self::Scaled6x10 => 7,
44 Self::Vector(scale) => (8 * scale) as u32,
45 Self::Custom(font) => font.advance as u32,
46 #[cfg(feature = "embedded-graphics")]
47 Self::MonoFont(font) => font.character_size.width + font.character_spacing,
48 }
49 }
50
51 pub const fn line_height(self) -> u32 {
52 match self {
53 Self::Tiny3x5 => 6,
54 Self::Medium4x7 => 8,
55 Self::Scaled6x10 => 11,
56 Self::Vector(scale) => (12 * scale) as u32,
57 Self::Custom(font) => font.line_height as u32,
58 #[cfg(feature = "embedded-graphics")]
59 Self::MonoFont(font) => font.character_size.height,
60 }
61 }
62}
63
64pub const fn packed_font(font: FontId) -> &'static PackedFont {
65 match font {
66 FontId::Tiny3x5 => &ASCII_3X5_FONT,
67 FontId::Medium4x7 => &ASCII_4X7_FONT,
68 FontId::Scaled6x10 => &ASCII_3X5_FONT,
69 FontId::Vector(_) => &ASCII_3X5_FONT,
70 FontId::Custom(font) => font,
71 #[cfg(feature = "embedded-graphics")]
72 FontId::MonoFont(_) => &ASCII_3X5_FONT,
73 }
74}
75
76impl From<&'static PackedFont> for FontId {
77 fn from(font: &'static PackedFont) -> Self {
78 FontId::Custom(font)
79 }
80}
81
82#[cfg(feature = "embedded-graphics")]
83impl From<&'static embedded_graphics::mono_font::MonoFont<'static>> for FontId {
84 fn from(font: &'static embedded_graphics::mono_font::MonoFont<'static>) -> Self {
85 FontId::MonoFont(font)
86 }
87}
88
89pub fn get_vector_glyph(ch: char) -> &'static [(u8, u8)] {
90 match ch {
91 ' ' => &[],
92 '0' => &[
93 (2, 0),
94 (6, 0),
95 (6, 10),
96 (2, 10),
97 (2, 0),
98 (0xFF, 0xFF),
99 (2, 10),
100 (6, 0),
101 ],
102 '1' => &[
103 (4, 0),
104 (4, 10),
105 (0xFF, 0xFF),
106 (2, 2),
107 (4, 0),
108 (0xFF, 0xFF),
109 (2, 10),
110 (6, 10),
111 ],
112 '2' => &[(2, 0), (6, 0), (6, 5), (2, 5), (2, 10), (6, 10)],
113 '3' => &[
114 (2, 0),
115 (6, 0),
116 (6, 10),
117 (2, 10),
118 (0xFF, 0xFF),
119 (2, 5),
120 (6, 5),
121 ],
122 '4' => &[(2, 0), (2, 5), (6, 5), (0xFF, 0xFF), (6, 0), (6, 10)],
123 '5' => &[(6, 0), (2, 0), (2, 5), (6, 5), (6, 10), (2, 10)],
124 '6' => &[(6, 0), (2, 0), (2, 10), (6, 10), (6, 5), (2, 5)],
125 '7' => &[(2, 0), (6, 0), (2, 10)],
126 '8' => &[
127 (2, 0),
128 (6, 0),
129 (6, 10),
130 (2, 10),
131 (2, 0),
132 (0xFF, 0xFF),
133 (2, 5),
134 (6, 5),
135 ],
136 '9' => &[(6, 5), (2, 5), (2, 0), (6, 0), (6, 10), (2, 10)],
137 'A' | 'a' => &[(2, 10), (4, 0), (6, 10), (0xFF, 0xFF), (3, 5), (5, 5)],
138 'B' | 'b' => &[
139 (2, 0),
140 (5, 0),
141 (6, 2),
142 (6, 4),
143 (5, 5),
144 (2, 5),
145 (5, 5),
146 (6, 6),
147 (6, 8),
148 (5, 10),
149 (2, 10),
150 (2, 0),
151 ],
152 'C' | 'c' => &[(6, 0), (2, 0), (2, 10), (6, 10)],
153 'D' | 'd' => &[(2, 0), (5, 0), (6, 3), (6, 7), (5, 10), (2, 10), (2, 0)],
154 'E' | 'e' => &[
155 (6, 0),
156 (2, 0),
157 (2, 10),
158 (6, 10),
159 (0xFF, 0xFF),
160 (2, 5),
161 (5, 5),
162 ],
163 'F' | 'f' => &[(6, 0), (2, 0), (2, 10), (0xFF, 0xFF), (2, 5), (5, 5)],
164 'G' | 'g' => &[(6, 2), (6, 0), (2, 0), (2, 10), (6, 10), (6, 5), (4, 5)],
165 'H' | 'h' => &[
166 (2, 0),
167 (2, 10),
168 (0xFF, 0xFF),
169 (6, 0),
170 (6, 10),
171 (0xFF, 0xFF),
172 (2, 5),
173 (6, 5),
174 ],
175 'I' | 'i' => &[
176 (4, 0),
177 (4, 10),
178 (0xFF, 0xFF),
179 (2, 0),
180 (6, 0),
181 (0xFF, 0xFF),
182 (2, 10),
183 (6, 10),
184 ],
185 'J' | 'j' => &[(6, 0), (6, 8), (4, 10), (2, 8)],
186 'K' | 'k' => &[(2, 0), (2, 10), (0xFF, 0xFF), (6, 0), (2, 5), (6, 10)],
187 'L' | 'l' => &[(2, 0), (2, 10), (6, 10)],
188 'M' | 'm' => &[(2, 10), (2, 0), (4, 5), (6, 0), (6, 10)],
189 'N' | 'n' => &[(2, 10), (2, 0), (6, 10), (6, 0)],
190 'O' | 'o' => &[(2, 0), (6, 0), (6, 10), (2, 10), (2, 0)],
191 'P' | 'p' => &[(2, 10), (2, 0), (6, 0), (6, 5), (2, 5)],
192 'Q' | 'q' => &[
193 (2, 0),
194 (6, 0),
195 (6, 10),
196 (2, 10),
197 (2, 0),
198 (0xFF, 0xFF),
199 (4, 7),
200 (7, 10),
201 ],
202 'R' | 'r' => &[
203 (2, 10),
204 (2, 0),
205 (6, 0),
206 (6, 5),
207 (2, 5),
208 (0xFF, 0xFF),
209 (4, 5),
210 (6, 10),
211 ],
212 'S' | 's' => &[(6, 0), (2, 0), (2, 5), (6, 5), (6, 10), (2, 10)],
213 'T' | 't' => &[(2, 0), (6, 0), (0xFF, 0xFF), (4, 0), (4, 10)],
214 'U' | 'u' => &[(2, 0), (2, 10), (6, 10), (6, 0)],
215 'V' | 'v' => &[(2, 0), (4, 10), (6, 0)],
216 'W' | 'w' => &[(2, 0), (2, 10), (4, 5), (6, 10), (6, 0)],
217 'X' | 'x' => &[(2, 0), (6, 10), (0xFF, 0xFF), (6, 0), (2, 10)],
218 'Y' | 'y' => &[(2, 0), (4, 5), (6, 0), (0xFF, 0xFF), (4, 5), (4, 10)],
219 'Z' | 'z' => &[(2, 0), (6, 0), (2, 10), (6, 10)],
220 '-' => &[(2, 5), (6, 5)],
221 '+' => &[(2, 5), (6, 5), (0xFF, 0xFF), (4, 2), (4, 8)],
222 '.' => &[(4, 9), (4, 10)],
223 ':' => &[(4, 2), (4, 3), (0xFF, 0xFF), (4, 7), (4, 8)],
224 '/' => &[(2, 10), (6, 0)],
225 _ => &[(2, 0), (6, 0), (6, 10), (2, 10), (2, 0), (2, 0), (6, 10)],
226 }
227}
228
229pub fn glyph_rows(font: FontId, ch: char) -> [u8; 5] {
230 let packed = packed_font(font);
231 let code = ch as u32;
232 if code >= packed.first_char as u32 {
233 let idx = (code as usize).saturating_sub(packed.first_char as usize);
234 if idx < packed.glyphs.len() {
235 return packed.glyphs[idx];
236 }
237 }
238 let fallback = b'?'.saturating_sub(packed.first_char) as usize;
239 packed.glyphs.get(fallback).copied().unwrap_or([0; 5])
240}
241
242#[cfg(test)]
243mod tests {
244 use super::*;
245
246 static MY_CUSTOM_GLYPHS: [[u8; 5]; 2] = [
247 [0b111, 0b101, 0b111, 0b101, 0b101], [0b111, 0b111, 0b111, 0b111, 0b111],
249 ];
250
251 static MY_CUSTOM_FONT: PackedFont = PackedFont {
252 first_char: 32,
253 advance: 8,
254 line_height: 12,
255 glyphs: &MY_CUSTOM_GLYPHS,
256 };
257
258 #[test]
259 fn test_custom_font_id() {
260 let font_id = FontId::Custom(&MY_CUSTOM_FONT);
261 assert_eq!(font_id.advance(), 8);
262 assert_eq!(font_id.line_height(), 12);
263 assert_eq!(packed_font(font_id).first_char, 32);
264 assert_eq!(
265 glyph_rows(font_id, ' '),
266 [0b111, 0b101, 0b111, 0b101, 0b101]
267 );
268 }
269}