glyph picker

This commit is contained in:
2026-06-20 15:27:09 -05:00
parent e74d015d1b
commit 05142e5712
12 changed files with 638 additions and 26 deletions
+91
View File
@@ -0,0 +1,91 @@
//! CP437 → Unicode mapping for interpreting glyph tile indices as characters.
//!
//! kiln stores each cell's visual as a `tile: u32` index into a bitmap font.
//! The default kiln font is IBM CP437, where the tile index equals the CP437
//! code point. A terminal can't draw the bitmap font, so a front-end reinterprets
//! the tile index as a character via this table and prints that character with
//! the cell's foreground/background colors. This lives in kiln-core (not a
//! front-end) because it is the *meaning* of a tile index under the default font,
//! shared by every renderer and by the editor's glyph picker.
/// CP437 code point → Unicode scalar value.
///
/// Index this array by a byte value (0255) to get the displayable character.
/// The low control range (0x000x1F) maps to CP437's graphic glyphs (hearts,
/// arrows, musical notes, etc.) rather than ASCII control codes, matching how
/// these byte values render in a DOS/ZZT-style font. Code 0x00 maps to a blank
/// space since a literal NUL is not displayable.
const CP437: [char; 256] = [
// 0x000x0F
' ', '☺', '☻', '♥', '♦', '♣', '♠', '•', '◘', '○', '◙', '♂', '♀', '♪', '♫', '☼',
// 0x100x1F
'►', '◄', '↕', '‼', '¶', '§', '▬', '↨', '↑', '↓', '→', '←', '∟', '↔', '▲', '▼',
// 0x200x2F (ASCII space onward)
' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
// 0x300x3F
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
// 0x400x4F
'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
// 0x500x5F
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
// 0x600x6F
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
// 0x700x7F
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '⌂',
// 0x800x8F
'Ç', 'ü', 'é', 'â', 'ä', 'à', 'å', 'ç', 'ê', 'ë', 'è', 'ï', 'î', 'ì', 'Ä', 'Å',
// 0x900x9F
'É', 'æ', 'Æ', 'ô', 'ö', 'ò', 'û', 'ù', 'ÿ', 'Ö', 'Ü', '¢', '£', '¥', '₧', 'ƒ',
// 0xA00xAF
'á', 'í', 'ó', 'ú', 'ñ', 'Ñ', 'ª', 'º', '¿', '⌐', '¬', '½', '¼', '¡', '«', '»',
// 0xB00xBF (shading + box drawing)
'░', '▒', '▓', '│', '┤', '╡', '╢', '╖', '╕', '╣', '║', '╗', '╝', '╜', '╛', '┐',
// 0xC00xCF
'└', '┴', '┬', '├', '─', '┼', '╞', '╟', '╚', '╔', '╩', '╦', '╠', '═', '╬', '╧',
// 0xD00xDF
'╨', '╤', '╥', '╙', '╘', '╒', '╓', '╫', '╪', '┘', '┌', '█', '▄', '▌', '▐', '▀',
// 0xE00xEF
'α', 'ß', 'Γ', 'π', 'Σ', 'σ', 'µ', 'τ', 'Φ', 'Θ', 'Ω', 'δ', '∞', 'φ', 'ε', '∩',
// 0xF00xFF
'≡', '±', '≥', '≤', '⌠', '⌡', '÷', '≈', '°', '∙', '·', '√', 'ⁿ', '²', '■', '\u{00A0}',
];
/// Converts a glyph tile index into a displayable character.
///
/// Tile indices in `0..256` use the [`CP437`] table. Larger indices (which a
/// non-default font could in principle reference) fall back to interpreting the
/// index as a raw Unicode scalar, then to a blank space if that is not a valid
/// or printable character.
pub fn tile_to_char(tile: u32) -> char {
if tile < 256 {
CP437[tile as usize]
} else {
char::from_u32(tile).unwrap_or(' ')
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ascii_passthrough() {
// The printable ASCII range must map to itself.
assert_eq!(tile_to_char('@' as u32), '@'); // player tile 64
assert_eq!(tile_to_char('#' as u32), '#'); // wall tile 35
assert_eq!(tile_to_char(' ' as u32), ' '); // empty tile 32
}
#[test]
fn box_drawing_and_blocks() {
assert_eq!(tile_to_char(0xB0), '░');
assert_eq!(tile_to_char(0xDB), '█');
assert_eq!(tile_to_char(0xC4), '─');
}
#[test]
fn out_of_range_falls_back_to_space() {
// A surrogate code point is not a valid char → blank.
assert_eq!(tile_to_char(0xD800), ' ');
}
}
+2
View File
@@ -2,6 +2,8 @@ mod action;
mod archetype;
mod board;
mod builtin_scripts;
/// CP437 tile-index → character mapping ([`cp437::tile_to_char`]) for the default font.
pub mod cp437;
/// Procedural floor generators ([`floor::FloorGenerator`]).
pub mod floor;
/// Core game types: [`board::Board`], [`glyph::Glyph`], [`archetype::Archetype`], etc.