From 2bbcba21522f4942b71a0acbbe805854d9f23e27 Mon Sep 17 00:00:00 2001 From: Kevin Hamacher Date: Tue, 18 Feb 2020 15:40:03 +0100 Subject: [PATCH] Fix sprite color & wide sprites --- src/display.rs | 110 +++++++++++++++++++++++++------------------- src/interconnect.rs | 5 +- 2 files changed, 65 insertions(+), 50 deletions(-) diff --git a/src/display.rs b/src/display.rs index 2d94b86..9aa2ecc 100644 --- a/src/display.rs +++ b/src/display.rs @@ -1,6 +1,8 @@ extern crate libc; extern crate sdl2; +use std::io::Write; + // Internal ram size const VRAM_SIZE: usize = 0x2000; @@ -71,7 +73,15 @@ impl CgbPalette { let r = (v & 0b1_1111) as u8; let g = ((v >> 5) & 0b1_1111) as u8; let b = ((v >> 10) & 0b1_1111) as u8; - sdl2::pixels::Color::RGB(r << 3, g << 3, b << 3) + // According to some code: + // Real colors: + let r = r as u16; + let g = g as u16; + let b = b as u16; + let rR = ((r * 13 + g * 2 + b) >> 1) as u8; + let rG = ((g * 3 + b) << 1) as u8; + let rB = ((r * 3 + g * 2 + b * 11) >> 1) as u8; + sdl2::pixels::Color::RGB(rR, rG, rB) } } @@ -198,7 +208,7 @@ pub struct Display { vram_bank: u8, current_ticks: u16, current_mode: DisplayMode, - // TODO + renderer: sdl2::render::Canvas, pub event_pump: sdl2::EventPump, @@ -216,7 +226,9 @@ pub struct Display { background_palette_index: u8, background_palette_cgb: [CgbPalette; 0x40 / 8], + object_palette_autoinc: bool, object_palette_index: u8, + object_palette_cgb: [CgbPalette; 0x40 / 8], } impl Display { @@ -263,7 +275,9 @@ impl Display { background_palette_autoinc: false, background_palette_index: 0, background_palette_cgb: [CgbPalette([0u8; 2 * 4]); 0x40 / 8], + object_palette_autoinc: false, object_palette_index: 0, + object_palette_cgb: [CgbPalette([0u8; 2 * 4]); 0x40 / 8], } } @@ -360,19 +374,29 @@ impl Display { } 0xFF69 => { let idx = self.background_palette_index as usize; - self.background_palette_cgb[idx / 8].0[idx % 8] = val; + if idx < 64 { + self.background_palette_cgb[idx / 8].0[idx % 8] = val; + } else { + panic!("OOB palette w/ autoinc"); + } if self.background_palette_autoinc { self.background_palette_index += 1; - if self.background_palette_index >= 8 { - self.background_palette_index = 0; - } } } 0xFF6A => { - self.object_palette_index = val; + self.object_palette_index = val & 0b0111_1111; + self.object_palette_autoinc = (val >> 7) != 0; } 0xFF6B => { - self.object_palette[self.object_palette_index as usize] = val; + let idx = self.object_palette_index as usize; + if idx < 64 { + self.object_palette_cgb[idx / 8].0[idx % 8] = val; + } else { + panic!("OOB obj palette w/ autoinc"); + } + if self.object_palette_autoinc { + self.object_palette_index += 1; + } } 0xFF4A => { if self.windowy != val { @@ -557,20 +581,25 @@ impl Display { // Calculate correct coords let x: u8 = sprite.x.wrapping_sub(8); + // Flip sprite, TODO: What does this do in WIDE mode? let y: u8 = sprite.y.wrapping_sub(16); - let render_y = self.curline; // Is this sprite on the current line? - if y.wrapping_add(8) > render_y && y <= render_y { + let wide_mode = self.control & CTRL_BG_SPRITE_SIZE > 0; + let actual_h = match wide_mode { + true => 16, + false => 8, + }; + + if sprite.is_y_flipped() { + panic!("Sorry, no y flip support yet"); + } + + if y.wrapping_add(actual_h) > render_y && y <= render_y { num_rendered += 1; - // Flip sprite, TODO: Validate - let y_o: u8 = match sprite.is_y_flipped() { - true => y ^ 7, - false => y, - }; - let tile_offset_y: usize = render_y as usize - y_o as usize; - let tile_base_addr: usize = sprite.tile as usize * 16; // Should this be twice as wide in wide mode? + let tile_offset_y: usize = render_y as usize - y as usize; + let tile_base_addr: usize = sprite.tile as usize * 16; let tile_addr = tile_base_addr + tile_offset_y * 2; let vram = if sprite.vram_bank() == 0 { @@ -580,16 +609,8 @@ impl Display { }; let tile_line_1 = vram[tile_addr + 0]; let tile_line_2 = vram[tile_addr + 1]; - let tile_line_3 = vram[tile_addr + 2]; - let tile_line_4 = vram[tile_addr + 3]; - // We need to draw this. - let wide_mode = self.control & CTRL_BG_SPRITE_SIZE > 0; - let limit = match wide_mode { - true => 16, - false => 8, - }; - for x_o in 0..limit { + for x_o in 0..8 { let b1: bool; let b2: bool; @@ -604,21 +625,12 @@ impl Display { } } - if wide_mode && x_o > 7 { - let x_o2: u8 = match sprite.is_x_flipped() { - true => (x_o - 8) ^ 7, - false => (x_o - 8), - }; - b1 = (tile_line_3 & 1 << (7 - x_o2)) > 0; - b2 = (tile_line_4 & 1 << (7 - x_o2)) > 0; - } else { - let x_o2: u8 = match sprite.is_x_flipped() { - true => x_o ^ 7, - false => x_o, - }; - b1 = (tile_line_1 & 1 << (7 - x_o2)) > 0; - b2 = (tile_line_2 & 1 << (7 - x_o2)) > 0; - } + let x_maybe_flipped: u8 = match sprite.is_x_flipped() { + true => x_o ^ 7, + false => x_o, + }; + b1 = (tile_line_1 & 1 << (7 - x_o)) > 0; + b2 = (tile_line_2 & 1 << (7 - x_o)) > 0; // Sprites may be transparent. if !b1 && !b2 { @@ -654,8 +666,11 @@ impl Display { ); */ let c = ((b1 as u8) * 2 + b2 as u8) as usize; - let c = self.background_palette_cgb[sprite.palette() as usize].get_color(c); - self.set_pixel(x.wrapping_add(x_o), render_y, c, PixelOrigin::Sprite); + if c == 0 { + continue; + } + let c = self.object_palette_cgb[sprite.palette() as usize].get_color(c); + self.set_pixel(x.wrapping_add(x_maybe_flipped), render_y, c, PixelOrigin::Sprite); } } } @@ -730,16 +745,15 @@ impl Display { // Render background if (self.control & CTRL_BG_DISPLAY) == CTRL_BG_DISPLAY { // Render pixels (20 tiles) + let render_abs_y = map_offset_y.wrapping_add(render_y); + let tile_index_y: u8 = render_abs_y >> 3; + let tile_offset_y: u8 = render_abs_y & 7; + for render_x in 0..160 { // Absolute render coordinates let render_abs_x = map_offset_x.wrapping_add(render_x); - let render_abs_y = map_offset_y.wrapping_add(render_y); - let tile_index_x: u8 = render_abs_x >> 3; - let tile_index_y: u8 = render_abs_y >> 3; - let tile_offset_x: u8 = render_abs_x & 7; - let tile_offset_y: u8 = render_abs_y & 7; let vram_offset: usize = background_map + ((tile_index_y as usize) * 32) + tile_index_x as usize; diff --git a/src/interconnect.rs b/src/interconnect.rs index 7430cd0..3cb1659 100644 --- a/src/interconnect.rs +++ b/src/interconnect.rs @@ -174,6 +174,7 @@ impl Interconnect { .. } => { self.cartridge.save(); + self.display.dump_vram(); return TickResult::Shutdown; } Event::KeyDown { @@ -361,14 +362,14 @@ impl Interconnect { self.sound .sound_object .lock() - .unwrap() + .expect("Sound-related crash") .write_byte(addr, val); } 0xFF30..=0xFF3F => self .sound .sound_object .lock() - .unwrap() + .expect("Sound related crash") .write_byte(addr, val), // Exclude DMA transfer, we will do this below 0xFF40..=0xFF45 | 0xFF47..=0xFF4B => {