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 libc;
|
||||||
extern crate sdl2;
|
extern crate sdl2;
|
||||||
|
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
// Internal ram size
|
// Internal ram size
|
||||||
const VRAM_SIZE: usize = 0x2000;
|
const VRAM_SIZE: usize = 0x2000;
|
||||||
|
|
||||||
@ -71,7 +73,15 @@ impl CgbPalette {
|
|||||||
let r = (v & 0b1_1111) as u8;
|
let r = (v & 0b1_1111) as u8;
|
||||||
let g = ((v >> 5) & 0b1_1111) as u8;
|
let g = ((v >> 5) & 0b1_1111) as u8;
|
||||||
let b = ((v >> 10) & 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,
|
vram_bank: u8,
|
||||||
current_ticks: u16,
|
current_ticks: u16,
|
||||||
current_mode: DisplayMode,
|
current_mode: DisplayMode,
|
||||||
// TODO
|
|
||||||
renderer: sdl2::render::Canvas<sdl2::video::Window>,
|
renderer: sdl2::render::Canvas<sdl2::video::Window>,
|
||||||
|
|
||||||
pub event_pump: sdl2::EventPump,
|
pub event_pump: sdl2::EventPump,
|
||||||
@ -216,7 +226,9 @@ pub struct Display {
|
|||||||
background_palette_index: u8,
|
background_palette_index: u8,
|
||||||
background_palette_cgb: [CgbPalette; 0x40 / 8],
|
background_palette_cgb: [CgbPalette; 0x40 / 8],
|
||||||
|
|
||||||
|
object_palette_autoinc: bool,
|
||||||
object_palette_index: u8,
|
object_palette_index: u8,
|
||||||
|
object_palette_cgb: [CgbPalette; 0x40 / 8],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display {
|
impl Display {
|
||||||
@ -263,7 +275,9 @@ impl Display {
|
|||||||
background_palette_autoinc: false,
|
background_palette_autoinc: false,
|
||||||
background_palette_index: 0,
|
background_palette_index: 0,
|
||||||
background_palette_cgb: [CgbPalette([0u8; 2 * 4]); 0x40 / 8],
|
background_palette_cgb: [CgbPalette([0u8; 2 * 4]); 0x40 / 8],
|
||||||
|
object_palette_autoinc: false,
|
||||||
object_palette_index: 0,
|
object_palette_index: 0,
|
||||||
|
object_palette_cgb: [CgbPalette([0u8; 2 * 4]); 0x40 / 8],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,19 +374,29 @@ impl Display {
|
|||||||
}
|
}
|
||||||
0xFF69 => {
|
0xFF69 => {
|
||||||
let idx = self.background_palette_index as usize;
|
let idx = self.background_palette_index as usize;
|
||||||
|
if idx < 64 {
|
||||||
self.background_palette_cgb[idx / 8].0[idx % 8] = val;
|
self.background_palette_cgb[idx / 8].0[idx % 8] = val;
|
||||||
|
} else {
|
||||||
|
panic!("OOB palette w/ autoinc");
|
||||||
|
}
|
||||||
if self.background_palette_autoinc {
|
if self.background_palette_autoinc {
|
||||||
self.background_palette_index += 1;
|
self.background_palette_index += 1;
|
||||||
if self.background_palette_index >= 8 {
|
|
||||||
self.background_palette_index = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0xFF6A => {
|
0xFF6A => {
|
||||||
self.object_palette_index = val;
|
self.object_palette_index = val & 0b0111_1111;
|
||||||
|
self.object_palette_autoinc = (val >> 7) != 0;
|
||||||
}
|
}
|
||||||
0xFF6B => {
|
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 => {
|
0xFF4A => {
|
||||||
if self.windowy != val {
|
if self.windowy != val {
|
||||||
@ -557,20 +581,25 @@ impl Display {
|
|||||||
|
|
||||||
// Calculate correct coords
|
// Calculate correct coords
|
||||||
let x: u8 = sprite.x.wrapping_sub(8);
|
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 y: u8 = sprite.y.wrapping_sub(16);
|
||||||
|
|
||||||
let render_y = self.curline;
|
let render_y = self.curline;
|
||||||
|
|
||||||
// Is this sprite on the current line?
|
// 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;
|
||||||
num_rendered += 1;
|
let actual_h = match wide_mode {
|
||||||
// Flip sprite, TODO: Validate
|
true => 16,
|
||||||
let y_o: u8 = match sprite.is_y_flipped() {
|
false => 8,
|
||||||
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?
|
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 tile_addr = tile_base_addr + tile_offset_y * 2;
|
||||||
let vram = if sprite.vram_bank() == 0 {
|
let vram = if sprite.vram_bank() == 0 {
|
||||||
@ -580,16 +609,8 @@ impl Display {
|
|||||||
};
|
};
|
||||||
let tile_line_1 = vram[tile_addr + 0];
|
let tile_line_1 = vram[tile_addr + 0];
|
||||||
let tile_line_2 = vram[tile_addr + 1];
|
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.
|
for x_o in 0..8 {
|
||||||
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 {
|
|
||||||
let b1: bool;
|
let b1: bool;
|
||||||
let b2: bool;
|
let b2: bool;
|
||||||
|
|
||||||
@ -604,21 +625,12 @@ impl Display {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if wide_mode && x_o > 7 {
|
let x_maybe_flipped: u8 = match sprite.is_x_flipped() {
|
||||||
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,
|
true => x_o ^ 7,
|
||||||
false => x_o,
|
false => x_o,
|
||||||
};
|
};
|
||||||
b1 = (tile_line_1 & 1 << (7 - x_o2)) > 0;
|
b1 = (tile_line_1 & 1 << (7 - x_o)) > 0;
|
||||||
b2 = (tile_line_2 & 1 << (7 - x_o2)) > 0;
|
b2 = (tile_line_2 & 1 << (7 - x_o)) > 0;
|
||||||
}
|
|
||||||
|
|
||||||
// Sprites may be transparent.
|
// Sprites may be transparent.
|
||||||
if !b1 && !b2 {
|
if !b1 && !b2 {
|
||||||
@ -654,8 +666,11 @@ impl Display {
|
|||||||
);
|
);
|
||||||
*/
|
*/
|
||||||
let c = ((b1 as u8) * 2 + b2 as u8) as usize;
|
let c = ((b1 as u8) * 2 + b2 as u8) as usize;
|
||||||
let c = self.background_palette_cgb[sprite.palette() as usize].get_color(c);
|
if c == 0 {
|
||||||
self.set_pixel(x.wrapping_add(x_o), render_y, c, PixelOrigin::Sprite);
|
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
|
// Render background
|
||||||
if (self.control & CTRL_BG_DISPLAY) == CTRL_BG_DISPLAY {
|
if (self.control & CTRL_BG_DISPLAY) == CTRL_BG_DISPLAY {
|
||||||
// Render pixels (20 tiles)
|
// 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 {
|
for render_x in 0..160 {
|
||||||
// Absolute render coordinates
|
// Absolute render coordinates
|
||||||
let render_abs_x = map_offset_x.wrapping_add(render_x);
|
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_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_x: u8 = render_abs_x & 7;
|
||||||
let tile_offset_y: u8 = render_abs_y & 7;
|
|
||||||
|
|
||||||
let vram_offset: usize =
|
let vram_offset: usize =
|
||||||
background_map + ((tile_index_y as usize) * 32) + tile_index_x as usize;
|
background_map + ((tile_index_y as usize) * 32) + tile_index_x as usize;
|
||||||
|
|||||||
@ -174,6 +174,7 @@ impl Interconnect {
|
|||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
self.cartridge.save();
|
self.cartridge.save();
|
||||||
|
self.display.dump_vram();
|
||||||
return TickResult::Shutdown;
|
return TickResult::Shutdown;
|
||||||
}
|
}
|
||||||
Event::KeyDown {
|
Event::KeyDown {
|
||||||
@ -361,14 +362,14 @@ impl Interconnect {
|
|||||||
self.sound
|
self.sound
|
||||||
.sound_object
|
.sound_object
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.expect("Sound-related crash")
|
||||||
.write_byte(addr, val);
|
.write_byte(addr, val);
|
||||||
}
|
}
|
||||||
0xFF30..=0xFF3F => self
|
0xFF30..=0xFF3F => self
|
||||||
.sound
|
.sound
|
||||||
.sound_object
|
.sound_object
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.expect("Sound related crash")
|
||||||
.write_byte(addr, val),
|
.write_byte(addr, val),
|
||||||
// Exclude DMA transfer, we will do this below
|
// Exclude DMA transfer, we will do this below
|
||||||
0xFF40..=0xFF45 | 0xFF47..=0xFF4B => {
|
0xFF40..=0xFF45 | 0xFF47..=0xFF4B => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user