Started work on palette support

This commit is contained in:
Kevin Hamacher 2016-06-01 19:55:26 +02:00
parent 509a76924a
commit 458fec99dd

View File

@ -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 {
}
}
}
}