fix(ppu): fix sprite buffer bug
Now, the background renders like it should and some sprites do load, though they aren't where they're supposed to be
This commit is contained in:
parent
4f4c867a63
commit
c90b9ab024
178
src/ppu.rs
178
src/ppu.rs
|
@ -186,7 +186,7 @@ impl Ppu {
|
||||||
self.fetcher.bg.pause();
|
self.fetcher.bg.pause();
|
||||||
self.fifo.pause();
|
self.fifo.pause();
|
||||||
|
|
||||||
obj_attr = Some(attr);
|
obj_attr = Some(*attr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -207,7 +207,7 @@ impl Ppu {
|
||||||
ObjectSize::EightBySixteen => 16,
|
ObjectSize::EightBySixteen => 16,
|
||||||
};
|
};
|
||||||
|
|
||||||
let addr = PixelFetcher::get_obj_low_addr(attr, &self.pos, obj_size);
|
let addr = PixelFetcher::get_obj_low_addr(&attr, &self.pos, obj_size);
|
||||||
|
|
||||||
let byte = self.read_byte(addr);
|
let byte = self.read_byte(addr);
|
||||||
self.fetcher.obj.tile.with_low_byte(byte);
|
self.fetcher.obj.tile.with_low_byte(byte);
|
||||||
|
@ -222,7 +222,7 @@ impl Ppu {
|
||||||
ObjectSize::EightBySixteen => 16,
|
ObjectSize::EightBySixteen => 16,
|
||||||
};
|
};
|
||||||
|
|
||||||
let addr = PixelFetcher::get_obj_low_addr(attr, &self.pos, obj_size);
|
let addr = PixelFetcher::get_obj_low_addr(&attr, &self.pos, obj_size);
|
||||||
|
|
||||||
let byte = self.read_byte(addr + 1);
|
let byte = self.read_byte(addr + 1);
|
||||||
self.fetcher.obj.tile.with_high_byte(byte);
|
self.fetcher.obj.tile.with_high_byte(byte);
|
||||||
|
@ -268,6 +268,10 @@ impl Ppu {
|
||||||
|
|
||||||
self.fetcher.bg.resume();
|
self.fetcher.bg.resume();
|
||||||
self.fifo.resume();
|
self.fifo.resume();
|
||||||
|
|
||||||
|
self.obj_buffer
|
||||||
|
.remove(&attr)
|
||||||
|
.expect("Failed to remove Sprite Attribute from Buffer");
|
||||||
}
|
}
|
||||||
} else if self.fetcher.obj.fifo_count == 2 {
|
} else if self.fetcher.obj.fifo_count == 2 {
|
||||||
self.fetcher.obj.reset();
|
self.fetcher.obj.reset();
|
||||||
|
@ -279,51 +283,49 @@ 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 && self.fetcher.bg.is_enabled() {
|
||||||
if self.fetcher.bg.is_enabled() {
|
match self.fetcher.bg.state {
|
||||||
match self.fetcher.bg.state {
|
TileNumber => {
|
||||||
TileNumber => {
|
// 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 is_window && !self.fetcher.bg.window_line.checked() {
|
||||||
if is_window && !self.fetcher.bg.window_line.checked() {
|
self.fetcher.bg.window_line.increment();
|
||||||
self.fetcher.bg.window_line.increment();
|
|
||||||
}
|
|
||||||
|
|
||||||
let x_pos = self.fetcher.x_pos;
|
|
||||||
|
|
||||||
let addr = self
|
|
||||||
.fetcher
|
|
||||||
.bg_tile_num_addr(control, pos, x_pos, is_window);
|
|
||||||
|
|
||||||
let id = self.read_byte(addr);
|
|
||||||
self.fetcher.bg.tile.with_id(id);
|
|
||||||
|
|
||||||
// Move on to the Next state in 2 T-cycles
|
|
||||||
self.fetcher.bg.next(TileDataLow);
|
|
||||||
}
|
}
|
||||||
TileDataLow => {
|
|
||||||
let addr = self.fetcher.bg_byte_low_addr(control, pos, is_window);
|
|
||||||
|
|
||||||
let low = self.read_byte(addr);
|
let x_pos = self.fetcher.x_pos;
|
||||||
self.fetcher.bg.tile.with_low_byte(low);
|
|
||||||
|
|
||||||
self.fetcher.bg.next(TileDataHigh);
|
let addr = self
|
||||||
}
|
.fetcher
|
||||||
TileDataHigh => {
|
.bg_tile_num_addr(control, pos, x_pos, is_window);
|
||||||
let addr = self.fetcher.bg_byte_low_addr(control, pos, is_window);
|
|
||||||
|
|
||||||
let high = self.read_byte(addr + 1);
|
let id = self.read_byte(addr);
|
||||||
self.fetcher.bg.tile.with_high_byte(high);
|
self.fetcher.bg.tile.with_id(id);
|
||||||
|
|
||||||
self.fetcher.bg.next(SendToFifo);
|
// Move on to the Next state in 2 T-cycles
|
||||||
}
|
self.fetcher.bg.next(TileDataLow);
|
||||||
SendToFifo => {
|
}
|
||||||
let palette = &self.monochrome.bg_palette;
|
TileDataLow => {
|
||||||
self.fetcher.send_to_fifo(&mut self.fifo, palette);
|
let addr = self.fetcher.bg_byte_low_addr(control, pos, is_window);
|
||||||
|
|
||||||
// FIXME: Should this be equivalent to a reset?
|
let low = self.read_byte(addr);
|
||||||
self.fetcher.bg.next(TileNumber);
|
self.fetcher.bg.tile.with_low_byte(low);
|
||||||
}
|
|
||||||
|
self.fetcher.bg.next(TileDataHigh);
|
||||||
|
}
|
||||||
|
TileDataHigh => {
|
||||||
|
let addr = self.fetcher.bg_byte_low_addr(control, pos, is_window);
|
||||||
|
|
||||||
|
let high = self.read_byte(addr + 1);
|
||||||
|
self.fetcher.bg.tile.with_high_byte(high);
|
||||||
|
|
||||||
|
self.fetcher.bg.next(SendToFifo);
|
||||||
|
}
|
||||||
|
SendToFifo => {
|
||||||
|
let palette = &self.monochrome.bg_palette;
|
||||||
|
self.fetcher.send_to_fifo(&mut self.fifo, palette);
|
||||||
|
|
||||||
|
// FIXME: Should this be equivalent to a reset?
|
||||||
|
self.fetcher.bg.next(TileNumber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -331,18 +333,31 @@ impl Ppu {
|
||||||
if self.fifo.is_enabled() {
|
if self.fifo.is_enabled() {
|
||||||
// Handle Background Pixel and Sprite FIFO
|
// Handle Background Pixel and Sprite FIFO
|
||||||
if let Some(bg_pixel) = self.fifo.background.pop_front() {
|
if let Some(bg_pixel) = self.fifo.background.pop_front() {
|
||||||
if let Some(_object_pixel) = self.fifo.object.pop_front() {
|
let rgba = match self.fifo.object.pop_front() {
|
||||||
todo!("Mix the pixels or whatever I'm supposed todo here");
|
Some(obj_pixel) => match obj_pixel.shade {
|
||||||
} else {
|
Some(obj_shade) => {
|
||||||
// Only Background Pixels will be rendered
|
if let RenderPriority::BackgroundAndWindow = obj_pixel.priority {
|
||||||
|
match bg_pixel.shade {
|
||||||
|
GrayShade::White => obj_shade.into_rgba(),
|
||||||
|
_ => bg_pixel.shade.into_rgba(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
obj_shade.into_rgba()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => bg_pixel.shade.into_rgba(),
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
// Only Background Pixels will be rendered
|
||||||
|
bg_pixel.shade.into_rgba()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let y = self.pos.line_y as usize;
|
let y = self.pos.line_y as usize;
|
||||||
let x = self.x_pos as usize;
|
let x = self.x_pos as usize;
|
||||||
let rgba = bg_pixel.0.into_rgba();
|
|
||||||
|
|
||||||
let i = (GB_WIDTH * 4) * y + (x * 4);
|
let i = (GB_WIDTH * 4) * y + (x * 4);
|
||||||
self.frame_buf[i..(i + rgba.len())].copy_from_slice(&rgba);
|
self.frame_buf[i..(i + rgba.len())].copy_from_slice(&rgba);
|
||||||
}
|
|
||||||
|
|
||||||
self.x_pos += 1;
|
self.x_pos += 1;
|
||||||
}
|
}
|
||||||
|
@ -816,7 +831,7 @@ impl Default for ObjectAttributeTable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
|
||||||
pub struct ObjectAttribute {
|
pub struct ObjectAttribute {
|
||||||
y: u8,
|
y: u8,
|
||||||
x: u8,
|
x: u8,
|
||||||
|
@ -856,6 +871,13 @@ bitfield! {
|
||||||
from into ObjectPaletteId, palette, set_palette: 4, 4;
|
from into ObjectPaletteId, palette, set_palette: 4, 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Eq for ObjectFlags {}
|
||||||
|
impl PartialEq for ObjectFlags {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.0 == other.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Copy for ObjectFlags {}
|
impl Copy for ObjectFlags {}
|
||||||
impl Clone for ObjectFlags {
|
impl Clone for ObjectFlags {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
|
@ -963,6 +985,38 @@ impl ObjectBuffer {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn position(&self, attr: &ObjectAttribute) -> Option<usize> {
|
||||||
|
let mut index = None;
|
||||||
|
|
||||||
|
for i in 0..self.len {
|
||||||
|
if self.buf[i] == *attr {
|
||||||
|
index = Some(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
index
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(&mut self, attr: &ObjectAttribute) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
// TODO: Make this not bad code
|
||||||
|
let mut copy: ObjectBuffer = Default::default();
|
||||||
|
|
||||||
|
let i = self
|
||||||
|
.position(attr)
|
||||||
|
.ok_or_else(|| format!("Could not find {:?} in Sprite Buffer", attr))?;
|
||||||
|
|
||||||
|
for j in 0..self.len {
|
||||||
|
if j != i {
|
||||||
|
copy.add(self.buf[j])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.buf = copy.buf;
|
||||||
|
self.len = copy.len;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ObjectBuffer {
|
impl Default for ObjectBuffer {
|
||||||
|
@ -1073,7 +1127,7 @@ impl PixelFetcher {
|
||||||
|
|
||||||
let shade = palette.colour(pixel.pixel(bit));
|
let shade = palette.colour(pixel.pixel(bit));
|
||||||
|
|
||||||
let fifo_pixel = BackgroundFifoPixel(shade);
|
let fifo_pixel = BackgroundFifoPixel { shade };
|
||||||
fifo.background.push_back(fifo_pixel);
|
fifo.background.push_back(fifo_pixel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1222,20 +1276,10 @@ impl Default for FetcherState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
enum FifoPixelKind {
|
|
||||||
Background,
|
|
||||||
Object,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for FifoPixelKind {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::Background
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
struct BackgroundFifoPixel(GrayShade);
|
struct BackgroundFifoPixel {
|
||||||
|
shade: GrayShade,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
struct ObjectFifoPixel {
|
struct ObjectFifoPixel {
|
||||||
|
|
Loading…
Reference in New Issue