sprite cleanup part 1
This commit is contained in:
parent
8c0ef5529c
commit
509a76924a
16
src/cpu.rs
16
src/cpu.rs
@ -1,11 +1,5 @@
|
|||||||
use super::interconnect;
|
use super::interconnect;
|
||||||
|
|
||||||
//const REG_B: usize = 0;
|
|
||||||
//const REG_C: usize = 1;
|
|
||||||
//const REG_D: usize = 2;
|
|
||||||
//const REG_E: usize = 3;
|
|
||||||
//const REG_H: usize = 4;
|
|
||||||
//const REG_L: usize = 5;
|
|
||||||
const REG_A: usize = 6;
|
const REG_A: usize = 6;
|
||||||
|
|
||||||
const REG_N_B: usize = 0;
|
const REG_N_B: usize = 0;
|
||||||
@ -874,7 +868,7 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_instruction(&mut self) {
|
pub fn run_instruction(&mut self) {
|
||||||
//self.debug = !self.interconnect.is_boot_rom();
|
// self.debug = !self.interconnect.is_boot_rom();
|
||||||
/*
|
/*
|
||||||
if self.ip == 0x553 {
|
if self.ip == 0x553 {
|
||||||
self.debug = true;
|
self.debug = true;
|
||||||
@ -1081,22 +1075,22 @@ impl CPU {
|
|||||||
|
|
||||||
if self.flags & FLAG_N == 0 {
|
if self.flags & FLAG_N == 0 {
|
||||||
// Lower nibble
|
// Lower nibble
|
||||||
if self.flags & FLAG_H == FLAG_H || (v & 0xF) > 9 {
|
if ((self.flags & FLAG_H) == FLAG_H) || (v & 0xF) > 9 {
|
||||||
v += 0x06;
|
v += 0x06;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Higher nibble
|
// Higher nibble
|
||||||
if self.flags & FLAG_C == FLAG_C || v > 0x9F {
|
if ((self.flags & FLAG_C) == FLAG_C) || v > 0x9F {
|
||||||
v += 0x60;
|
v += 0x60;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Lower nibble
|
// Lower nibble
|
||||||
if self.flags & FLAG_H == FLAG_H {
|
if (self.flags & FLAG_H) == FLAG_H {
|
||||||
v = v.wrapping_sub(6) & 0xFF;
|
v = v.wrapping_sub(6) & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Higher nibble
|
// Higher nibble
|
||||||
if self.flags & FLAG_C == FLAG_C {
|
if (self.flags & FLAG_C) == FLAG_C {
|
||||||
v = v.wrapping_sub(0x60);
|
v = v.wrapping_sub(0x60);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
261
src/display.rs
261
src/display.rs
@ -45,7 +45,7 @@ const STAT_MODE_HBLANK_INT: u8 = 1 << 3;
|
|||||||
Bit2-0 Palette number **CGB Mode Only** (OBP0-7)
|
Bit2-0 Palette number **CGB Mode Only** (OBP0-7)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const SPRITE_OBC_BG_PRIORITY: u8 = 1 << 7;
|
const SPRITE_OBJ_BG_PRIORITY: u8 = 1 << 7;
|
||||||
const SPRITE_Y_FLIP: u8 = 1 << 6;
|
const SPRITE_Y_FLIP: u8 = 1 << 6;
|
||||||
const SPRITE_X_FLIP: u8 = 1 << 5;
|
const SPRITE_X_FLIP: u8 = 1 << 5;
|
||||||
const SPRITE_PALETTE_NO: u8 = 1 << 4; // NonCGB only
|
const SPRITE_PALETTE_NO: u8 = 1 << 4; // NonCGB only
|
||||||
@ -73,6 +73,24 @@ struct Sprite {
|
|||||||
flags: u8,
|
flags: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Sprite {
|
||||||
|
fn is_hidden(&self) -> bool {
|
||||||
|
self.x == 0 || self.y == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_foreground(&self) -> bool {
|
||||||
|
self.flags & SPRITE_OBJ_BG_PRIORITY == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_x_flipped(&self) -> bool {
|
||||||
|
self.flags & SPRITE_X_FLIP == SPRITE_X_FLIP
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_y_flipped(&self) -> bool {
|
||||||
|
self.flags & SPRITE_Y_FLIP == SPRITE_Y_FLIP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Display {
|
pub struct Display {
|
||||||
control: u8,
|
control: u8,
|
||||||
status: u8,
|
status: u8,
|
||||||
@ -255,7 +273,7 @@ impl Display {
|
|||||||
|
|
||||||
// render frame.
|
// render frame.
|
||||||
self.renderer.present();
|
self.renderer.present();
|
||||||
self.renderer.set_draw_color(sdl2::pixels::Color::RGB(0, 0, 0));
|
self.renderer.set_draw_color(sdl2::pixels::Color::RGB(255, 255, 255));
|
||||||
self.renderer.clear();
|
self.renderer.clear();
|
||||||
} else {
|
} else {
|
||||||
self.current_mode = DisplayMode::ReadOAMMemory; // Mode 2 again
|
self.current_mode = DisplayMode::ReadOAMMemory; // Mode 2 again
|
||||||
@ -298,6 +316,87 @@ impl Display {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_sprites(&mut self, sprites: &Vec<Sprite>, foreground: bool) {
|
||||||
|
if self.control & CTRL_BG_SPRITE_ENABLE > 0 {
|
||||||
|
for i in 0 .. 39 {
|
||||||
|
let sprite = &sprites[i];
|
||||||
|
|
||||||
|
if sprite.is_hidden() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if foreground && !sprite.is_foreground() {
|
||||||
|
continue;
|
||||||
|
} else if !foreground && sprite.is_foreground() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let x: u8 = sprite.x.wrapping_sub(8);
|
||||||
|
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 {
|
||||||
|
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_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];
|
||||||
|
let tile_line_3 = self.vram[tile_base_addr + tile_offset_y * 2 + 2];
|
||||||
|
let tile_line_4 = self.vram[tile_base_addr + tile_offset_y * 2 + 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 {
|
||||||
|
let b1: bool;
|
||||||
|
let b2: bool;
|
||||||
|
let mut factor = 0;
|
||||||
|
|
||||||
|
let x_o2: u8 = match sprite.is_x_flipped() {
|
||||||
|
true => x_o ^ 7,
|
||||||
|
false => x_o,
|
||||||
|
};
|
||||||
|
|
||||||
|
if wide_mode && x_o > 7 {
|
||||||
|
b1 = (tile_line_3 & 1 << (14 - x_o2)) > 0;
|
||||||
|
b2 = (tile_line_4 & 1 << (14 - x_o2)) > 0;
|
||||||
|
} else {
|
||||||
|
b1 = (tile_line_1 & 1 << (7 - x_o2)) > 0;
|
||||||
|
b2 = (tile_line_2 & 1 << (7 - x_o2)) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if b1 {
|
||||||
|
factor += 64;
|
||||||
|
}
|
||||||
|
if b2 {
|
||||||
|
factor += 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transparent.
|
||||||
|
if !b1 && !b2 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
factor = 255 - factor;
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn renderscan(&mut self) {
|
fn renderscan(&mut self) {
|
||||||
// Points to the background map offset to use.
|
// Points to the background map offset to use.
|
||||||
@ -314,27 +413,50 @@ impl Display {
|
|||||||
let map_offset_x: u8 = self.scrollx;
|
let map_offset_x: u8 = self.scrollx;
|
||||||
|
|
||||||
let render_y: u8 = self.curline;
|
let render_y: u8 = self.curline;
|
||||||
|
// Order sprites by priority
|
||||||
if self.control & CTRL_BG_SPRITE_ENABLE > 0 {
|
let mut queue: Vec<Sprite> = Vec::new();
|
||||||
// panic!("Sprites not supported");
|
for i in 0 .. 39 {
|
||||||
|
queue.push(Sprite{
|
||||||
|
y: self.oam[i * 4 + 0],
|
||||||
|
x: self.oam[i * 4 + 1],
|
||||||
|
tile: self.oam[i * 4 + 2],
|
||||||
|
flags: self.oam[i * 4 + 3],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is the non-CGB priority.
|
||||||
|
// Smaller x coord = higher.
|
||||||
|
use std::cmp;
|
||||||
|
queue.sort_by(|x, y| {
|
||||||
|
if x.x > y.x {
|
||||||
|
cmp::Ordering::Greater
|
||||||
|
} else if x.x < y.x {
|
||||||
|
cmp::Ordering::Less
|
||||||
|
} else {
|
||||||
|
cmp::Ordering::Equal
|
||||||
|
}
|
||||||
|
});
|
||||||
|
queue.reverse();
|
||||||
|
|
||||||
|
|
||||||
|
// Draw sprites behind the background
|
||||||
|
self.render_sprites(&queue, false);
|
||||||
|
|
||||||
// Render background
|
// Render background
|
||||||
if self.control & CTRL_BG_DISPLAY > 0 {
|
if self.control & CTRL_BG_DISPLAY > 0 {
|
||||||
|
// Draw borders if enabled
|
||||||
|
if false {
|
||||||
|
for t_x in 0 .. 160/8 {
|
||||||
|
self.renderer.set_draw_color(sdl2::pixels::Color::RGB(0xFF, 10, 0xFF));
|
||||||
|
|
||||||
// Draw borders first.
|
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;
|
||||||
for t_x in 0 .. 160/8 {
|
let TS: u32 = 8u32 * (SCALE as u32);
|
||||||
self.renderer.set_draw_color(sdl2::pixels::Color::RGB(0xFF, 10, 0xFF));
|
self.renderer.draw_rect(
|
||||||
|
sdl2::rect::Rect::new(RX * SCALE as i32, RY * SCALE as i32, TS, TS)
|
||||||
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)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
// Render pixels (20 tiles)
|
// Render pixels (20 tiles)
|
||||||
for render_x in 0 .. 160 {
|
for render_x in 0 .. 160 {
|
||||||
// Absolute render coordinates
|
// Absolute render coordinates
|
||||||
@ -372,6 +494,9 @@ impl Display {
|
|||||||
// Get the correct bit
|
// Get the correct bit
|
||||||
let b1: bool = (tile_line_1 & 1 << (7 - tile_offset_x)) > 0;
|
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 b2: bool = (tile_line_2 & 1 << (7 - tile_offset_x)) > 0;
|
||||||
|
if !b1 && !b2 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let mut factor = 0;
|
let mut factor = 0;
|
||||||
if b1 {
|
if b1 {
|
||||||
@ -381,112 +506,16 @@ impl Display {
|
|||||||
factor += 128;
|
factor += 128;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
factor = 255 - factor;
|
||||||
|
|
||||||
// Draw stuff. We're currently only in monochrome mode
|
// 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(factor, factor, factor));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.control & CTRL_BG_SPRITE_ENABLE > 0 {
|
if self.control & CTRL_BG_SPRITE_ENABLE > 0 {
|
||||||
// Let's draw sprites.
|
self.render_sprites(&queue, true);
|
||||||
// TODO: Sprites with smaller X coordinate should
|
|
||||||
// should be in front
|
|
||||||
// TODO: Draw only up to 10 sprites per line
|
|
||||||
if self.control & CTRL_BG_SPRITE_SIZE > 0 {
|
|
||||||
println!("Wide sprites not tested!");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Order sprites by priority
|
|
||||||
let mut queue: Vec<Sprite> = Vec::new();
|
|
||||||
for i in 0 .. 39 {
|
|
||||||
queue.push(Sprite{
|
|
||||||
x: self.oam[i * 4 + 0],
|
|
||||||
y: self.oam[i * 4 + 1],
|
|
||||||
tile: self.oam[i * 4 + 2],
|
|
||||||
flags: self.oam[i * 4 + 3],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is the non-CGB priority.
|
|
||||||
// Smaller x coord = higher.
|
|
||||||
use std::cmp;
|
|
||||||
queue.sort_by(|x, y| {
|
|
||||||
if x.x > y.x {
|
|
||||||
cmp::Ordering::Greater
|
|
||||||
} else if x.x < y.x {
|
|
||||||
cmp::Ordering::Less
|
|
||||||
} else {
|
|
||||||
cmp::Ordering::Equal
|
|
||||||
}
|
|
||||||
});
|
|
||||||
queue.reverse();
|
|
||||||
|
|
||||||
for i in 0 .. 39 {
|
|
||||||
let mut y: u8 = queue[i].x;
|
|
||||||
let mut x: u8 = queue[i].y;
|
|
||||||
let t_num: u8 = queue[i].tile;
|
|
||||||
let flags: u8 = queue[i].flags;
|
|
||||||
|
|
||||||
if x == 0 || y == 0 {
|
|
||||||
// This sprite is hidden
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
x = x.wrapping_sub(8);
|
|
||||||
y = y.wrapping_sub(16);
|
|
||||||
|
|
||||||
// Is this sprite on the current line?
|
|
||||||
if y.wrapping_add(8) >= render_y && y <= render_y {
|
|
||||||
let y_o: u8 = match flags & SPRITE_Y_FLIP == SPRITE_Y_FLIP {
|
|
||||||
true => y ^ 7,
|
|
||||||
false => y
|
|
||||||
};
|
|
||||||
let tile_offset_y: usize = render_y as usize - y_o as usize;
|
|
||||||
let tile_base_addr: usize = 0 + t_num as usize * 16;
|
|
||||||
|
|
||||||
let tile_line_1 = self.vram[tile_base_addr + tile_offset_y * 2];
|
|
||||||
let tile_line_2 = self.vram[tile_base_addr + tile_offset_y * 2 + 1];
|
|
||||||
let tile_line_3 = self.vram[tile_base_addr + tile_offset_y * 2 + 2];
|
|
||||||
let tile_line_4 = self.vram[tile_base_addr + tile_offset_y * 2 + 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 {
|
|
||||||
let b1: bool;
|
|
||||||
let b2: bool;
|
|
||||||
let mut factor = 0;
|
|
||||||
|
|
||||||
let x_o2: u8 = match flags & SPRITE_X_FLIP == SPRITE_X_FLIP {
|
|
||||||
true => x_o ^ 7,
|
|
||||||
false => x_o,
|
|
||||||
};
|
|
||||||
|
|
||||||
if wide_mode && x_o > 7 {
|
|
||||||
b1 = (tile_line_3 & 1 << (14 - x_o2)) > 0;
|
|
||||||
b2 = (tile_line_4 & 1 << (14 - x_o2)) > 0;
|
|
||||||
} else {
|
|
||||||
b1 = (tile_line_1 & 1 << (7 - x_o2)) > 0;
|
|
||||||
b2 = (tile_line_2 & 1 << (7 - x_o2)) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if b1 {
|
|
||||||
factor += 64;
|
|
||||||
}
|
|
||||||
if b2 {
|
|
||||||
factor += 128;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user