chore(ppu): move bg fetcher code into fetcher functions

This commit is contained in:
Rekai Nyangadzayi Musuka 2021-04-18 02:43:34 -05:00
parent 2acdaaeec2
commit 38460577b9
1 changed files with 106 additions and 85 deletions

View File

@ -170,6 +170,9 @@ impl Ppu {
// By only running on odd cycles, we can ensure that we draw every two T cycles // By only running on odd cycles, we can ensure that we draw every two T cycles
if cycle % 2 != 0 { if cycle % 2 != 0 {
let control = &self.control;
let pos = &self.pos;
let line_y = self.pos.line_y; let line_y = self.pos.line_y;
let scroll_y = self.pos.scroll_y; let scroll_y = self.pos.scroll_y;
let window_y = self.pos.window_y; let window_y = self.pos.window_y;
@ -177,38 +180,17 @@ impl Ppu {
match self.fetcher.state { match self.fetcher.state {
TileNumber => { TileNumber => {
let scroll_x = self.pos.scroll_x;
// Increment Window line counter if scanline had any window pixels on it // Increment Window line counter if scanline had any window pixels on it
// only increment once per scanline though // only increment once per scanline though
if window_present && !self.fetcher.window_line.checked() { if window_present && !self.fetcher.window_line.checked() {
self.fetcher.window_line.increment(); self.fetcher.window_line.increment();
} }
// Determine which tile map is being used let x_pos = self.fetcher.x_pos;
let tile_map = if window_present {
self.control.win_tile_map_addr()
} else {
self.control.bg_tile_map_addr()
};
let tile_map_addr = tile_map.into_address();
// Both Offsets are used to offset the tile map address we found above let addr = self
// Offsets are ANDed wih 0x3FF so that we stay in bounds of tile map memory .fetcher
// TODO: Is this necessary / important in other fetcher modes? .bg_tile_num_addr(control, pos, x_pos, window_present);
let x_offset = (self.fetcher.x_pos + scroll_x) as u16 & 0x03FF;
let y_offset = (line_y.wrapping_add(scroll_y)) as u16 & 0x03FF;
// Scroll X Offset is only used when we're rendering the background;
let scx_offset = if window_present { 0 } else { scroll_x / 8 } & 0x1F;
let offset = if window_present {
32 * (self.fetcher.window_line.count() as u16 / 8)
} else {
32 * (((y_offset) & 0x00FF) / 8)
};
let addr = tile_map_addr + offset + x_offset + scx_offset as u16;
let id = self.read_byte(addr); let id = self.read_byte(addr);
self.fetcher.tile.with_id(id); self.fetcher.tile.with_id(id);
@ -217,81 +199,26 @@ impl Ppu {
self.fetcher.state = TileDataLow; self.fetcher.state = TileDataLow;
} }
TileDataLow => { TileDataLow => {
let id = self let addr = self.fetcher.bg_byte_low_addr(control, pos, window_present);
.fetcher
.tile
.id
.expect("Tile Number unexpectedly missing");
let tile_data_addr = match self.control.tile_data_addr() {
TileDataAddress::X8800 => (0x9000_i32 + (id as i32 * 16)) as u16,
TileDataAddress::X8000 => 0x8000 + (id as u16 * 16),
};
let offset = if window_present {
2 * (self.fetcher.window_line.count() % 8)
} else {
2 * ((line_y + scroll_y) % 8)
};
let addr = tile_data_addr + offset as u16;
let low = self.read_byte(addr); let low = self.read_byte(addr);
self.fetcher.tile.with_low_byte(low); self.fetcher.tile.with_low_byte(low);
self.fetcher.state = TileDataHigh; self.fetcher.state = TileDataHigh;
} }
TileDataHigh => { TileDataHigh => {
let id = self let addr = self.fetcher.bg_byte_low_addr(control, pos, window_present);
.fetcher
.tile
.id
.expect("Tile Number unexpectedly missing");
let tile_data_addr = match self.control.tile_data_addr() {
TileDataAddress::X8800 => (0x9000_i32 + (id as i32 * 16)) as u16,
TileDataAddress::X8000 => 0x8000 + (id as u16 * 16),
};
let offset = if window_present {
2 * (self.fetcher.window_line.count() % 8)
} else {
2 * ((line_y + scroll_y) % 8)
};
let addr = tile_data_addr + offset as u16;
let high = self.read_byte(addr + 1); let high = self.read_byte(addr + 1);
self.fetcher.tile.with_high_byte(high); self.fetcher.tile.with_high_byte(high);
self.fetcher.state = SendToFifo; self.fetcher.state = SendToFifo;
} }
SendToFifo => { SendToFifo => {
if let Some(low) = self.fetcher.tile.low { let palette = &self.monochrome.bg_palette;
if let Some(high) = self.fetcher.tile.high { self.fetcher.send_to_fifo(&mut self.fifo, palette);
let pixel = TwoBitsPerPixel::from_bytes(high, low);
let palette = self.monochrome.bg_palette;
if self.fifo.background.is_empty() { self.fetcher.state = TileNumber;
for i in 0..8 {
// Horizontally flip pixels
let bit = 7 - i;
let shade = palette.colour(pixel.pixel(bit));
let fifo_pixel = FifoPixel {
kind: FifoPixelKind::Background,
shade,
palette: None,
priority: None,
};
self.fifo.background.push_back(fifo_pixel);
}
}
self.fetcher.state = TileNumber;
self.fetcher.x_pos += 1;
}
}
} }
} }
} }
@ -948,6 +875,100 @@ impl PixelFetcher {
pub fn vblank_reset(&mut self) { pub fn vblank_reset(&mut self) {
self.window_line.vblank_reset(); self.window_line.vblank_reset();
} }
fn bg_tile_num_addr(
&self,
control: &LCDControl,
pos: &ScreenPosition,
x_pos: u8,
window: bool,
) -> u16 {
let line_y = pos.line_y;
let scroll_y = pos.scroll_y;
let scroll_x = pos.scroll_x;
// Determine which tile map is being used
let tile_map = if window {
control.win_tile_map_addr()
} else {
control.bg_tile_map_addr()
};
let tile_map_addr = tile_map.into_address();
// Both Offsets are used to offset the tile map address we found above
// Offsets are ANDed wih 0x3FF so that we stay in bounds of tile map memory
// TODO: Is this necessary / important in other fetcher modes?
let x_offset = (x_pos + scroll_x) as u16 & 0x03FF;
let y_offset = (line_y.wrapping_add(scroll_y)) as u16 & 0x03FF;
// Scroll X Offset is only used when we're rendering the background;
let scx_offset = if window { 0 } else { scroll_x / 8 } & 0x1F;
let offset = if window {
32 * (self.window_line.count() as u16 / 8)
} else {
32 * (((y_offset) & 0x00FF) / 8)
};
// Determine Address
tile_map_addr + offset + x_offset + scx_offset as u16
}
fn bg_byte_low_addr(
&mut self,
control: &LCDControl,
pos: &ScreenPosition,
window: bool,
) -> u16 {
let line_y = pos.line_y;
let scroll_y = pos.scroll_y;
let id = self.tile.id.expect("Tile Number unexpectedly missing");
let tile_data_addr = match control.tile_data_addr() {
TileDataAddress::X8800 => (0x9000_i32 + (id as i32 * 16)) as u16,
TileDataAddress::X8000 => 0x8000 + (id as u16 * 16),
};
let offset = if window {
2 * (self.window_line.count() % 8)
} else {
2 * ((line_y + scroll_y) % 8)
};
tile_data_addr + offset as u16
}
fn send_to_fifo(&mut self, fifo: &mut FifoRenderer, palette: &BackgroundPalette) {
let tile_bytes = self.tile.low.zip(self.tile.high);
if let Some(bytes) = tile_bytes {
let low = bytes.0;
let high = bytes.1;
let pixel = TwoBitsPerPixel::from_bytes(high, low);
if fifo.background.is_empty() {
for i in 0..8 {
// Horizontally flip pixels
let bit = 7 - i;
let shade = palette.colour(pixel.pixel(bit));
let fifo_pixel = FifoPixel {
kind: FifoPixelKind::Background,
shade,
palette: None,
priority: None,
};
fifo.background.push_back(fifo_pixel);
}
}
}
self.x_pos += 1;
}
} }
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]