From 90d7474b67f08b1973b82e46485cf694dc16b660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com> Date: Thu, 7 Jul 2022 17:48:08 +0100 Subject: [PATCH] fix: issue with priority of obj --- src/ppu.rs | 72 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 22 deletions(-) diff --git a/src/ppu.rs b/src/ppu.rs index 9152939b..9ec80ce8 100644 --- a/src/ppu.rs +++ b/src/ppu.rs @@ -29,11 +29,16 @@ pub const DISPLAY_WIDTH: usize = 160; /// The height of the Game Boy screen in pixels. pub const DISPLAY_HEIGHT: usize = 144; -// The size of the RGB frame buffer in bytes. +/// The size to be used by the buffer of colors +/// for the Game Boy screen the values there should +/// range from 0 to 3. +pub const COLOR_BUFFER_SIZE: usize = DISPLAY_WIDTH * DISPLAY_HEIGHT; + +/// The size of the RGB frame buffer in bytes. pub const FRAME_BUFFER_SIZE: usize = DISPLAY_WIDTH * DISPLAY_HEIGHT * RGB_SIZE; -// Defines the Game Boy pixel type as a buffer -// with the size of RGB (3 bytes). +/// Defines the Game Boy pixel type as a buffer +/// with the size of RGB (3 bytes). pub type Pixel = [u8; RGB_SIZE]; /// Defines a type that represents a color palette @@ -69,7 +74,6 @@ impl Tile { } } - impl Tile { pub fn palette_buffer(&self, palette: Palette) -> Vec<u8> { self.buffer @@ -101,7 +105,7 @@ pub struct ObjectData { palette: u8, xflip: bool, yflip: bool, - prio: u8, + prio: bool, index: u8, } @@ -127,6 +131,10 @@ impl Display for ObjectData { /// ppu.clock(); /// ``` pub struct Ppu { + /// The color buffer that is going to store the colors + /// (from 0 to 3) for all the pixels in the screen. + pub color_buffer: Box<[u8; COLOR_BUFFER_SIZE]>, + /// The 8 bit based RGB frame buffer with the /// processed set of pixels ready to be displayed on screen. pub frame_buffer: Box<[u8; FRAME_BUFFER_SIZE]>, @@ -236,7 +244,8 @@ pub enum PpuMode { impl Ppu { pub fn new() -> Self { Self { - frame_buffer: Box::new([0u8; DISPLAY_WIDTH * DISPLAY_HEIGHT * RGB_SIZE]), + color_buffer: Box::new([0u8; COLOR_BUFFER_SIZE]), + frame_buffer: Box::new([0u8; FRAME_BUFFER_SIZE]), vram: [0u8; VRAM_SIZE], hram: [0u8; HRAM_SIZE], oam: [0u8; OAM_SIZE], @@ -248,7 +257,7 @@ impl Ppu { palette: 0, xflip: false, yflip: false, - prio: 0, + prio: false, index: 0, }; OBJ_COUNT], palette: [[0u8; RGB_SIZE]; PALETTE_SIZE], @@ -277,7 +286,8 @@ impl Ppu { } pub fn reset(&mut self) { - self.frame_buffer = Box::new([0u8; DISPLAY_WIDTH * DISPLAY_HEIGHT * RGB_SIZE]); + self.color_buffer = Box::new([0u8; COLOR_BUFFER_SIZE]); + self.frame_buffer = Box::new([0u8; FRAME_BUFFER_SIZE]); self.vram = [0u8; VRAM_SIZE]; self.hram = [0u8; HRAM_SIZE]; self.tiles = [Tile { buffer: [0u8; 64] }; TILE_COUNT]; @@ -496,6 +506,7 @@ impl Ppu { /// this method must represent the fastest way of achieving /// the fill background with color operation. pub fn fill_frame_buffer(&mut self, color: Pixel) { + self.color_buffer.fill(0); for index in (0..self.frame_buffer.len()).step_by(RGB_SIZE) { self.frame_buffer[index] = color[0]; self.frame_buffer[index + 1] = color[1]; @@ -556,7 +567,7 @@ impl Ppu { obj.palette = if value & 0x10 == 0x10 { 1 } else { 0 }; obj.xflip = if value & 0x20 == 0x20 { true } else { false }; obj.yflip = if value & 0x40 == 0x40 { true } else { false }; - obj.prio = if value & 0x80 == 0x80 { 1 } else { 0 }; + obj.prio = if value & 0x80 == 0x80 { false } else { true }; obj.index = obj_index as u8; } _ => (), @@ -597,6 +608,10 @@ impl Ppu { tile_index += 256; } + // calculates the offset that is going to be used in the update of the color buffer + // which stores Game Boy colors from 0 to 3 + let mut color_offset = self.ly as usize * DISPLAY_WIDTH; + // calculates the frame buffer offset position assuming the proper // Game Boy screen width and RGB pixel (3 bytes) size let mut frame_offset = self.ly as usize * DISPLAY_WIDTH * RGB_SIZE; @@ -607,11 +622,17 @@ impl Ppu { let pixel = self.tiles[tile_index].get(x, y); let color = self.palette[pixel as usize]; + // updates the pixel in the color buffer + self.color_buffer[color_offset] = pixel; + // set the color pixel in the frame buffer self.frame_buffer[frame_offset] = color[0]; self.frame_buffer[frame_offset + 1] = color[1]; self.frame_buffer[frame_offset + 2] = color[2]; + // increments the color offset by one + color_offset += 1; + // increments the offset of the frame buffer by the // size of an RGB pixel (which is 3 bytes) frame_offset += RGB_SIZE; @@ -661,6 +682,8 @@ impl Ppu { self.palette_obj_1 }; + let mut color_offset = self.ly as usize * DISPLAY_WIDTH + obj.x as usize; + // calculates the offset in the frame buffer for the sprite // that is going to be drawn, this is going to be the starting // point for the draw operation to be performed @@ -678,21 +701,26 @@ impl Ppu { for x in 0..TILE_WIDTH { let is_contained = (obj.x + x as i16 >= 0) && ((obj.x + x as i16) < DISPLAY_WIDTH as i16); - if !is_contained { - continue; + if is_contained { + // the object is only considered visible if it's a priority + // or if the underlying pixel is transparent (zero value) + let is_visible = obj.prio || self.color_buffer[color_offset] == 0; + if is_visible { + // obtains the current pixel data from the tile row and + // re-maps it according to the object palette + let pixel = tile_row[if obj.xflip { 7 - x } else { x }]; + let color = palette[pixel as usize]; + + // set the color pixel in the frame buffer + self.frame_buffer[frame_offset] = color[0]; + self.frame_buffer[frame_offset + 1] = color[1]; + self.frame_buffer[frame_offset + 2] = color[2]; + } } - //let is_visible = obj_data.prio || !scanrow[obj.x + x] // @todo must implement scanrown latter - - // obtains the current pixel data from the tile row and - // re-maps it according to the object palette - let pixel = tile_row[x]; - let color = palette[pixel as usize]; - - // set the color pixel in the frame buffer - self.frame_buffer[frame_offset] = color[0]; - self.frame_buffer[frame_offset + 1] = color[1]; - self.frame_buffer[frame_offset + 2] = color[2]; + // increment the color offset by one as this represents + // the advance of one color pixel + color_offset += 1; // increments the offset of the frame buffer by the // size of an RGB pixel (which is 3 bytes) -- GitLab