1
0
Fork 0
mirror of https://github.com/imjasonh/nescript synced 2026-07-15 20:58:20 +00:00
nescript/src/assets/palette.rs
Claude 058f7a87b6
M3: Asset pipeline, sprite/palette/background declarations, debug symbols
Parser extensions:
- sprite declarations with chr: @chr("file.png"), @binary("file.bin"), or inline [hex]
- palette declarations with colors: [0x0F, 0x00, 0x10, 0x20]
- background declarations with chr: asset source
- @chr/@binary asset source parsing
- load_background and set_palette statements
- --debug CLI flag (plumbed through, not yet wired to codegen)

Asset pipeline (new module):
- PNG → CHR tile conversion using image crate (8x8 tiles, 2-bitplane encoding)
- NES color palette table (all 64 standard NES colors as RGB)
- Nearest-color matching (Euclidean distance in RGB space)

Debug module (new):
- Source map (ROM address → source Span mapping)
- Debug symbols with variable address table
- Mesen-compatible .mlb label export
- .sym symbol table export

192 tests total (13 new: 5 parser + 3 asset + 5 debug)

https://claude.ai/code/session_01W6eQFStA66EuMKHUFo2rx3
2026-04-12 00:09:47 +00:00

88 lines
2.5 KiB
Rust

/// NES color palette -- 64 colors as (R, G, B) tuples.
pub const NES_COLORS: [(u8, u8, u8); 64] = [
// Row 0
(84, 84, 84), // 0x00
(0, 30, 116), // 0x01
(8, 16, 144), // 0x02
(48, 0, 136), // 0x03
(68, 0, 100), // 0x04
(92, 0, 48), // 0x05
(84, 4, 0), // 0x06
(60, 24, 0), // 0x07
(32, 42, 0), // 0x08
(8, 58, 0), // 0x09
(0, 64, 0), // 0x0A
(0, 60, 0), // 0x0B
(0, 50, 60), // 0x0C
(0, 0, 0), // 0x0D
(0, 0, 0), // 0x0E
(0, 0, 0), // 0x0F
// Row 1
(152, 150, 152), // 0x10
(8, 76, 196), // 0x11
(48, 50, 236), // 0x12
(92, 30, 228), // 0x13
(136, 20, 176), // 0x14
(160, 20, 100), // 0x15
(152, 34, 32), // 0x16
(120, 60, 0), // 0x17
(84, 90, 0), // 0x18
(40, 114, 0), // 0x19
(8, 124, 0), // 0x1A
(0, 118, 40), // 0x1B
(0, 102, 120), // 0x1C
(0, 0, 0), // 0x1D
(0, 0, 0), // 0x1E
(0, 0, 0), // 0x1F
// Row 2
(236, 238, 236), // 0x20
(76, 154, 236), // 0x21
(120, 124, 236), // 0x22
(176, 98, 236), // 0x23
(228, 84, 236), // 0x24
(236, 88, 180), // 0x25
(236, 106, 100), // 0x26
(212, 136, 32), // 0x27
(160, 170, 0), // 0x28
(116, 196, 0), // 0x29
(76, 208, 32), // 0x2A
(56, 204, 108), // 0x2B
(56, 180, 204), // 0x2C
(60, 60, 60), // 0x2D
(0, 0, 0), // 0x2E
(0, 0, 0), // 0x2F
// Row 3
(236, 238, 236), // 0x30
(168, 204, 236), // 0x31
(188, 188, 236), // 0x32
(212, 178, 236), // 0x33
(236, 174, 236), // 0x34
(236, 174, 212), // 0x35
(236, 180, 176), // 0x36
(228, 196, 144), // 0x37
(204, 210, 120), // 0x38
(180, 222, 120), // 0x39
(168, 226, 144), // 0x3A
(152, 226, 180), // 0x3B
(160, 214, 228), // 0x3C
(160, 162, 160), // 0x3D
(0, 0, 0), // 0x3E
(0, 0, 0), // 0x3F
];
/// Find the nearest NES color index for an RGB value.
pub fn nearest_nes_color(r: u8, g: u8, b: u8) -> u8 {
let mut best_idx = 0u8;
let mut best_dist = u32::MAX;
for (i, &(nr, ng, nb)) in NES_COLORS.iter().enumerate() {
let dr = i32::from(r) - i32::from(nr);
let dg = i32::from(g) - i32::from(ng);
let db = i32::from(b) - i32::from(nb);
let dist = (dr * dr + dg * dg + db * db).unsigned_abs();
if dist < best_dist {
best_dist = dist;
best_idx = i as u8;
}
}
best_idx
}