Fix sprite color & wide sprites
This commit is contained in:
parent
261fa4d78a
commit
2bbcba2152
102
src/display.rs
102
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<sdl2::video::Window>,
|
||||
|
||||
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;
|
||||
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 {
|
||||
num_rendered += 1;
|
||||
// Flip sprite, TODO: Validate
|
||||
let y_o: u8 = match sprite.is_y_flipped() {
|
||||
true => y ^ 7,
|
||||
false => y,
|
||||
let wide_mode = self.control & CTRL_BG_SPRITE_SIZE > 0;
|
||||
let actual_h = match wide_mode {
|
||||
true => 16,
|
||||
false => 8,
|
||||
};
|
||||
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?
|
||||
|
||||
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;
|
||||
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() {
|
||||
let x_maybe_flipped: 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;
|
||||
}
|
||||
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;
|
||||
|
||||
@ -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 => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user