glyph picker
This commit is contained in:
@@ -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 (0–255) to get the displayable character.
|
||||
/// The low control range (0x00–0x1F) 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] = [
|
||||
// 0x00–0x0F
|
||||
' ', '☺', '☻', '♥', '♦', '♣', '♠', '•', '◘', '○', '◙', '♂', '♀', '♪', '♫', '☼',
|
||||
// 0x10–0x1F
|
||||
'►', '◄', '↕', '‼', '¶', '§', '▬', '↨', '↑', '↓', '→', '←', '∟', '↔', '▲', '▼',
|
||||
// 0x20–0x2F (ASCII space onward)
|
||||
' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
|
||||
// 0x30–0x3F
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
|
||||
// 0x40–0x4F
|
||||
'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
|
||||
// 0x50–0x5F
|
||||
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
|
||||
// 0x60–0x6F
|
||||
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||
// 0x70–0x7F
|
||||
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '⌂',
|
||||
// 0x80–0x8F
|
||||
'Ç', 'ü', 'é', 'â', 'ä', 'à', 'å', 'ç', 'ê', 'ë', 'è', 'ï', 'î', 'ì', 'Ä', 'Å',
|
||||
// 0x90–0x9F
|
||||
'É', 'æ', 'Æ', 'ô', 'ö', 'ò', 'û', 'ù', 'ÿ', 'Ö', 'Ü', '¢', '£', '¥', '₧', 'ƒ',
|
||||
// 0xA0–0xAF
|
||||
'á', 'í', 'ó', 'ú', 'ñ', 'Ñ', 'ª', 'º', '¿', '⌐', '¬', '½', '¼', '¡', '«', '»',
|
||||
// 0xB0–0xBF (shading + box drawing)
|
||||
'░', '▒', '▓', '│', '┤', '╡', '╢', '╖', '╕', '╣', '║', '╗', '╝', '╜', '╛', '┐',
|
||||
// 0xC0–0xCF
|
||||
'└', '┴', '┬', '├', '─', '┼', '╞', '╟', '╚', '╔', '╩', '╦', '╠', '═', '╬', '╧',
|
||||
// 0xD0–0xDF
|
||||
'╨', '╤', '╥', '╙', '╘', '╒', '╓', '╫', '╪', '┘', '┌', '█', '▄', '▌', '▐', '▀',
|
||||
// 0xE0–0xEF
|
||||
'α', 'ß', 'Γ', 'π', 'Σ', 'σ', 'µ', 'τ', 'Φ', 'Θ', 'Ω', 'δ', '∞', 'φ', 'ε', '∩',
|
||||
// 0xF0–0xFF
|
||||
'≡', '±', '≥', '≤', '⌠', '⌡', '÷', '≈', '°', '∙', '·', '√', 'ⁿ', '²', '■', '\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,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.
|
||||
|
||||
Reference in New Issue
Block a user