From 458fec99dd79785a2d817b8505e05314905df397 Mon Sep 17 00:00:00 2001 From: Kevin Hamacher Date: Wed, 1 Jun 2016 19:55:26 +0200 Subject: [PATCH] Started work on palette support --- src/display.rs | 118 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 81 insertions(+), 37 deletions(-) diff --git a/src/display.rs b/src/display.rs index 28818ba..c619966 100644 --- a/src/display.rs +++ b/src/display.rs @@ -51,6 +51,12 @@ const SPRITE_X_FLIP: u8 = 1 << 5; const SPRITE_PALETTE_NO: u8 = 1 << 4; // NonCGB only const SPRITE_TILE_VRAM_BANK: u8 = 1 << 3; // CGB only +const MONOCHROME_PALETTE: &'static [[f64; 3]; 4] = &[ + [0.605, 0.734, 0.059], + [0.543, 0.672, 0.059], + [0.188, 0.383, 0.188], + [0.059, 0.219, 0.059], +]; #[derive(Debug)] enum DisplayMode { @@ -89,6 +95,14 @@ impl Sprite { fn is_y_flipped(&self) -> bool { self.flags & SPRITE_Y_FLIP == SPRITE_Y_FLIP } + + fn palette(&self) -> u8 { + if self.flags & SPRITE_PALETTE_NO == 0 { + 0 + } else { + 1 + } + } } pub struct Display { @@ -156,7 +170,8 @@ impl Display { #[inline] fn set_pixel(&mut self, x: u8, y: u8, color: sdl2::pixels::Color) { self.renderer.set_draw_color(color); - self.renderer.fill_rect(sdl2::rect::Rect::new((x as i32) * SCALE as i32, (y as i32) * SCALE as i32, SCALE as u32, SCALE as u32)); + self.renderer.fill_rect(sdl2::rect::Rect::new((x as i32) * SCALE as i32, (y as i32) * SCALE as i32, SCALE as u32, SCALE as u32)) + .expect("Draw failed"); } #[inline] @@ -198,11 +213,26 @@ impl Display { 0xFF43 => self.scrollx = val, 0xFF44 => self.curline = 0, 0xFF45 => self.lyc = val, - 0xFF47 => self.background_palette = val, - 0xFF48 => self.object_palette_0 = val, - 0xFF49 => self.object_palette_1 = val, - 0xFF4A => self.windowy = val, - 0xFF4B => self.windowx = val, + 0xFF47 => { + println!("BG PALETTE = {:02X}", val); + self.background_palette = val; + } + 0xFF48 => { + println!("OBJ0 PALETTE = {:02X}", val); + self.object_palette_0 = val; + } + 0xFF49 => { + println!("OBJ1 PALETTE = {:02X}", val); + self.object_palette_1 = val; + } + 0xFF4A => { + println!("WY set to {:02X}", val); + self.windowy = val; + } + 0xFF4B => { + println!("WX set to {:02X}", val); + self.windowx = val; + } _ => panic!("Display: Write {:02X} to {:04X} unsupported", val, addr), } } @@ -321,16 +351,19 @@ impl Display { for i in 0 .. 39 { let sprite = &sprites[i]; + // Skip hidden sprites if sprite.is_hidden() { continue; } + // Should we draw this sprite this iteration if foreground && !sprite.is_foreground() { continue; } else if !foreground && sprite.is_foreground() { continue; } + // Calculate correct coords let x: u8 = sprite.x.wrapping_sub(8); let y: u8 = sprite.y.wrapping_sub(16); @@ -338,12 +371,13 @@ impl Display { // Is this sprite on the current line? if y.wrapping_add(8) >= render_y && y <= render_y { + // 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; + let tile_base_addr: usize = sprite.tile as usize * 16; // Should this be twice as wide in wide mode? let tile_line_1 = self.vram[tile_base_addr + tile_offset_y * 2 + 1]; let tile_line_2 = self.vram[tile_base_addr + tile_offset_y * 2 + 1]; @@ -352,6 +386,9 @@ impl Display { // We need to draw this. let wide_mode = self.control & CTRL_BG_SPRITE_SIZE > 0; + if wide_mode { + panic!("TODO"); + } let limit = match wide_mode { true => 16, false => 8 @@ -374,23 +411,36 @@ impl Display { b2 = (tile_line_2 & 1 << (7 - x_o2)) > 0; } - if b1 { - factor += 64; - } - if b2 { - factor += 128; - } + // -> self.background_palette. + //0xFF47 => self.background_palette = val, + //0xFF48 => self.object_palette_0 = val, + //0xFF49 => self.object_palette_1 = val, - // Transparent. + // Sprites may be transparent. if !b1 && !b2 { continue; } - factor = 255 - factor; + let c = (b1 as u8) * 2 + b2 as u8; + let lookup: [u8; 4] = match sprite.palette() { + 0 => [ + self.object_palette_0 & 3, + (self.object_palette_0 >> 2) & 3, + (self.object_palette_0 >> 4) & 3, + (self.object_palette_0 >> 6) & 3, + ], + 1 => [ + self.object_palette_1 & 3, + (self.object_palette_1 >> 2) & 3, + (self.object_palette_1 >> 4) & 3, + (self.object_palette_1 >> 6) & 3, + ], + _ => unreachable!(), + }; + let entry = MONOCHROME_PALETTE[lookup[c as usize] as usize]; // Draw stuff. We're currently only in monochrome mode - self.set_pixel(x.wrapping_add(x_o), render_y, sdl2::pixels::Color::RGB(factor, factor, factor)); - + self.set_pixel(x.wrapping_add(x_o), render_y, sdl2::pixels::Color::RGB((entry[0]*255.0) as u8, (entry[1]*255.0) as u8, (entry[2]*255.0) as u8)); } } } @@ -449,12 +499,12 @@ impl Display { for t_x in 0 .. 160/8 { self.renderer.set_draw_color(sdl2::pixels::Color::RGB(0xFF, 10, 0xFF)); - let RX: i32 = (t_x as i32)*8 + map_offset_x as i32; - let RY: i32 = ((render_y as u32) & 0xFFFFFFF8) as i32 - map_offset_y as i32; - let TS: u32 = 8u32 * (SCALE as u32); + let rx: i32 = (t_x as i32)*8 + map_offset_x as i32; + let ry: i32 = ((render_y as u32) & 0xFFFFFFF8) as i32 - map_offset_y as i32; + let ts: u32 = 8u32 * (SCALE as u32); self.renderer.draw_rect( - sdl2::rect::Rect::new(RX * SCALE as i32, RY * SCALE as i32, TS, TS) - ); + sdl2::rect::Rect::new(rx * SCALE as i32, ry * SCALE as i32, ts, ts) + ).expect("Draw failed"); } } // Render pixels (20 tiles) @@ -494,23 +544,18 @@ impl Display { // 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; - if !b1 && !b2 { - continue; - } - let mut factor = 0; - if b1 { - factor += 64; - } - if b2 { - factor += 128; - } - - factor = 255 - factor; + let c = (b1 as u8) * 2 + b2 as u8; + let lookup: [u8; 4] = [ + self.background_palette & 3, + (self.background_palette >> 2) & 3, + (self.background_palette >> 4) & 3, + (self.background_palette >> 6) & 3, + ]; + let entry = MONOCHROME_PALETTE[lookup[c as usize] as usize]; // Draw stuff. We're currently only in monochrome mode - self.set_pixel(render_x, render_y, sdl2::pixels::Color::RGB(factor, factor, factor)); - + self.set_pixel(render_x, render_y, sdl2::pixels::Color::RGB((entry[0]*255.0) as u8, (entry[1]*255.0) as u8, (entry[2]*255.0) as u8)); } if self.control & CTRL_BG_SPRITE_ENABLE > 0 { @@ -518,5 +563,4 @@ impl Display { } } } - }