core/gpu: Impl bitmap mode 5 and properly handle wraparound for bitmap modes.

resolves #90


Former-commit-id: 633580870e2d44d95a8b53b6311232f0fad48bd9
Former-commit-id: aa2ba32116900f635f12f9dcc9d29344367711eb
This commit is contained in:
Michel Heily 2020-05-30 14:32:03 +03:00
parent 90e492d81a
commit 1b1b855702
3 changed files with 64 additions and 10 deletions

View file

@ -384,6 +384,10 @@ impl Gpu {
self.render_mode4(2); self.render_mode4(2);
self.finalize_scanline(2, 2); self.finalize_scanline(2, 2);
} }
5 => {
self.render_mode5(2);
self.finalize_scanline(2, 2);
}
_ => panic!("{:?} not supported", self.dispcnt.mode()), _ => panic!("{:?} not supported", self.dispcnt.mode()),
} }
// self.mosaic_sfx(); // self.mosaic_sfx();

View file

@ -36,6 +36,11 @@ pub(super) static SCREEN_VIEWPORT: ViewPort = ViewPort {
w: DISPLAY_WIDTH as i32, w: DISPLAY_WIDTH as i32,
h: DISPLAY_HEIGHT 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 { pub(super) mod utils {
use super::Point; use super::Point;

View file

@ -4,7 +4,7 @@ use super::super::consts::*;
use super::super::Gpu; use super::super::Gpu;
use super::super::Rgb15; use super::super::Rgb15;
use super::{utils, SCREEN_VIEWPORT}; use super::{utils, MODE5_VIEWPORT, SCREEN_VIEWPORT};
use crate::Bus; use crate::Bus;
@ -16,13 +16,19 @@ impl Gpu {
let pc = self.bg_aff[bg - 2].pc as i32; let pc = self.bg_aff[bg - 2].pc as i32;
let ref_point = self.get_ref_point(bg); let ref_point = self.get_ref_point(bg);
let wraparound = self.backgrounds[bg].bgcnt.affine_wraparound();
for x in 0..DISPLAY_WIDTH { 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) { 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; self.backgrounds[bg].line[x] = Rgb15::TRANSPARENT;
continue; continue;
} }
}
let pixel_index = index2d!(u32, t.0, t.1, DISPLAY_WIDTH); let pixel_index = index2d!(u32, t.0, t.1, DISPLAY_WIDTH);
let pixel_ofs = 2 * pixel_index; let pixel_ofs = 2 * pixel_index;
let color = Rgb15(self.vram.read_16(pixel_ofs)); let color = Rgb15(self.vram.read_16(pixel_ofs));
@ -43,12 +49,19 @@ impl Gpu {
let pc = self.bg_aff[bg - 2].pc as i32; let pc = self.bg_aff[bg - 2].pc as i32;
let ref_point = self.get_ref_point(bg); let ref_point = self.get_ref_point(bg);
let wraparound = self.backgrounds[bg].bgcnt.affine_wraparound();
for x in 0..DISPLAY_WIDTH { 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) { 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; self.backgrounds[bg].line[x] = Rgb15::TRANSPARENT;
continue; continue;
} }
}
let bitmap_index = index2d!(u32, t.0, t.1, DISPLAY_WIDTH); let bitmap_index = index2d!(u32, t.0, t.1, DISPLAY_WIDTH);
let bitmap_ofs = page_ofs + (bitmap_index as u32); let bitmap_ofs = page_ofs + (bitmap_index as u32);
let index = self.vram.read_8(bitmap_ofs) as u32; let index = self.vram.read_8(bitmap_ofs) as u32;
@ -56,4 +69,36 @@ impl Gpu {
self.backgrounds[bg].line[x] = color; 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;
}
}
} }