Skip to main content

endbasic_std/gfx/lcd/fonts/
mod.rs

1// EndBASIC
2// Copyright 2025 Julio Merino
3//
4// Licensed under the Apache License, Version 2.0 (the "License"); you may not
5// use this file except in compliance with the License.  You may obtain a copy
6// of the License at:
7//
8//     http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
13// License for the specific language governing permissions and limitations
14// under the License.
15
16//! Support for bitmap fonts directly rendered onto an LCD.
17
18use crate::gfx::lcd::LcdSize;
19use std::collections::HashMap;
20
21mod font_5x8;
22pub(crate) use font_5x8::FONT_5X8;
23
24mod font_16x16;
25pub(crate) use font_16x16::FONT_16X16;
26
27/// Representation of a font.
28pub struct Font {
29    /// The name of the font.
30    pub name: &'static str,
31
32    /// The size of a single glyph, in pixels.
33    pub glyph_size: LcdSize,
34
35    /// The number of bytes in every glyph row.
36    pub stride: usize,
37
38    /// The bitmap data for the font.
39    pub data: &'static [u8],
40}
41
42impl Font {
43    /// Returns the raw font data for `ch`.
44    ///
45    /// Each entry in the array corresponds to a row of pixels and is a bitmask indicating which
46    /// pixels to turn on.
47    pub(crate) fn glyph(&self, mut ch: char) -> &'static [u8] {
48        if !(' '..='~').contains(&ch) {
49            // TODO(jmmv): Would be nicer to draw an empty box, much like how unknown Unicode
50            // characters are typically displayed.
51            ch = '?';
52        }
53        let height = self.glyph_size.height * self.stride;
54        let offset = ((ch as usize) - (' ' as usize)) * height;
55        debug_assert!(offset < (self.data.len() + height));
56        &self.data[offset..offset + height]
57    }
58}
59
60/// Registry of all available fonts.
61pub type Fonts = HashMap<&'static str, &'static Font>;
62
63/// Obtains a mapping of all available fonts.
64pub fn all_fonts() -> Fonts {
65    let mut fonts = Fonts::default();
66    fonts.insert(FONT_5X8.name, &FONT_5X8);
67    fonts.insert(FONT_16X16.name, &FONT_16X16);
68    fonts
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn test_font_glyph_printable() {
77        let font = &FONT_5X8;
78
79        let offset = (usize::from(b'a') - usize::from(b' ')) * 8;
80        let expected = &font.data[offset..offset + 8];
81
82        let data = font.glyph('a');
83        assert_eq!(expected, data);
84    }
85
86    #[test]
87    fn test_font_glyph_non_printable() {
88        let font = &FONT_5X8;
89
90        let offset = (usize::from(b'?') - usize::from(b' ')) * 8;
91        let expected = &font.data[offset..offset + 8];
92
93        let data = font.glyph(char::from(30));
94        assert_eq!(expected, data);
95    }
96}