diff --git a/core/src/gpu/mod.rs b/core/src/gpu/mod.rs index 37c1d2a..97fed96 100644 --- a/core/src/gpu/mod.rs +++ b/core/src/gpu/mod.rs @@ -384,6 +384,10 @@ impl Gpu { self.render_mode4(2); self.finalize_scanline(2, 2); } + 5 => { + self.render_mode5(2); + self.finalize_scanline(2, 2); + } _ => panic!("{:?} not supported", self.dispcnt.mode()), } // self.mosaic_sfx(); diff --git a/core/src/gpu/render.rs b/core/src/gpu/render.rs index a884aa6..eed2449 100644 --- a/core/src/gpu/render.rs +++ b/core/src/gpu/render.rs @@ -36,6 +36,11 @@ pub(super) static SCREEN_VIEWPORT: ViewPort = ViewPort { w: DISPLAY_WIDTH as i32, h: DISPLAY_HEIGHT as i32, }; +pub(super) static MODE5_VIEWPORT: ViewPort = ViewPort { + origin: (0, 0), + w: 160, + h: 128, +}; pub(super) mod utils { use super::Point; diff --git a/core/src/gpu/render/bitmap.rs b/core/src/gpu/render/bitmap.rs index 641679f..ba9185c 100644 --- a/core/src/gpu/render/bitmap.rs +++ b/core/src/gpu/render/bitmap.rs @@ -4,7 +4,7 @@ use super::super::consts::*; use super::super::Gpu; use super::super::Rgb15; -use super::{utils, SCREEN_VIEWPORT}; +use super::{utils, MODE5_VIEWPORT, SCREEN_VIEWPORT}; use crate::Bus; @@ -16,13 +16,19 @@ impl Gpu { let pc = self.bg_aff[bg - 2].pc as i32; let ref_point = self.get_ref_point(bg); - for x in 0..DISPLAY_WIDTH { - let t = utils::transform_bg_point(ref_point, x as i32, pa, pc); - if !SCREEN_VIEWPORT.contains_point(t) { - self.backgrounds[bg].line[x] = Rgb15::TRANSPARENT; - continue; - } + let wraparound = self.backgrounds[bg].bgcnt.affine_wraparound(); + for x in 0..DISPLAY_WIDTH { + let mut t = utils::transform_bg_point(ref_point, x as i32, pa, pc); + if !SCREEN_VIEWPORT.contains_point(t) { + if wraparound { + t.0 = t.0.rem_euclid(SCREEN_VIEWPORT.w); + t.1 = t.1.rem_euclid(SCREEN_VIEWPORT.h); + } else { + self.backgrounds[bg].line[x] = Rgb15::TRANSPARENT; + continue; + } + } let pixel_index = index2d!(u32, t.0, t.1, DISPLAY_WIDTH); let pixel_ofs = 2 * pixel_index; let color = Rgb15(self.vram.read_16(pixel_ofs)); @@ -43,11 +49,18 @@ impl Gpu { let pc = self.bg_aff[bg - 2].pc as i32; let ref_point = self.get_ref_point(bg); + let wraparound = self.backgrounds[bg].bgcnt.affine_wraparound(); + for x in 0..DISPLAY_WIDTH { - let t = utils::transform_bg_point(ref_point, x as i32, pa, pc); + let mut t = utils::transform_bg_point(ref_point, x as i32, pa, pc); if !SCREEN_VIEWPORT.contains_point(t) { - self.backgrounds[bg].line[x] = Rgb15::TRANSPARENT; - continue; + if wraparound { + t.0 = t.0.rem_euclid(SCREEN_VIEWPORT.w); + t.1 = t.1.rem_euclid(SCREEN_VIEWPORT.h); + } else { + self.backgrounds[bg].line[x] = Rgb15::TRANSPARENT; + continue; + } } let bitmap_index = index2d!(u32, t.0, t.1, DISPLAY_WIDTH); let bitmap_ofs = page_ofs + (bitmap_index as u32); @@ -56,4 +69,36 @@ impl Gpu { self.backgrounds[bg].line[x] = color; } } + + pub(in super::super) fn render_mode5(&mut self, bg: usize) { + let page_ofs: u32 = match self.dispcnt.display_frame() { + 0 => 0x0600_0000 - VRAM_ADDR, + 1 => 0x0600_a000 - VRAM_ADDR, + _ => unreachable!(), + }; + + let _y = self.vcount; + + let pa = self.bg_aff[bg - 2].pa as i32; + let pc = self.bg_aff[bg - 2].pc as i32; + let ref_point = self.get_ref_point(bg); + + let wraparound = self.backgrounds[bg].bgcnt.affine_wraparound(); + + for x in 0..DISPLAY_WIDTH { + let mut t = utils::transform_bg_point(ref_point, x as i32, pa, pc); + if !MODE5_VIEWPORT.contains_point(t) { + if wraparound { + t.0 = t.0.rem_euclid(MODE5_VIEWPORT.w); + t.1 = t.1.rem_euclid(MODE5_VIEWPORT.h); + } else { + self.backgrounds[bg].line[x] = Rgb15::TRANSPARENT; + continue; + } + } + let pixel_ofs = page_ofs + 2 * index2d!(u32, t.0, t.1, MODE5_VIEWPORT.w); + let color = Rgb15(self.vram.read_16(pixel_ofs)); + self.backgrounds[bg].line[x] = color; + } + } }