diff --git a/src/cpu.rs b/src/cpu.rs index e652e5e..7c0592a 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -912,7 +912,10 @@ impl CPU { // cycle. let expected_cycles = start.elapsed().as_nanos() / (238 / 2); while cycles_executed < expected_cycles { - if let CpuTickResult::Continue { cycles_executed: x, .. } = self.run_instruction() { + if let CpuTickResult::Continue { + cycles_executed: x, .. + } = self.run_instruction() + { cycles_executed += x as u128; } else { return; @@ -1757,8 +1760,12 @@ impl CPU { } if self.interconnect.tick(cycles) == TickResult::Shutdown { - return CpuTickResult::Shutdown { cycles_executed: cycles as usize } + return CpuTickResult::Shutdown { + cycles_executed: cycles as usize, + }; + } + CpuTickResult::Continue { + cycles_executed: cycles as usize, } - CpuTickResult::Continue { cycles_executed: cycles as usize } } } diff --git a/src/display.rs b/src/display.rs index 516b7ca..a589085 100644 --- a/src/display.rs +++ b/src/display.rs @@ -60,6 +60,37 @@ const MONOCHROME_PALETTE: &'static [[u8; 3]; 4] = &[ [50, 50, 50], ]; +#[derive(Copy, Clone)] +struct CgbPalette([u8; 8]); +impl CgbPalette { + fn get_color(&self, n: usize) -> sdl2::pixels::Color { + let v = ((self.0[2 * n + 1] as u16) << 8) | (self.0[2 * n] as u16); + 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) + } +} + +struct BgMapAttributes(u8); +impl BgMapAttributes { + fn palette_number(&self) -> usize { + (self.0 & 0b111) as usize + } + + fn vram_bank_number(&self) -> usize { + (((self.0 >> 3) & 1) as usize) + } + + fn horizontal_flip(&self) -> bool { + (self.0 >> 5) != 0 + } + + fn vertical_flip(&self) -> bool { + (self.0 >> 6) != 0 + } +} + #[derive(Debug, Copy, Clone)] enum PixelOrigin { Empty, @@ -180,7 +211,7 @@ pub struct Display { // GBC: background_palette_autoinc: bool, background_palette_index: u8, - background_palette_c: [u8; 256], // 0x40], + background_palette_cgb: [CgbPalette; 0x40 / 8], object_palette_index: u8, } @@ -228,7 +259,7 @@ impl Display { background_palette_autoinc: false, background_palette_index: 0, - background_palette_c: [0u8; 256], // 0x40], + background_palette_cgb: [CgbPalette([0u8; 2 * 4]); 0x40 / 8], object_palette_index: 0, } } @@ -321,13 +352,17 @@ impl Display { 0xFF49 => self.object_palette[1] = val, // GBC 0xFF68 => { - self.background_palette_index = val; + self.background_palette_index = val & 0b0111_1111; self.background_palette_autoinc = (val >> 7) != 0; } 0xFF69 => { - self.background_palette_c[self.background_palette_index as usize] = val; + let idx = self.background_palette_index as usize; + self.background_palette_cgb[idx / 8].0[idx % 8] = val; if self.background_palette_autoinc { self.background_palette_index += 1; + if self.background_palette_index >= 8 { + self.background_palette_index = 0; + } } } 0xFF6A => { @@ -380,6 +415,26 @@ impl Display { } } + fn get_background_attribute( + &self, + //tile_index_x: usize, + //tile_index_y: usize, + vram_offset: usize, + ) -> BgMapAttributes { + /* + let background_map = if self.control & CTRL_BG_TILE_MAP_SELECT != 0 { + 0x1C00 + } else { + 0x1800 + }; + + let vram_offset: usize = + background_map + ((tile_index_y as usize) * 32) + tile_index_x as usize; + */ + + BgMapAttributes(self.vram1[vram_offset]) + } + #[inline] pub fn tick(&mut self, ticks: u16) { self.status &= 0xFC; @@ -594,18 +649,8 @@ impl Display { ); */ let c = ((b1 as u8) * 2 + b2 as u8) as usize; - let a = self.object_palette[sprite.palette() as usize * 8 + c * 2]; - let b = self.object_palette[sprite.palette() as usize * 8 + c * 2 + 1]; - let ab = ((b as u16) << 8) | a as u16; - let r = (ab & 0b11111) as u8; - let g = ((ab >> 5) & 0b11111) as u8; - let b = ((ab >> 10) & 0b11111) as u8; - self.set_pixel( - x.wrapping_add(x_o), - render_y, - sdl2::pixels::Color::RGB(r, g, b), - PixelOrigin::Sprite, - ); + 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); } } } @@ -681,9 +726,9 @@ impl Display { let render_abs_y = map_offset_y.wrapping_add(render_y); let tile_index_x: u8 = render_abs_x >> 3; - let tile_offset_x: u8 = render_abs_x & 7; - 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 = @@ -692,25 +737,53 @@ impl Display { // Obtain tile ID in this area let tile_id = self.vram0[vram_offset]; - // Obtain tile information - let tile_base_addr: usize = self.get_bg_window_tile_addr(tile_id); - let addr = tile_base_addr + (tile_offset_y as usize) * 2; - // GBC stuff - let vram = if (self.vram1[vram_offset] >> 3) == 1 { + let bg_attribs = self.get_background_attribute(vram_offset); + // Get BG map attributes + let vram = if bg_attribs.vram_bank_number() == 0 { &*self.vram0 } else { &*self.vram1 }; + // TODO: Priority + let tile_offset_y = if bg_attribs.vertical_flip() { + 7 ^ tile_offset_y + } else { + tile_offset_y + }; + + // Obtain tile information + let tile_base_addr: usize = self.get_bg_window_tile_addr(tile_id); + // TODO: Colored background + let addr = tile_base_addr + (tile_offset_y as usize) * 2; + let tile_line_1 = vram[addr]; let tile_line_2 = vram[addr + 1]; // Get the correct bit - let b1: bool = (tile_line_1 & 1 << (7 - tile_offset_x)) != 0; - let b2: bool = (tile_line_2 & 1 << (7 - tile_offset_x)) != 0; + let b1 = if bg_attribs.horizontal_flip() { + 7 ^ (1 << (7 - tile_offset_x)) + } else { + 1 << (7 - tile_offset_x) + }; + let b2 = if bg_attribs.horizontal_flip() { + 7 ^ (1 << (7 - tile_offset_x)) + } else { + 1 << (7 - tile_offset_x) + }; + let b1: bool = (tile_line_1 & b1) != 0; + let b2: bool = (tile_line_2 & b2) != 0; // Lookup the color + let c = ((b1 as u8) * 2 + b2 as u8) as usize; + let origin = match c { + 0 => PixelOrigin::Empty, // Hack so that objects will be in front of it. + _ => PixelOrigin::Background, + }; + let c = self.background_palette_cgb[bg_attribs.palette_number()].get_color(c); + self.set_pixel(render_x, render_y, c, origin); + /* let c = (b1 as u8) * 2 + b2 as u8; let lookup: [u8; 4] = [ self.background_palette & 3, @@ -730,6 +803,7 @@ impl Display { sdl2::pixels::Color::RGB(entry[0], entry[1], entry[2]), origin, ); + */ } } @@ -744,8 +818,8 @@ impl Display { let render_x = r_x.wrapping_add(rx); // Absolute render coordinates let tile_index_x: u8 = render_x >> 3; - let tile_offset_x: u8 = render_x & 7; let tile_index_y: u8 = ry >> 3; + let tile_offset_x: u8 = render_x & 7; let tile_offset_y: u8 = ry & 7; let vram_offset: usize = @@ -754,17 +828,49 @@ impl Display { // Obtain tile ID in this area let tile_id = self.vram0[vram_offset]; + let bg_attribs = self.get_background_attribute( + //tile_index_x as usize, tile_index_y as usize + vram_offset, + ); + + // Get BG map attributes + let vram = if bg_attribs.vram_bank_number() == 0 { + &*self.vram0 + } else { + &*self.vram1 + }; + + // TODO: Priority + let tile_offset_x = if bg_attribs.vertical_flip() { + 7 ^ tile_offset_x + } else { + tile_offset_x + }; + let tile_offset_y = if bg_attribs.horizontal_flip() { + 7 ^ tile_offset_y + } else { + tile_offset_y + }; + // Obtain tile information let tile_base_addr: usize = self.get_bg_window_tile_addr(tile_id); let tile_addr = tile_base_addr + (tile_offset_y as usize) * 2; - let tile_line_1 = self.vram0[tile_addr]; - let tile_line_2 = self.vram0[tile_addr + 1]; + let tile_line_1 = vram[tile_addr]; + let tile_line_2 = vram[tile_addr + 1]; // Get the correct bit let b1: bool = (tile_line_1 & 1 << (7 - tile_offset_x)) > 0; let b2: bool = (tile_line_2 & 1 << (7 - tile_offset_x)) > 0; let c = (b1 as u8) * 2 + b2 as u8; + let origin = match c { + 0 => PixelOrigin::Empty, // Hack so that objects will be in front of it. + _ => PixelOrigin::Window, + }; + let c = self.background_palette_cgb[bg_attribs.palette_number()] + .get_color(c as usize); + self.set_pixel(render_x, render_y, c, origin); + /* let lookup: [u8; 4] = [ self.background_palette & 3, (self.background_palette >> 2) & 3, @@ -784,6 +890,7 @@ impl Display { sdl2::pixels::Color::RGB(entry[0], entry[1], entry[2]), origin, ); + */ } } }