From cb035495307841506a8ca9105f4f9fe5ef3b44d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com> Date: Sun, 4 Jun 2023 23:32:29 +0100 Subject: [PATCH] chore: made render for dmg only --- frontends/sdl/Cargo.toml | 2 + src/ppu.rs | 113 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 113 insertions(+), 2 deletions(-) diff --git a/frontends/sdl/Cargo.toml b/frontends/sdl/Cargo.toml index 20ae6478..7d916f68 100644 --- a/frontends/sdl/Cargo.toml +++ b/frontends/sdl/Cargo.toml @@ -28,6 +28,8 @@ version = "0.4" [dependencies.sdl2] version = "0.35" +git = "https://github.com/Rust-SDL2/rust-sdl2" +rev = "27cd1fd67c811e06b9d997a77bb6089a1b65070d" features = ["ttf", "image", "gfx", "mixer", "static-link", "use-vcpkg"] # For MacOS running under arm64 architecture there may be linking issues diff --git a/src/ppu.rs b/src/ppu.rs index 7df9a923..996e9858 100644 --- a/src/ppu.rs +++ b/src/ppu.rs @@ -1069,16 +1069,124 @@ impl Ppu { let switch_bg_window = (self.gb_mode == GameBoyMode::Cgb && !self.dmg_compat) || self.switch_bg; if switch_bg_window { - self.render_map(self.bg_map, self.scx, self.scy, 0, 0, self.ly); + self.render_map_no_cgb(self.bg_map, self.scx, self.scy, 0, 0, self.ly); } if switch_bg_window && self.switch_window { - self.render_map(self.window_map, 0, 0, self.wx, self.wy, self.window_counter); + self.render_map_no_cgb(self.window_map, 0, 0, self.wx, self.wy, self.window_counter); } if self.switch_obj { self.render_objects(); } } + fn render_map_no_cgb(&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; + } + + // 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 }; + + // calculates the map row index for the tile by using the current line + // index and the DY (scroll Y) divided by 8 (as the tiles are 8x8 pixels), + // on top of that ensures that the result is modulus 32 meaning that the + // drawing wraps around the Y axis + let row_index = (((ld as usize + scy as usize) & 0xff) >> 3) % 32; + + // calculates the map offset by the row offset multiplied by the number + // of tiles in each row (32) + let row_offset = row_index * 32; + + // calculates the sprite line offset by using the SCX register + // shifted by 3 meaning that the tiles are 8x8 + let mut line_offset = (scx >> 3) as usize; + + // calculates the index of the initial tile in drawing, + // if the tile data set in use is #1, the indexes are + // signed, then calculates a real tile offset + let mut tile_index = self.vram[map_offset + row_offset + line_offset] as usize; + if !self.bg_tile && tile_index < 128 { + tile_index += 256; + } + + // obtains the reference to the tile that is going to be drawn + let mut tile = &self.tiles[tile_index]; + + // 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; + + // calculates both the current Y and X positions within the tiles + // using the bitwise and operation as an effective modulus 8 + let y = (ld as usize + scy as usize) & 0x07; + let mut x = (scx & 0x07) as usize; + + // calculates the initial tile X position in drawing, doing this + // allows us to position the background map properly in the display + let initial_index = max(wx as i16 - 7, 0) as usize; + color_offset += initial_index; + frame_offset += initial_index * RGB_SIZE; + + // iterates over all the pixels in the current line of the display + // to draw the background map, note that the initial index is used + // to skip the drawing of the tiles that are not visible (WX) + 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]; + + // updates the pixel in the color buffer, which stores + // the raw pixel color information (unmapped) + 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 current tile X position in drawing + x += 1; + + // in case the end of tile width has been reached then + // a new tile must be retrieved for rendering + if x == TILE_WIDTH { + // resets the tile X position to the base value + // as a new tile is going to be drawn + x = 0; + + // calculates the new line tile offset making sure that + // the maximum of 32 is not overflown + line_offset = (line_offset + 1) % 32; + + // calculates the tile index and makes sure the value + // takes into consideration the bg tile value + tile_index = self.vram[map_offset + row_offset + line_offset] as usize; + if !self.bg_tile && tile_index < 128 { + tile_index += 256; + } + + // obtains the reference to the new tile in drawing + tile = &self.tiles[tile_index]; + } + + // increments the color offset by one, representing + // the drawing of one pixel + 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; + } + } + 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 @@ -1088,6 +1196,7 @@ impl Ppu { // 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 { -- GitLab