pub fn fetch_window_pixel(
x: u32,
scanline: u8,
vram: &[u8; 0x2000],
lcdc: u8,
wx: u8,
wy: u8,
window_line: u8,
) -> Option<u8> {
if lcdc & 0x20 == 0 {
return None;
}
if scanline < wy {
return None;
}
let win_x_start = wx.saturating_sub(7);
if x < win_x_start as u32 {
return None;
}
let win_x = (x as u8).wrapping_sub(win_x_start);
let win_y = window_line;
let map_base: usize = if lcdc & 0x40 != 0 { 0x1C00 } else { 0x1800 };
let tile_col = (win_x / 8) as usize;
let tile_row = (win_y / 8) as usize;
let tile_index_raw = vram[map_base + tile_row * 32 + tile_col];
let tile_data_start: usize = if lcdc & 0x10 != 0 {
(tile_index_raw as usize) * 16
} else {
(0x1000i32 + (tile_index_raw as i8 as i32) * 16) as usize
};
let row_in_tile = (win_y % 8) as usize;
let bit = 7 - (win_x % 8);
let addr = tile_data_start + row_in_tile * 2;
let low = vram[addr];
let high = vram[addr + 1];
Some(((high >> bit) & 1) << 1 | ((low >> bit) & 1))
}
#[cfg(test)]
mod tests {
use super::*;
fn blank_vram() -> [u8; 0x2000] {
[0u8; 0x2000]
}
#[test]
fn test_window_returns_none_when_disabled_in_lcdc() {
let vram = blank_vram();
let lcdc = 0x81u8; let result = fetch_window_pixel(0, 0, &vram, lcdc, 7, 0, 0);
assert_eq!(result, None);
}
#[test]
fn test_window_returns_none_above_wy() {
let vram = blank_vram();
let lcdc = 0xA1u8; let result = fetch_window_pixel(0, 9, &vram, lcdc, 7, 10, 0);
assert_eq!(result, None);
}
#[test]
fn test_window_returns_none_left_of_wx() {
let vram = blank_vram();
let lcdc = 0xA1u8;
let result = fetch_window_pixel(6, 0, &vram, lcdc, 14, 0, 0);
assert_eq!(result, None);
}
#[test]
fn test_window_returns_colour_index_for_pixel_inside_window() {
let vram = blank_vram();
let lcdc = 0xA1u8; let result = fetch_window_pixel(0, 0, &vram, lcdc, 7, 0, 0);
assert_eq!(result, Some(0));
}
#[test]
fn test_window_tile_data_colour_bits_from_vram() {
let mut vram = blank_vram();
vram[0x0010] = 0xFF;
vram[0x0011] = 0xFF;
vram[0x1800] = 0x01;
let lcdc = 0xB1u8;
let result = fetch_window_pixel(0, 0, &vram, lcdc, 7, 0, 0);
assert_eq!(result, Some(3));
}
}