// font_aa_generated.h - Anti-aliased font for LED Matrix // Generated from TrueType font with 4-level anti-aliasing #pragma once #include struct AAChar { uint8_t width; uint8_t data[16]; // 8x8 pixels, 2 bits each = 128 bits = 16 bytes }; // Anti-aliased font data for ASCII 32-126 const AAChar aa_font[] = { {8, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 32 ' ' {5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 33 '!' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 34 '\"' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x90, 0x01, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 35 '#' {5, {0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x80, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 36 '$' {6, {0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0xA0, 0x01, 0x40, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 37 '%' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x80, 0x01, 0x90, 0x02, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 38 '&' {4, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 39 '\'' {4, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 40 '(' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x40, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 41 ')' {4, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 42 '*' {5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 43 '+' {5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 44 ',' {4, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 45 '-' {8, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 46 '.' {4, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 47 '/' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x50, 0x01, 0x50, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 48 '0' {5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 49 '1' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x40, 0x00, 0x50, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 50 '2' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x40, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 51 '3' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x90, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 52 '4' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x90, 0x01, 0x40, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 53 '5' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x90, 0x01, 0x90, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 54 '6' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 55 '7' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x80, 0x01, 0x50, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 56 '8' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x90, 0x01, 0x80, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 57 '9' {8, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 58 ':' {5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 59 ';' {5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 60 '<' {5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 61 '=' {5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 62 '>' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 63 '?' {6, {0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x50, 0x05, 0x50, 0x06, 0x90, 0x06, 0x00, 0x00, 0x00, 0x00}}, // 64 '@' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x80, 0x01, 0x90, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 65 'A' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x90, 0x02, 0x50, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 66 'B' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x50, 0x01, 0x50, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 67 'C' {6, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x50, 0x05, 0x50, 0x05, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 68 'D' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x90, 0x01, 0x50, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 69 'E' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x90, 0x01, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 70 'F' {6, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x50, 0x01, 0x50, 0x06, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 71 'G' {6, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x02, 0x50, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 72 'H' {5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 73 'I' {5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x40, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 74 'J' {5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x90, 0x01, 0x90, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 75 'K' {5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x50, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 76 'L' {5, {0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x60, 0x02, 0x90, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 77 'M' {6, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x90, 0x01, 0x50, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 78 'N' {6, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x50, 0x05, 0x50, 0x05, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 79 'O' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x50, 0x02, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 80 'P' {6, {0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x10, 0x04, 0x80, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 81 'Q' {6, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x90, 0x02, 0x50, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 82 'R' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 83 'S' {5, {0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0x40, 0x01, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 84 'T' {6, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x05, 0x50, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 85 'U' {5, {0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x50, 0x01, 0x40, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 86 'V' {6, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x50, 0x05, 0x50, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 87 'W' {5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x80, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 88 'X' {5, {0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x40, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 89 'Y' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x50, 0x00, 0x50, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 90 'Z' {4, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 91 '[' {4, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 92 '\\' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x01, 0x00, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 93 ']' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 94 '^' {6, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 95 '_' {4, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 96 '`' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x80, 0x01, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 97 'a' {5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0x50, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 98 'b' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 99 'c' {5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x02, 0x40, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 100 'd' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x90, 0x01, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 101 'e' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 102 'f' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x40, 0x01, 0x40, 0x02, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 103 'g' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x02, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 104 'h' {5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 105 'i' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x40, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 106 'j' {5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 107 'k' {5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 108 'l' {5, {0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0x50, 0x01, 0x50, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 109 'm' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 110 'n' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x50, 0x01, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 111 'o' {5, {0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0x50, 0x01, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 112 'p' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x40, 0x01, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 113 'q' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 114 'r' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x80, 0x01, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 115 's' {4, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x80, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 116 't' {5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 117 'u' {5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 118 'v' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x50, 0x02, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 119 'w' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 120 'x' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 121 'y' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 122 'z' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x00, 0x40, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 123 '{' {5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 124 '|' {5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 125 '}' {5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 126 '~' }; // Draw anti-aliased character at position void draw_aa_char(light::AddressableLight &it, char c, int x_pos, int y_pos, Color color, float alpha = 1.0f) { if (c < 32 || c > 126) return; const AAChar &char_data = aa_font[c - 32]; for (int y = 0; y < 8; y++) { for (int x = 0; x < 8; x++) { // Extract 2-bit brightness value int byte_idx = (y * 2) + (x / 4); int bit_shift = (x % 4) * 2; uint8_t brightness_level = (char_data.data[byte_idx] >> bit_shift) & 0x03; if (brightness_level > 0) { float brightness = (brightness_level / 3.0f) * alpha; int px = x_pos + x; int py = y_pos + y; if (px >= 0 && px < 32 && py >= 0 && py < 8) { int flipped_y = 7 - py; int led_index; if (flipped_y % 2 == 0) { led_index = flipped_y * 32 + px; } else { led_index = flipped_y * 32 + (31 - px); } if (led_index >= 0 && led_index < 256) { // Apply brightness with alpha blending Color existing = it[led_index].get(); it[led_index] = Color( existing.r + (color.r - existing.r) * brightness, existing.g + (color.g - existing.g) * brightness, existing.b + (color.b - existing.b) * brightness ); } } } } } } // Draw anti-aliased string at position void draw_aa_string(light::AddressableLight &it, const std::string &text, int x_pos, int y_pos, Color color, float alpha = 1.0f) { int current_x = x_pos; for (char c : text) { if (c >= 32 && c <= 126) { draw_aa_char(it, c, current_x, y_pos, color, alpha); current_x += aa_font[c - 32].width + 1; // Add 1 pixel spacing } } } // Get width of anti-aliased string in pixels int get_aa_text_width(const std::string &text) { int width = 0; for (size_t i = 0; i < text.length(); i++) { char c = text[i]; if (c >= 32 && c <= 126) { width += aa_font[c - 32].width; if (i < text.length() - 1) width += 1; // spacing } } return width; } // Draw with sub-pixel positioning for smooth scrolling void draw_aa_string_subpixel(light::AddressableLight &it, const std::string &text, float x_pos, float y_pos, Color color) { float current_x = x_pos; for (char c : text) { if (c >= 32 && c <= 126) { int x_int = (int)x_pos; float x_frac = x_pos - x_int; // Draw character at two positions with appropriate alpha if (x_frac > 0.01f) { draw_aa_char(it, c, x_int, (int)y_pos, color, 1.0f - x_frac); draw_aa_char(it, c, x_int + 1, (int)y_pos, color, x_frac); } else { draw_aa_char(it, c, x_int, (int)y_pos, color, 1.0f); } current_x += aa_font[c - 32].width + 1; } } }