fix(editor): replace placeholder font with real 8x12 ASCII bitmap glyphs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -8,10 +8,205 @@ pub struct FontAtlas {
|
||||
pub pixels: Vec<u8>, // R8 grayscale
|
||||
}
|
||||
|
||||
/// Classic 8x12 PC BIOS bitmap font data for ASCII 32-126 (95 characters).
|
||||
/// Each character is 12 bytes (one byte per row, MSB = leftmost pixel).
|
||||
#[rustfmt::skip]
|
||||
const FONT_DATA: [u8; 95 * 12] = [
|
||||
// 32: Space
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 33: !
|
||||
0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00,
|
||||
// 34: "
|
||||
0x00, 0x6C, 0x6C, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 35: #
|
||||
0x00, 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 36: $
|
||||
0x00, 0x18, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x18, 0x00, 0x00, 0x00, 0x00,
|
||||
// 37: %
|
||||
0x00, 0x00, 0x62, 0x64, 0x08, 0x10, 0x26, 0x46, 0x00, 0x00, 0x00, 0x00,
|
||||
// 38: &
|
||||
0x00, 0x30, 0x48, 0x48, 0x30, 0x4A, 0x44, 0x3A, 0x00, 0x00, 0x00, 0x00,
|
||||
// 39: '
|
||||
0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 40: (
|
||||
0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 41: )
|
||||
0x00, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
|
||||
// 42: *
|
||||
0x00, 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 43: +
|
||||
0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 44: ,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
|
||||
// 45: -
|
||||
0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 46: .
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
|
||||
// 47: /
|
||||
0x00, 0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00, 0x00, 0x00, 0x00,
|
||||
// 48: 0
|
||||
0x00, 0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 49: 1
|
||||
0x00, 0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00,
|
||||
// 50: 2
|
||||
0x00, 0x3C, 0x66, 0x06, 0x0C, 0x18, 0x30, 0x7E, 0x00, 0x00, 0x00, 0x00,
|
||||
// 51: 3
|
||||
0x00, 0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 52: 4
|
||||
0x00, 0x0C, 0x1C, 0x2C, 0x4C, 0x7E, 0x0C, 0x0C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 53: 5
|
||||
0x00, 0x7E, 0x60, 0x7C, 0x06, 0x06, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 54: 6
|
||||
0x00, 0x1C, 0x30, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 55: 7
|
||||
0x00, 0x7E, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
|
||||
// 56: 8
|
||||
0x00, 0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 57: 9
|
||||
0x00, 0x3C, 0x66, 0x66, 0x3E, 0x06, 0x0C, 0x38, 0x00, 0x00, 0x00, 0x00,
|
||||
// 58: :
|
||||
0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 59: ;
|
||||
0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
|
||||
// 60: <
|
||||
0x00, 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00,
|
||||
// 61: =
|
||||
0x00, 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 62: >
|
||||
0x00, 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
|
||||
// 63: ?
|
||||
0x00, 0x3C, 0x66, 0x06, 0x0C, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00,
|
||||
// 64: @
|
||||
0x00, 0x3C, 0x66, 0x6E, 0x6A, 0x6E, 0x60, 0x3E, 0x00, 0x00, 0x00, 0x00,
|
||||
// 65: A
|
||||
0x00, 0x18, 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
|
||||
// 66: B
|
||||
0x00, 0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 67: C
|
||||
0x00, 0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 68: D
|
||||
0x00, 0x78, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0x78, 0x00, 0x00, 0x00, 0x00,
|
||||
// 69: E
|
||||
0x00, 0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00, 0x00, 0x00, 0x00,
|
||||
// 70: F
|
||||
0x00, 0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00,
|
||||
// 71: G
|
||||
0x00, 0x3C, 0x66, 0x60, 0x6E, 0x66, 0x66, 0x3E, 0x00, 0x00, 0x00, 0x00,
|
||||
// 72: H
|
||||
0x00, 0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
|
||||
// 73: I
|
||||
0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00,
|
||||
// 74: J
|
||||
0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 75: K
|
||||
0x00, 0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00, 0x00, 0x00, 0x00,
|
||||
// 76: L
|
||||
0x00, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00, 0x00, 0x00, 0x00,
|
||||
// 77: M
|
||||
0x00, 0xC6, 0xEE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
|
||||
// 78: N
|
||||
0x00, 0x66, 0x76, 0x7E, 0x7E, 0x6E, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
|
||||
// 79: O
|
||||
0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 80: P
|
||||
0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00,
|
||||
// 81: Q
|
||||
0x00, 0x3C, 0x66, 0x66, 0x66, 0x6A, 0x6C, 0x36, 0x00, 0x00, 0x00, 0x00,
|
||||
// 82: R
|
||||
0x00, 0x7C, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
|
||||
// 83: S
|
||||
0x00, 0x3C, 0x66, 0x60, 0x3C, 0x06, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 84: T
|
||||
0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
|
||||
// 85: U
|
||||
0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 86: V
|
||||
0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00,
|
||||
// 87: W
|
||||
0x00, 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00, 0x00, 0x00, 0x00,
|
||||
// 88: X
|
||||
0x00, 0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
|
||||
// 89: Y
|
||||
0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
|
||||
// 90: Z
|
||||
0x00, 0x7E, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x7E, 0x00, 0x00, 0x00, 0x00,
|
||||
// 91: [
|
||||
0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 92: backslash
|
||||
0x00, 0x40, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
|
||||
// 93: ]
|
||||
0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 94: ^
|
||||
0x00, 0x18, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 95: _
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
|
||||
// 96: `
|
||||
0x00, 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 97: a
|
||||
0x00, 0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00, 0x00, 0x00, 0x00,
|
||||
// 98: b
|
||||
0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 99: c
|
||||
0x00, 0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 100: d
|
||||
0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x00, 0x00, 0x00, 0x00,
|
||||
// 101: e
|
||||
0x00, 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 102: f
|
||||
0x00, 0x1C, 0x30, 0x30, 0x7C, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
|
||||
// 103: g
|
||||
0x00, 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x3C, 0x00, 0x00, 0x00,
|
||||
// 104: h
|
||||
0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
|
||||
// 105: i
|
||||
0x00, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 106: j
|
||||
0x00, 0x0C, 0x00, 0x1C, 0x0C, 0x0C, 0x0C, 0x0C, 0x78, 0x00, 0x00, 0x00,
|
||||
// 107: k
|
||||
0x00, 0x60, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00, 0x00, 0x00, 0x00,
|
||||
// 108: l
|
||||
0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 109: m
|
||||
0x00, 0x00, 0x00, 0xEC, 0xFE, 0xD6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
|
||||
// 110: n
|
||||
0x00, 0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
|
||||
// 111: o
|
||||
0x00, 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 112: p
|
||||
0x00, 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00, 0x00, 0x00,
|
||||
// 113: q
|
||||
0x00, 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x00, 0x00, 0x00,
|
||||
// 114: r
|
||||
0x00, 0x00, 0x00, 0x7C, 0x66, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00,
|
||||
// 115: s
|
||||
0x00, 0x00, 0x00, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 116: t
|
||||
0x00, 0x30, 0x30, 0x7C, 0x30, 0x30, 0x30, 0x1C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 117: u
|
||||
0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00, 0x00, 0x00, 0x00,
|
||||
// 118: v
|
||||
0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00,
|
||||
// 119: w
|
||||
0x00, 0x00, 0x00, 0xC6, 0xC6, 0xD6, 0xFE, 0x6C, 0x00, 0x00, 0x00, 0x00,
|
||||
// 120: x
|
||||
0x00, 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00,
|
||||
// 121: y
|
||||
0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x3C, 0x00, 0x00, 0x00,
|
||||
// 122: z
|
||||
0x00, 0x00, 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x7E, 0x00, 0x00, 0x00, 0x00,
|
||||
// 123: {
|
||||
0x00, 0x0E, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0E, 0x00, 0x00, 0x00, 0x00,
|
||||
// 124: |
|
||||
0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
|
||||
// 125: }
|
||||
0x00, 0x70, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
|
||||
// 126: ~
|
||||
0x00, 0x32, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
impl FontAtlas {
|
||||
/// Generate a minimal font atlas.
|
||||
/// Generate a bitmap font atlas with real 8x12 PC BIOS-style glyphs.
|
||||
/// Each glyph is 8x12 pixels. Atlas is 16 cols x 6 rows = 128x72.
|
||||
/// Space (32) = all zeros. Other chars get a simple recognizable pattern.
|
||||
pub fn generate() -> Self {
|
||||
let glyph_width: u32 = 8;
|
||||
let glyph_height: u32 = 12;
|
||||
@@ -22,41 +217,20 @@ impl FontAtlas {
|
||||
|
||||
let mut pixels = vec![0u8; (width * height) as usize];
|
||||
|
||||
// ASCII 32 (space) through 126 (~) = 95 characters
|
||||
// Unpack 1-bit-per-pixel FONT_DATA into R8 pixel atlas
|
||||
for code in 32u8..=126u8 {
|
||||
let index = (code - 32) as u32;
|
||||
let col = index % cols;
|
||||
let row = index / cols;
|
||||
let base_x = col * glyph_width;
|
||||
let base_y = row * glyph_height;
|
||||
let data_offset = (index as usize) * 12;
|
||||
|
||||
if code == 32 {
|
||||
// Space: all zeros (already zero)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Generate a recognizable pattern based on char code.
|
||||
// Draw a border frame + inner pattern derived from code value.
|
||||
for py in 0..glyph_height {
|
||||
for px in 0..glyph_width {
|
||||
let pixel_idx = ((base_y + py) * width + (base_x + px)) as usize;
|
||||
|
||||
let on_border = px == 0 || px == glyph_width - 1
|
||||
|| py == 0 || py == glyph_height - 1;
|
||||
|
||||
// Inner pattern: use bits of char code to create variation
|
||||
let inner_bit = ((code as u32).wrapping_mul(px + 1).wrapping_mul(py + 1)) & 0x3;
|
||||
let on_inner = inner_bit == 0 && px > 1 && px < glyph_width - 2
|
||||
&& py > 2 && py < glyph_height - 2;
|
||||
|
||||
// Horizontal bar in middle for letter-like appearance
|
||||
let mid_y = glyph_height / 2;
|
||||
let on_midbar = py == mid_y && px > 1 && px < glyph_width - 2;
|
||||
|
||||
// Vertical stem on left side
|
||||
let on_stem = px == 2 && py > 1 && py < glyph_height - 2;
|
||||
|
||||
if on_border || on_inner || on_midbar || on_stem {
|
||||
for py in 0..12u32 {
|
||||
let row_byte = FONT_DATA[data_offset + py as usize];
|
||||
for px in 0..8u32 {
|
||||
if (row_byte >> (7 - px)) & 1 != 0 {
|
||||
let pixel_idx = ((base_y + py) * width + (base_x + px)) as usize;
|
||||
pixels[pixel_idx] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user