Files
xenia-rs/crates/xenia-ui/src/font.rs
MechaCat02 e2b8860e10 Add xenia-ui crate; switch analysis store to DuckDB
Workspace gains a new xenia-ui member that owns the winit/wgpu
window, the Xenos display pipeline (xenos_pipeline + render +
texture_cache_host), HUD font/blit shaders, and the input-bridge
plumbing the app uses to surface guest framebuffers and overlays.

Workspace dependencies grow accordingly: rusqlite is replaced with
duckdb (analysis pipeline now writes DuckDB stores), and tracing /
metrics / pprof / winit / wgpu / gilrs / pollster / crossbeam /
bytemuck are added at workspace level so xenia-ui and xenia-app
share versions. Cargo.lock regenerated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 16:26:48 +02:00

232 lines
6.9 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Minimal 8×8 bitmap font for the HUD.
//!
//! Only printable ASCII (0x20..0x7E) is populated. Each glyph is 8 bytes, one
//! byte per row, MSB = leftmost pixel. This is a bespoke hand-drawn font just
//! wide enough for status-line text ("Swap: 0x1234 Pad: 0x0040 …"); no
//! international glyphs, no kerning, no anti-aliasing.
//!
//! The font is rendered by uploading the 8×(8·N) atlas as an R8 texture and
//! sampling one cell per character quad from the HUD shader.
pub const CELL_W: u32 = 8;
pub const CELL_H: u32 = 8;
pub const FIRST: u8 = 0x20;
pub const LAST: u8 = 0x7E;
pub const GLYPH_COUNT: u32 = (LAST as u32) - (FIRST as u32) + 1;
/// Build the atlas as a linear R8 buffer, `CELL_W × (CELL_H * GLYPH_COUNT)`,
/// one glyph per 8-row strip stacked top-to-bottom.
pub fn build_atlas() -> Vec<u8> {
let mut out = vec![0u8; (CELL_W * CELL_H * GLYPH_COUNT) as usize];
for ch in FIRST..=LAST {
let rows = GLYPHS[(ch - FIRST) as usize];
for (row, byte) in rows.iter().enumerate() {
for col in 0..8 {
let bit = (byte >> (7 - col)) & 1;
if bit != 0 {
let idx = ((ch - FIRST) as u32 * CELL_H + row as u32) * CELL_W + col as u32;
out[idx as usize] = 0xFF;
}
}
}
}
out
}
/// 95 glyphs (0x20..0x7E). Each entry is 8 bytes of rows.
/// Hand-crafted for the HUD lines we actually emit. Most punctuation is
/// covered; unsupported chars fall through to the space glyph.
#[rustfmt::skip]
pub const GLYPHS: [[u8; 8]; 95] = [
// 0x20 ' '
[0,0,0,0,0,0,0,0],
// '!'
[0x18,0x18,0x18,0x18,0x00,0x00,0x18,0x00],
// '"'
[0x36,0x36,0x00,0x00,0x00,0x00,0x00,0x00],
// '#'
[0x6C,0xFE,0x6C,0x6C,0x6C,0xFE,0x6C,0x00],
// '$'
[0x18,0x3E,0x60,0x3C,0x06,0x7C,0x18,0x00],
// '%'
[0x00,0xC6,0xCC,0x18,0x30,0x66,0xC6,0x00],
// '&'
[0x38,0x6C,0x38,0x76,0xDC,0xCC,0x76,0x00],
// '\''
[0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00],
// '('
[0x0C,0x18,0x30,0x30,0x30,0x18,0x0C,0x00],
// ')'
[0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x00],
// '*'
[0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00],
// '+'
[0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00],
// ','
[0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30],
// '-'
[0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00],
// '.'
[0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00],
// '/'
[0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00],
// '0'
[0x7C,0xC6,0xCE,0xD6,0xE6,0xC6,0x7C,0x00],
// '1'
[0x18,0x38,0x18,0x18,0x18,0x18,0x7E,0x00],
// '2'
[0x7C,0xC6,0x06,0x1C,0x30,0x66,0xFE,0x00],
// '3'
[0x7C,0xC6,0x06,0x3C,0x06,0xC6,0x7C,0x00],
// '4'
[0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x1E,0x00],
// '5'
[0xFE,0xC0,0xC0,0xFC,0x06,0xC6,0x7C,0x00],
// '6'
[0x38,0x60,0xC0,0xFC,0xC6,0xC6,0x7C,0x00],
// '7'
[0xFE,0xC6,0x0C,0x18,0x30,0x30,0x30,0x00],
// '8'
[0x7C,0xC6,0xC6,0x7C,0xC6,0xC6,0x7C,0x00],
// '9'
[0x7C,0xC6,0xC6,0x7E,0x06,0x0C,0x78,0x00],
// ':'
[0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00],
// ';'
[0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x30],
// '<'
[0x06,0x0C,0x18,0x30,0x18,0x0C,0x06,0x00],
// '='
[0x00,0x00,0x7E,0x00,0x7E,0x00,0x00,0x00],
// '>'
[0x60,0x30,0x18,0x0C,0x18,0x30,0x60,0x00],
// '?'
[0x7C,0xC6,0x0C,0x18,0x18,0x00,0x18,0x00],
// '@'
[0x7C,0xC6,0xDE,0xDE,0xDE,0xC0,0x78,0x00],
// 'A'
[0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0x00],
// 'B'
[0xFC,0x66,0x66,0x7C,0x66,0x66,0xFC,0x00],
// 'C'
[0x3C,0x66,0xC0,0xC0,0xC0,0x66,0x3C,0x00],
// 'D'
[0xF8,0x6C,0x66,0x66,0x66,0x6C,0xF8,0x00],
// 'E'
[0xFE,0x62,0x68,0x78,0x68,0x62,0xFE,0x00],
// 'F'
[0xFE,0x62,0x68,0x78,0x68,0x60,0xF0,0x00],
// 'G'
[0x3C,0x66,0xC0,0xC0,0xCE,0x66,0x3E,0x00],
// 'H'
[0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00],
// 'I'
[0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00],
// 'J'
[0x1E,0x0C,0x0C,0x0C,0xCC,0xCC,0x78,0x00],
// 'K'
[0xE6,0x66,0x6C,0x78,0x6C,0x66,0xE6,0x00],
// 'L'
[0xF0,0x60,0x60,0x60,0x62,0x66,0xFE,0x00],
// 'M'
[0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0x00],
// 'N'
[0xC6,0xE6,0xF6,0xDE,0xCE,0xC6,0xC6,0x00],
// 'O'
[0x38,0x6C,0xC6,0xC6,0xC6,0x6C,0x38,0x00],
// 'P'
[0xFC,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00],
// 'Q'
[0x7C,0xC6,0xC6,0xC6,0xCE,0x7C,0x0E,0x00],
// 'R'
[0xFC,0x66,0x66,0x7C,0x6C,0x66,0xE6,0x00],
// 'S'
[0x7C,0xC6,0xE0,0x78,0x0E,0xC6,0x7C,0x00],
// 'T'
[0x7E,0x7E,0x5A,0x18,0x18,0x18,0x3C,0x00],
// 'U'
[0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00],
// 'V'
[0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x00],
// 'W'
[0xC6,0xC6,0xC6,0xD6,0xFE,0xEE,0xC6,0x00],
// 'X'
[0xC6,0xC6,0x6C,0x38,0x6C,0xC6,0xC6,0x00],
// 'Y'
[0x66,0x66,0x66,0x3C,0x18,0x18,0x3C,0x00],
// 'Z'
[0xFE,0xC6,0x8C,0x18,0x32,0x66,0xFE,0x00],
// '['
[0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00],
// '\\'
[0xC0,0x60,0x30,0x18,0x0C,0x06,0x02,0x00],
// ']'
[0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00],
// '^'
[0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00],
// '_'
[0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF],
// '`'
[0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00],
// 'a'
[0x00,0x00,0x78,0x0C,0x7C,0xCC,0x76,0x00],
// 'b'
[0xE0,0x60,0x7C,0x66,0x66,0x66,0xDC,0x00],
// 'c'
[0x00,0x00,0x7C,0xC6,0xC0,0xC6,0x7C,0x00],
// 'd'
[0x1C,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00],
// 'e'
[0x00,0x00,0x7C,0xC6,0xFE,0xC0,0x7C,0x00],
// 'f'
[0x1C,0x36,0x30,0x78,0x30,0x30,0x78,0x00],
// 'g'
[0x00,0x00,0x76,0xCC,0xCC,0x7C,0x0C,0xF8],
// 'h'
[0xE0,0x60,0x6C,0x76,0x66,0x66,0xE6,0x00],
// 'i'
[0x18,0x00,0x38,0x18,0x18,0x18,0x3C,0x00],
// 'j'
[0x06,0x00,0x0E,0x06,0x06,0x66,0x66,0x3C],
// 'k'
[0xE0,0x60,0x66,0x6C,0x78,0x6C,0xE6,0x00],
// 'l'
[0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00],
// 'm'
[0x00,0x00,0xEC,0xFE,0xD6,0xD6,0xD6,0x00],
// 'n'
[0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x00],
// 'o'
[0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7C,0x00],
// 'p'
[0x00,0x00,0xDC,0x66,0x66,0x7C,0x60,0xF0],
// 'q'
[0x00,0x00,0x76,0xCC,0xCC,0x7C,0x0C,0x1E],
// 'r'
[0x00,0x00,0xDC,0x76,0x60,0x60,0xF0,0x00],
// 's'
[0x00,0x00,0x7E,0xC0,0x7C,0x06,0xFC,0x00],
// 't'
[0x30,0x30,0x7C,0x30,0x30,0x36,0x1C,0x00],
// 'u'
[0x00,0x00,0xCC,0xCC,0xCC,0xCC,0x76,0x00],
// 'v'
[0x00,0x00,0xC6,0xC6,0xC6,0x6C,0x38,0x00],
// 'w'
[0x00,0x00,0xC6,0xD6,0xD6,0xFE,0x6C,0x00],
// 'x'
[0x00,0x00,0xC6,0x6C,0x38,0x6C,0xC6,0x00],
// 'y'
[0x00,0x00,0xC6,0xC6,0xC6,0x7E,0x06,0xFC],
// 'z'
[0x00,0x00,0xFE,0x4C,0x18,0x32,0xFE,0x00],
// '{'
[0x0E,0x18,0x18,0x70,0x18,0x18,0x0E,0x00],
// '|'
[0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00],
// '}'
[0x70,0x18,0x18,0x0E,0x18,0x18,0x70,0x00],
// '~'
[0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00],
];