//! A small bitmap font for labels in headless pictures (the CPU rasterizer has no text //! otherwise): capitals, digits and a few marks on a 5 × 7 grid, drawn for FieldCraft. Lower case //! is drawn in capitals; anything else is a question mark. /// Glyph width and height in font pixels, and the advance between glyphs. pub const W: usize = 5; pub const H: usize = 7; pub const ADVANCE: usize = 6; /// The rows of a character, top first, the leftmost pixel in bit 4. pub fn rows(c: char) -> [u8; H] { match c.to_ascii_uppercase() { 'A' => [0x0e, 0x11, 0x11, 0x1f, 0x11, 0x11, 0x11], 'B' => [0x1e, 0x11, 0x11, 0x1e, 0x11, 0x11, 0x1e], 'C' => [0x0e, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0e], 'D' => [0x1e, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1e], 'E' => [0x1f, 0x10, 0x10, 0x1e, 0x10, 0x10, 0x1f], 'F' => [0x1f, 0x10, 0x10, 0x1e, 0x10, 0x10, 0x10], 'G' => [0x0e, 0x11, 0x10, 0x17, 0x11, 0x11, 0x0f], 'H' => [0x11, 0x11, 0x11, 0x1f, 0x11, 0x11, 0x11], 'I' => [0x0e, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0e], 'J' => [0x07, 0x02, 0x02, 0x02, 0x02, 0x12, 0x0c], 'K' => [0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11], 'L' => [0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1f], 'M' => [0x11, 0x1b, 0x15, 0x15, 0x11, 0x11, 0x11], 'N' => [0x11, 0x11, 0x19, 0x15, 0x13, 0x11, 0x11], 'O' => [0x0e, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0e], 'P' => [0x1e, 0x11, 0x11, 0x1e, 0x10, 0x10, 0x10], 'Q' => [0x0e, 0x11, 0x11, 0x11, 0x15, 0x12, 0x0d], 'R' => [0x1e, 0x11, 0x11, 0x1e, 0x14, 0x12, 0x11], 'S' => [0x0f, 0x10, 0x10, 0x0e, 0x01, 0x01, 0x1e], 'T' => [0x1f, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04], 'U' => [0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0e], 'V' => [0x11, 0x11, 0x11, 0x11, 0x11, 0x0a, 0x04], 'W' => [0x11, 0x11, 0x11, 0x15, 0x15, 0x15, 0x0a], 'X' => [0x11, 0x11, 0x0a, 0x04, 0x0a, 0x11, 0x11], 'Y' => [0x11, 0x11, 0x0a, 0x04, 0x04, 0x04, 0x04], 'Z' => [0x1f, 0x01, 0x02, 0x04, 0x08, 0x10, 0x1f], '0' => [0x0e, 0x11, 0x13, 0x15, 0x19, 0x11, 0x0e], '1' => [0x04, 0x0c, 0x04, 0x04, 0x04, 0x04, 0x0e], '2' => [0x0e, 0x11, 0x01, 0x02, 0x04, 0x08, 0x1f], '3' => [0x1f, 0x02, 0x04, 0x02, 0x01, 0x11, 0x0e], '4' => [0x02, 0x06, 0x0a, 0x12, 0x1f, 0x02, 0x02], '5' => [0x1f, 0x10, 0x1e, 0x01, 0x01, 0x11, 0x0e], '6' => [0x06, 0x08, 0x10, 0x1e, 0x11, 0x11, 0x0e], '7' => [0x1f, 0x01, 0x02, 0x04, 0x08, 0x08, 0x08], '8' => [0x0e, 0x11, 0x11, 0x0e, 0x11, 0x11, 0x0e], '9' => [0x0e, 0x11, 0x11, 0x0f, 0x01, 0x02, 0x0c], ' ' => [0; H], '-' => [0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00], '_' => [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f], '.' => [0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c], ',' => [0x00, 0x00, 0x00, 0x00, 0x0c, 0x04, 0x08], ':' => [0x00, 0x0c, 0x0c, 0x00, 0x0c, 0x0c, 0x00], '(' => [0x02, 0x04, 0x08, 0x08, 0x08, 0x04, 0x02], ')' => [0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08], '/' => [0x01, 0x01, 0x02, 0x04, 0x08, 0x10, 0x10], '+' => [0x00, 0x04, 0x04, 0x1f, 0x04, 0x04, 0x00], '#' => [0x0a, 0x0a, 0x1f, 0x0a, 0x1f, 0x0a, 0x0a], _ => [0x0e, 0x11, 0x01, 0x02, 0x04, 0x00, 0x04], } } /// Whether font pixel (`x`, `y`) of `c` is set. pub fn on(c: char, x: usize, y: usize) -> bool { x < W && rows(c).get(y).is_some_and(|r| r & (0x10 >> x) != 0) } #[cfg(test)] mod tests { use super::*; #[test] fn characters_are_distinct_and_lower_case_draws_capitals() { let set: Vec = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.,:()/+#".chars().collect(); for (i, a) in set.iter().enumerate() { assert!(rows(*a).iter().all(|r| *r < 0x20), "{a}"); for b in set.iter().skip(i + 1) { assert_ne!(rows(*a), rows(*b), "{a} and {b}"); } } assert_eq!(rows('r'), rows('R')); assert_eq!(rows('é'), rows('?')); assert!(on('L', 0, 6) && !on('L', 4, 0) && !on('L', 9, 0) && !on('L', 0, 9)); } }