const DMG_GREY: [u8; 4] = [0xFF, 0xAA, 0x55, 0x00];
pub(crate) fn dmg_palette_index(palette_reg: u8, colour_index: u8) -> u8 {
(palette_reg >> (colour_index * 2)) & 0x03
}
pub(crate) fn dmg_grey(shade: u8) -> u8 {
DMG_GREY[shade as usize]
}
#[inline]
fn cgb_5bit_to_8bit(c5: u8) -> u8 {
(c5 << 3) | (c5 >> 2)
}
pub(crate) fn cgb_palette_lookup(
palette_ram: &[u8; 64],
palette_num: u8,
colour_index: u8,
) -> (u8, u8, u8) {
let base = (palette_num as usize) * 8 + (colour_index as usize) * 2;
let lo = palette_ram[base];
let hi = palette_ram[base + 1];
let color = u16::from_le_bytes([lo, hi]);
let r5 = (color & 0x1F) as u8;
let g5 = ((color >> 5) & 0x1F) as u8;
let b5 = ((color >> 10) & 0x1F) as u8;
(
cgb_5bit_to_8bit(r5),
cgb_5bit_to_8bit(g5),
cgb_5bit_to_8bit(b5),
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_palette_index_0_maps_to_white_with_default_bgp() {
assert_eq!(dmg_grey(dmg_palette_index(0xE4, 0)), DMG_GREY[0]);
}
#[test]
fn test_palette_index_3_maps_to_black_with_default_bgp() {
assert_eq!(dmg_grey(dmg_palette_index(0xE4, 3)), DMG_GREY[3]);
}
#[test]
fn test_palette_inverted_bgp_maps_0_to_black() {
assert_eq!(dmg_grey(dmg_palette_index(0x1B, 0)), DMG_GREY[3]);
}
#[test]
fn test_palette_all_white_bgp_maps_every_index_to_white() {
for i in 0..4 {
assert_eq!(dmg_grey(dmg_palette_index(0x00, i)), DMG_GREY[0]);
}
}
#[test]
fn test_cgb_5bit_to_8bit_known_values() {
assert_eq!(cgb_5bit_to_8bit(0), 0);
assert_eq!(cgb_5bit_to_8bit(31), 255); assert_eq!(cgb_5bit_to_8bit(1), 8); assert_eq!(cgb_5bit_to_8bit(16), 132); }
#[test]
fn test_cgb_palette_lookup_decodes_5_5_5_le() {
let mut palette_ram = [0u8; 64];
palette_ram[2] = 0x1F; palette_ram[3] = 0x00; let (r, g, b) = cgb_palette_lookup(&palette_ram, 0, 1);
assert_eq!(r, 255, "R should be max");
assert_eq!(g, 0, "G should be 0");
assert_eq!(b, 0, "B should be 0");
}
}