From 876cdfdcb39f1538c73060a81a68a515225d2a66 Mon Sep 17 00:00:00 2001 From: Michel Heily Date: Mon, 15 Jul 2019 20:49:47 +0300 Subject: [PATCH] Implement MODE4 rendering, ArmWrestler renders now! Former-commit-id: 4910a63b454ae9309abc0aa584a7d0bc96143538 --- src/debugger/render_view.rs | 34 +++++++++++-------- src/debugger/tile_view.rs | 68 ++++++++++++++++++++++++------------- src/lcd.rs | 21 +++++++++++- 3 files changed, 84 insertions(+), 39 deletions(-) diff --git a/src/debugger/render_view.rs b/src/debugger/render_view.rs index 0c18936..99cfb94 100644 --- a/src/debugger/render_view.rs +++ b/src/debugger/render_view.rs @@ -1,3 +1,5 @@ +use std::time::Duration; + use sdl2::event::Event; use sdl2::pixels::Color; use sdl2::rect::Point; @@ -20,21 +22,6 @@ pub fn create_render_view(gba: &GameBoyAdvance) { let mut canvas = window.into_canvas().build().unwrap(); - canvas.set_draw_color(Color::RGB(0xfa, 0xfa, 0xfa)); - canvas.clear(); - - for y in 0..Lcd::DISPLAY_HEIGHT { - for x in 0..Lcd::DISPLAY_WIDTH { - let index = (x as usize) + (y as usize) * (256 as usize); - let color = gba.lcd.pixeldata[index]; - let rgb24: Color = color.into(); - canvas.set_draw_color(rgb24); - canvas.draw_point(Point::from((x as i32, y as i32))); - } - } - - canvas.present(); - let mut event_pump = sdl_context.event_pump().unwrap(); 'running: loop { for event in event_pump.poll_iter() { @@ -46,5 +33,22 @@ pub fn create_render_view(gba: &GameBoyAdvance) { _ => {} } } + + canvas.set_draw_color(Color::RGB(0xfa, 0xfa, 0xfa)); + canvas.clear(); + + for y in 0..Lcd::DISPLAY_HEIGHT { + for x in 0..Lcd::DISPLAY_WIDTH { + let index = (x as usize) + (y as usize) * (256 as usize); + let color = gba.lcd.pixeldata[index]; + let rgb24: Color = color.into(); + canvas.set_draw_color(rgb24); + canvas.draw_point(Point::from((x as i32, y as i32))); + } + } + + canvas.present(); + + ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60)); } } diff --git a/src/debugger/tile_view.rs b/src/debugger/tile_view.rs index ace8533..b2c580f 100644 --- a/src/debugger/tile_view.rs +++ b/src/debugger/tile_view.rs @@ -1,3 +1,5 @@ +use std::time::Duration; + use sdl2::event::Event; use sdl2::pixels::Color; use sdl2::rect::{Point, Rect}; @@ -48,6 +50,9 @@ fn draw_tile( } } +const TILESET_INITIAL_X: i32 = 0x20; +const TILESET_INITIAL_Y: i32 = 0x20; + pub fn create_tile_view(bg: u32, gba: &GameBoyAdvance) { let sdl_context = sdl2::init().unwrap(); let video_subsystem = sdl_context.video().unwrap(); @@ -60,9 +65,6 @@ pub fn create_tile_view(bg: u32, gba: &GameBoyAdvance) { let mut canvas = window.into_canvas().build().unwrap(); - canvas.set_draw_color(Color::RGB(00, 00, 00)); - canvas.clear(); - let bgcnt = BgControl::from(gba.sysbus.ioregs.read_reg(REG_BG0CNT + 2 * bg)); let palette = Palette::from(gba.sysbus.get_bytes(0x0500_0000)); @@ -73,33 +75,53 @@ pub fn create_tile_view(bg: u32, gba: &GameBoyAdvance) { let num_tiles = 0x4000 / tile_size; println!("tileset: {:#x}, tilemap: {:#x}", tileset_addr, tilemap_addr); - let mut tile_x = 0x20; - let mut tile_y = 0x20; - for t in 0..num_tiles { - let tile_addr = tileset_addr + t * tile_size; - if t != 0 && t % tiles_per_row == 0 { - tile_y += 10; - tile_x = 0x20; - } - tile_x += 10; - draw_tile( - gba, - tile_addr, - pixel_format, - Point::from((tile_x, tile_y)), - &mut canvas, - ); - } - - canvas.present(); - let mut event_pump = sdl_context.event_pump().unwrap(); 'running: loop { for event in event_pump.poll_iter() { match event { Event::Quit { .. } => break 'running, + Event::MouseButtonDown { x, y, .. } => { + let click_point = Point::new(x, y); + let mut tile_x = TILESET_INITIAL_X; + let mut tile_y = TILESET_INITIAL_Y; + for t in 0..num_tiles { + let tile_addr = tileset_addr + t * tile_size; + if t != 0 && t % tiles_per_row == 0 { + tile_y += 10; + tile_x = TILESET_INITIAL_Y; + } + tile_x += 10; + if Rect::new(tile_x, tile_y, 8, 8).contains_point(click_point) { + println!("tile #{:#x}, addr={:#x}", t, tile_addr); + } + } + } _ => {} } } + + + canvas.set_draw_color(Color::RGB(00, 00, 00)); + canvas.clear(); + + let mut tile_x = TILESET_INITIAL_X; + let mut tile_y = TILESET_INITIAL_Y; + for t in 0..num_tiles { + let tile_addr = tileset_addr + t * tile_size; + if t != 0 && t % tiles_per_row == 0 { + tile_y += 10; + tile_x = TILESET_INITIAL_Y; + } + tile_x += 10; + draw_tile( + gba, + tile_addr, + pixel_format, + Point::from((tile_x, tile_y)), + &mut canvas, + ); + } + canvas.present(); + ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60)); } } diff --git a/src/lcd.rs b/src/lcd.rs index fb48421..918e76f 100644 --- a/src/lcd.rs +++ b/src/lcd.rs @@ -313,9 +313,25 @@ impl Lcd { } } + fn scanline_mode4(&mut self, bg: u32, dispcnt: &DisplayControl, sysbus: &mut SysBus) { + let page: u32 = match dispcnt.display_frame { + 0 => 0x0600_0000, + 1 => 0x0600_a000, + _ => unreachable!() + }; + + let y = self.current_scanline; + + for x in 0..Self::DISPLAY_WIDTH { + let bitmap_index = x + y * Self::DISPLAY_WIDTH; + let bitmap_addr = page + (bitmap_index as u32); + let index = sysbus.read_8(bitmap_addr as Addr) as u32; + self.pixeldata[x + y * 256] = self.get_palette_color(sysbus, index, 0); + } + } + pub fn scanline(&mut self, sysbus: &mut SysBus) { let dispcnt = DisplayControl::from(sysbus.ioregs.read_reg(REG_DISPCNT)); - let dispstat = DisplayStatus::from(sysbus.ioregs.read_reg(REG_DISPSTAT)); match dispcnt.bg_mode { BGMode::BGMode0 | BGMode::BGMode2 => { @@ -325,6 +341,9 @@ impl Lcd { } } } + BGMode::BGMode4 => { + self.scanline_mode4(2, &dispcnt, sysbus); + } _ => panic!("{:?} not supported", dispcnt.bg_mode), } }