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;
|
||||
|
||||
//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_N_B: usize = 0;
|
||||
@ -874,7 +868,7 @@ impl CPU {
|
||||
}
|
||||
|
||||
pub fn run_instruction(&mut self) {
|
||||
//self.debug = !self.interconnect.is_boot_rom();
|
||||
// self.debug = !self.interconnect.is_boot_rom();
|
||||
/*
|
||||
if self.ip == 0x553 {
|
||||
self.debug = true;
|
||||
@ -1081,22 +1075,22 @@ impl CPU {
|
||||
|
||||
if self.flags & FLAG_N == 0 {
|
||||
// Lower nibble
|
||||
if self.flags & FLAG_H == FLAG_H || (v & 0xF) > 9 {
|
||||
if ((self.flags & FLAG_H) == FLAG_H) || (v & 0xF) > 9 {
|
||||
v += 0x06;
|
||||
}
|
||||
|
||||
// Higher nibble
|
||||
if self.flags & FLAG_C == FLAG_C || v > 0x9F {
|
||||
if ((self.flags & FLAG_C) == FLAG_C) || v > 0x9F {
|
||||
v += 0x60;
|
||||
}
|
||||
} else {
|
||||
// Lower nibble
|
||||
if self.flags & FLAG_H == FLAG_H {
|
||||
if (self.flags & FLAG_H) == FLAG_H {
|
||||
v = v.wrapping_sub(6) & 0xFF;
|
||||
}
|
||||
|
||||
// Higher nibble
|
||||
if self.flags & FLAG_C == FLAG_C {
|
||||
if (self.flags & FLAG_C) == FLAG_C {
|
||||
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)
|
||||
*/
|
||||
|
||||
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_X_FLIP: u8 = 1 << 5;
|
||||
const SPRITE_PALETTE_NO: u8 = 1 << 4; // NonCGB only
|
||||
@ -73,6 +73,24 @@ struct Sprite {
|
||||
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 {
|
||||
control: u8,
|
||||
status: u8,
|
||||
@ -255,7 +273,7 @@ impl Display {
|
||||
|
||||
// render frame.
|
||||
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();
|
||||
} else {
|
||||
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]
|
||||
fn renderscan(&mut self) {
|
||||
// Points to the background map offset to use.
|
||||
@ -314,27 +413,50 @@ impl Display {
|
||||
let map_offset_x: u8 = self.scrollx;
|
||||
|
||||
let render_y: u8 = self.curline;
|
||||
|
||||
if self.control & CTRL_BG_SPRITE_ENABLE > 0 {
|
||||
// panic!("Sprites not supported");
|
||||
// Order sprites by priority
|
||||
let mut queue: Vec<Sprite> = Vec::new();
|
||||
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
|
||||
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.
|
||||
/*
|
||||
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);
|
||||
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)
|
||||
for render_x in 0 .. 160 {
|
||||
// Absolute render coordinates
|
||||
@ -372,6 +494,9 @@ 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 {
|
||||
@ -381,112 +506,16 @@ impl Display {
|
||||
factor += 128;
|
||||
}
|
||||
|
||||
factor = 255 - factor;
|
||||
|
||||
// Draw stuff. We're currently only in monochrome mode
|
||||
self.set_pixel(render_x, render_y, sdl2::pixels::Color::RGB(factor, factor, factor));
|
||||
|
||||
}
|
||||
|
||||
if self.control & CTRL_BG_SPRITE_ENABLE > 0 {
|
||||
// Let's draw sprites.
|
||||
// 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));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
self.render_sprites(&queue, true);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user