chore(ppu): move bg fetcher code into fetcher functions
This commit is contained in:
parent
2acdaaeec2
commit
38460577b9
191
src/ppu.rs
191
src/ppu.rs
|
@ -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)]
|
||||||
|
|
Loading…
Reference in New Issue