From f7b5476a7e5eff25a09984e947a0192c82ea20ad Mon Sep 17 00:00:00 2001 From: velllu <91963404+velllu@users.noreply.github.com> Date: Sun, 7 Apr 2024 19:08:40 +0200 Subject: [PATCH] Implemented basic window rendering --- src/consts.rs | 2 ++ src/gpu/mod.rs | 1 + src/gpu/states.rs | 21 ++++++++++++++++++--- src/gpu/tile_parser.rs | 9 +++++++-- src/gpu/window.rs | 11 +++++++++++ 5 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 src/gpu/window.rs diff --git a/src/consts.rs b/src/consts.rs index bd76279..f070da5 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -20,6 +20,8 @@ pub mod gpu { pub const LYC: u16 = 0xFF45; pub const OBP0: u16 = 0xFF48; pub const OBP1: u16 = 0xFF49; + pub const WY: u16 = 0xFF4A; + pub const WX: u16 = 0xFF4B; pub const IE: u16 = 0xFFFF; } diff --git a/src/gpu/mod.rs b/src/gpu/mod.rs index 53e53ab..73a1bd0 100644 --- a/src/gpu/mod.rs +++ b/src/gpu/mod.rs @@ -2,6 +2,7 @@ pub(crate) mod palette; pub(crate) mod sprite_parser; pub mod states; pub mod tile_parser; +pub(crate) mod window; #[derive(Clone, Copy, PartialEq, Debug)] pub enum Color { diff --git a/src/gpu/states.rs b/src/gpu/states.rs index de9354e..3a24d9c 100644 --- a/src/gpu/states.rs +++ b/src/gpu/states.rs @@ -2,7 +2,7 @@ use crate::{ common::Bit, consts::{ display::{DISPLAY_SIZE_X, DISPLAY_SIZE_Y}, - gpu::{LCDC, LY, SCX, SCY}, + gpu::{LCDC, LY, SCX, SCY, WX, WY}, }, GameBoy, }; @@ -36,8 +36,8 @@ pub struct Gpu { rendered_sprites_on_line: u8, // These represent the current position of the "cursor" - x: u8, - y: u8, + pub(crate) x: u8, + pub(crate) y: u8, /// A dot is 1/4 of a CPU cycle pub dots: u16, @@ -98,12 +98,16 @@ impl GameBoy { self.gpu.dots += 12; } + // TODO: Scrolling is actually handled a bit differently, read this + // "https://gbdev.io/pandocs/Scrolling.html#mid-frame-behavior" + // And we get the background fifo and the sprite fifo let background_fifo = match self.bus[LCDC].get_bit(0) { false => Line::new_blank(), // When LCDC.0 is 0, the background tile is white true => self.get_line_from_coordinates( self.gpu.x.wrapping_add(self.bus[SCX]), self.gpu.y.wrapping_add(self.bus[SCY]), + false, ), }; @@ -123,6 +127,17 @@ impl GameBoy { self.draw_line(&background_fifo, self.gpu.x as usize, self.gpu.y as usize); } + // Window rendering + // `- 7` because WX is always 7 more then the actual value + let window_x = self.gpu.x as i32 - (self.bus[WX] as i32 - 7); + let window_y = self.gpu.y as i32 - self.bus[WY] as i32; + + // Window doesn't scroll so we don't wrap around like with the background + if window_x >= 0 && window_y >= 0 && self.can_render_window() { + let window_fifo = self.get_line_from_coordinates(window_x as u8, window_y as u8, true); + self.draw_line(&window_fifo, self.gpu.x as usize, self.gpu.y as usize); + } + self.gpu.x += 8; if self.gpu.x == (DISPLAY_SIZE_X as u8) { diff --git a/src/gpu/tile_parser.rs b/src/gpu/tile_parser.rs index 5b95414..b8318a9 100644 --- a/src/gpu/tile_parser.rs +++ b/src/gpu/tile_parser.rs @@ -80,8 +80,13 @@ impl GameBoy { /// Returns the line that should be at the given coordinates of the screen (excluding /// horizontal and vertical scroll) - pub(crate) fn get_line_from_coordinates(&self, x: u8, y: u8) -> Line { - let tile_map_address: u16 = match self.bus[0xFF40].get_bit(3) { + pub(crate) fn get_line_from_coordinates(&self, x: u8, y: u8, window: bool) -> Line { + let lcdc_bit = match window { + false => 3, + true => 6, + }; + + let tile_map_address: u16 = match self.bus[LCDC].get_bit(lcdc_bit) { false => 0x9800, true => 0x9C00, }; diff --git a/src/gpu/window.rs b/src/gpu/window.rs new file mode 100644 index 0000000..2dd7f05 --- /dev/null +++ b/src/gpu/window.rs @@ -0,0 +1,11 @@ +use crate::{common::Bit, consts::gpu::LCDC, GameBoy}; + +impl GameBoy { + pub(crate) fn can_render_window(&self) -> bool { + if !self.bus[LCDC].get_bit(0) || !self.bus[LCDC].get_bit(5) { + return false; + } + + true + } +}