diff --git a/src/gb.rs b/src/gb.rs index c6b0cd4314a14174c92811292ae04195e259fa2d..437c5ecebade820779474da41c22b5a562a6eff8 100644 --- a/src/gb.rs +++ b/src/gb.rs @@ -58,7 +58,7 @@ impl GameBoyMode { } } - pub fn from_u8(value: u8) -> GameBoyMode { + pub fn from_u8(value: u8) -> Self { match value { 1 => GameBoyMode::Dmg, 2 => GameBoyMode::Cgb, @@ -67,7 +67,7 @@ impl GameBoyMode { } } - pub fn from_string(value: &str) -> GameBoyMode { + pub fn from_string(value: &str) -> Self { match value { "dmg" => GameBoyMode::Dmg, "cgb" => GameBoyMode::Cgb, @@ -75,6 +75,18 @@ impl GameBoyMode { _ => panic!("Invalid mode value: {}", value), } } + + pub fn is_dmg(&self) -> bool { + *self == GameBoyMode::Dmg + } + + pub fn is_cgb(&self) -> bool { + *self == GameBoyMode::Cgb + } + + pub fn is_sgb(&self) -> bool { + *self == GameBoyMode::Sgb + } } impl Display for GameBoyMode { @@ -98,7 +110,7 @@ impl GameBoySpeed { } } - pub fn switch(&self) -> GameBoySpeed { + pub fn switch(&self) -> Self { match self { GameBoySpeed::Normal => GameBoySpeed::Double, GameBoySpeed::Double => GameBoySpeed::Normal, @@ -112,7 +124,7 @@ impl GameBoySpeed { } } - pub fn from_u8(value: u8) -> GameBoySpeed { + pub fn from_u8(value: u8) -> Self { match value { 0 => GameBoySpeed::Normal, 1 => GameBoySpeed::Double, diff --git a/src/ppu.rs b/src/ppu.rs index 4461a53877817a5d106b8ae9cdb90e659b72ec64..690da47c5f3554bc31057dcf02c0e4ecddf060a9 100644 --- a/src/ppu.rs +++ b/src/ppu.rs @@ -1063,38 +1063,60 @@ impl Ppu { } fn render_line(&mut self) { + if self.gb_mode == GameBoyMode::Dmg { + self.render_line_dmg(); + } else { + self.render_line_cgb(); + } + } + + fn render_line_dmg(&mut self) { if self.first_frame { return; } - let switch_bg_window = - (self.gb_mode == GameBoyMode::Cgb && !self.dmg_compat) || self.switch_bg; + if self.switch_bg { + self.render_map_dmg(self.bg_map, self.scx, self.scy, 0, 0, self.ly); + } + if self.switch_bg && self.switch_window { + self.render_map_dmg(self.window_map, 0, 0, self.wx, self.wy, self.window_counter); + } + if self.switch_obj { + self.render_objects(); + } + } + fn render_line_cgb(&mut self) { + if self.first_frame { + return; + } + let switch_bg_window = (self.gb_mode.is_cgb() && !self.dmg_compat) || self.switch_bg; if switch_bg_window { - if self.gb_mode == GameBoyMode::Dmg { - self.render_map_dmg(self.bg_map, self.scx, self.scy, 0, 0, self.ly); - } else { - self.render_map(self.bg_map, self.scx, self.scy, 0, 0, self.ly); - } + self.render_map(self.bg_map, self.scx, self.scy, 0, 0, self.ly); } if switch_bg_window && self.switch_window { - if self.gb_mode == GameBoyMode::Dmg { - self.render_map_dmg(self.window_map, 0, 0, self.wx, self.wy, self.window_counter); - } else { - self.render_map(self.window_map, 0, 0, self.wx, self.wy, self.window_counter); - } + self.render_map(self.window_map, 0, 0, self.wx, self.wy, self.window_counter); } if self.switch_obj { self.render_objects(); } } - fn render_map_dmg(&mut self, map: bool, scx: u8, scy: u8, wx: u8, wy: u8, ld: u8) { + fn render_map(&mut self, map: bool, scx: u8, scy: u8, wx: u8, wy: u8, ld: u8) { // in case the target window Y position has not yet been reached // then there's nothing to be done, returns control flow immediately if self.ly < wy { return; } + // selects the correct background attributes map based on the bg map flag + // because the attributes are separated according to the map they represent + // this is only relevant for CGB mode + let bg_map_attrs = if map { + self.bg_map_attrs_1 + } else { + self.bg_map_attrs_0 + }; + // obtains the base address of the background map using the bg map flag // that control which background map is going to be used let map_offset: usize = if map { 0x1c00 } else { 0x1800 }; @@ -1121,6 +1143,35 @@ impl Ppu { tile_index += 256; } + // obtains the reference to the attributes of the new tile in + // drawing for meta processing (CGB only) + let mut tile_attr = if self.dmg_compat { + &DEFAULT_TILE_ATTR + } else { + &bg_map_attrs[row_offset + line_offset] + }; + + // retrieves the proper palette for the current tile in drawing + // taking into consideration if we're running in CGB mode or not + let mut palette = if self.gb_mode == GameBoyMode::Cgb { + if self.dmg_compat { + &self.palette_bg + } else { + &self.palettes_color_bg[tile_attr.palette as usize] + } + } else { + &self.palette_bg + }; + + // obtains the values of both X and Y flips for the current tile + // they will be applied by the get tile pixel method + let mut xflip = tile_attr.xflip; + let mut yflip = tile_attr.yflip; + + // increments the tile index value by the required offset for the VRAM + // bank in which the tile is stored, this is only required for CGB mode + tile_index += tile_attr.vram_bank as usize * TILE_COUNT_DMG; + // obtains the reference to the tile that is going to be drawn let mut tile = &self.tiles[tile_index]; @@ -1149,8 +1200,8 @@ impl Ppu { for _ in initial_index..DISPLAY_WIDTH { // obtains the current pixel data from the tile and // re-maps it according to the current palette - let pixel = tile.get(x, y); - let color = &self.palette_bg[pixel as usize]; + let pixel = tile.get_flipped(x, y, xflip, yflip); + let color = &palette[pixel as usize]; // updates the pixel in the color buffer, which stores // the raw pixel color information (unmapped) @@ -1182,6 +1233,17 @@ impl Ppu { tile_index += 256; } + // in case the current mode is CGB and the DMG compatibility + // flag is not set then a series of tile values must be + // updated according to the tile attributes field + if self.gb_mode == GameBoyMode::Cgb && !self.dmg_compat { + tile_attr = &bg_map_attrs[row_offset + line_offset]; + palette = &self.palettes_color_bg[tile_attr.palette as usize]; + xflip = tile_attr.xflip; + yflip = tile_attr.yflip; + tile_index += tile_attr.vram_bank as usize * TILE_COUNT_DMG; + } + // obtains the reference to the new tile in drawing tile = &self.tiles[tile_index]; } @@ -1196,22 +1258,13 @@ impl Ppu { } } - fn render_map(&mut self, map: bool, scx: u8, scy: u8, wx: u8, wy: u8, ld: u8) { + fn render_map_dmg(&mut self, map: bool, scx: u8, scy: u8, wx: u8, wy: u8, ld: u8) { // in case the target window Y position has not yet been reached // then there's nothing to be done, returns control flow immediately if self.ly < wy { return; } - // selects the correct background attributes map based on the bg map flag - // because the attributes are separated according to the map they represent - // this is only relevant for CGB mode - let bg_map_attrs = if map { - self.bg_map_attrs_1 - } else { - self.bg_map_attrs_0 - }; - // obtains the base address of the background map using the bg map flag // that control which background map is going to be used let map_offset: usize = if map { 0x1c00 } else { 0x1800 }; @@ -1238,35 +1291,6 @@ impl Ppu { tile_index += 256; } - // obtains the reference to the attributes of the new tile in - // drawing for meta processing (CGB only) - let mut tile_attr = if self.dmg_compat { - &DEFAULT_TILE_ATTR - } else { - &bg_map_attrs[row_offset + line_offset] - }; - - // retrieves the proper palette for the current tile in drawing - // taking into consideration if we're running in CGB mode or not - let mut palette = if self.gb_mode == GameBoyMode::Cgb { - if self.dmg_compat { - &self.palette_bg - } else { - &self.palettes_color_bg[tile_attr.palette as usize] - } - } else { - &self.palette_bg - }; - - // obtains the values of both X and Y flips for the current tile - // they will be applied by the get tile pixel method - let mut xflip = tile_attr.xflip; - let mut yflip = tile_attr.yflip; - - // increments the tile index value by the required offset for the VRAM - // bank in which the tile is stored, this is only required for CGB mode - tile_index += tile_attr.vram_bank as usize * TILE_COUNT_DMG; - // obtains the reference to the tile that is going to be drawn let mut tile = &self.tiles[tile_index]; @@ -1295,8 +1319,8 @@ impl Ppu { for _ in initial_index..DISPLAY_WIDTH { // obtains the current pixel data from the tile and // re-maps it according to the current palette - let pixel = tile.get_flipped(x, y, xflip, yflip); - let color = &palette[pixel as usize]; + let pixel = tile.get(x, y); + let color = &self.palette_bg[pixel as usize]; // updates the pixel in the color buffer, which stores // the raw pixel color information (unmapped) @@ -1328,17 +1352,6 @@ impl Ppu { tile_index += 256; } - // in case the current mode is CGB and the DMG compatibility - // flag is not set then a series of tile values must be - // updated according to the tile attributes field - if self.gb_mode == GameBoyMode::Cgb && !self.dmg_compat { - tile_attr = &bg_map_attrs[row_offset + line_offset]; - palette = &self.palettes_color_bg[tile_attr.palette as usize]; - xflip = tile_attr.xflip; - yflip = tile_attr.yflip; - tile_index += tile_attr.vram_bank as usize * TILE_COUNT_DMG; - } - // obtains the reference to the new tile in drawing tile = &self.tiles[tile_index]; }