diff --git a/src/display.rs b/src/display.rs index 7300a65..0fc6bd1 100644 --- a/src/display.rs +++ b/src/display.rs @@ -34,6 +34,24 @@ const STAT_MODE_OAM_INT: u8 = 1 << 5; const STAT_MODE_VBLANK_INT: u8 = 1 << 4; const STAT_MODE_HBLANK_INT: u8 = 1 << 3; +// Sprite flags +/* + Bit7 OBJ-to-BG Priority (0=OBJ Above BG, 1=OBJ Behind BG color 1-3) + (Used for both BG and Window. BG color 0 is always behind OBJ) + Bit6 Y flip (0=Normal, 1=Vertically mirrored) + Bit5 X flip (0=Normal, 1=Horizontally mirrored) + Bit4 Palette number **Non CGB Mode Only** (0=OBP0, 1=OBP1) + Bit3 Tile VRAM-Bank **CGB Mode Only** (0=Bank 0, 1=Bank 1) + Bit2-0 Palette number **CGB Mode Only** (OBP0-7) +*/ + +const SPRITE_OBC_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 +const SPRITE_TILE_VRAM_BANK: u8 = 1 << 3; // CGB only + + #[derive(Debug)] enum DisplayMode { ReadOAMMemory, @@ -48,6 +66,13 @@ impl Default for DisplayMode { } } +struct Sprite { + x: u8, + y: u8, + tile: u8, + flags: u8, +} + pub struct Display { control: u8, status: u8, @@ -369,11 +394,37 @@ impl Display { if self.control & CTRL_BG_SPRITE_SIZE > 0 { println!("Wide sprites not tested!"); } + + // Order sprites by priority + let mut queue: Vec = Vec::new(); for i in 0 .. 39 { - let mut y: u8 = self.oam[i * 4 + 0]; - let mut x: u8 = self.oam[i * 4 + 1]; - let t_num: u8 = self.oam[i * 4 + 2]; - let flags: u8 = self.oam[i * 4 + 3]; + 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 @@ -385,7 +436,11 @@ impl Display { // Is this sprite on the current line? if y.wrapping_add(8) >= render_y && y <= render_y { - let tile_offset_y: usize = render_y as usize - y as usize; + 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]; @@ -403,12 +458,18 @@ impl Display { 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_o)) > 0; - b2 = (tile_line_4 & 1 << (14 - x_o)) > 0; + 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_o)) > 0; - b2 = (tile_line_2 & 1 << (7 - x_o)) > 0; + b1 = (tile_line_1 & 1 << (7 - x_o2)) > 0; + b2 = (tile_line_2 & 1 << (7 - x_o2)) > 0; } if b1 { diff --git a/src/mbc/mbc3.rs b/src/mbc/mbc3.rs index e076ab8..4c1c229 100644 --- a/src/mbc/mbc3.rs +++ b/src/mbc/mbc3.rs @@ -42,7 +42,6 @@ impl MBC for MBC3 { let addr = addr - 0xA000; match self.active_ram_bank() { 0x00 ... 0x03 => { - println!("MBC3: Access RAM [{:02X}] {:04X}", self.ram_bank_no, addr); self.ram[self.active_ram_bank() as usize * 0x2000 + addr as usize] } 0x08 ... 0x0C => { @@ -89,7 +88,6 @@ impl MBC for MBC3 { let addr = addr - 0xA000; match self.active_ram_bank() { 0x00 ... 0x03 => { - println!("MBC3: Writing RAM [{:02X}] {:04X} = {:02X}", self.ram_bank_no, addr, val); let active_bank = self.active_ram_bank() as usize; self.ram[active_bank * 0x2000 + addr as usize] = val; } diff --git a/src/sound.rs b/src/sound.rs index cc0c918..6a6313d 100644 --- a/src/sound.rs +++ b/src/sound.rs @@ -7,6 +7,11 @@ pub struct Sound { sound_output_terminal_selector: u8, sound_freq_low: u8, sound_freq_high: u8, + + channel2_sound_length: u8, + channel2_volume: u8, + channel2_freq_lo: u8, + channel2_freq_hi: u8, } impl Sound { @@ -20,6 +25,12 @@ impl Sound { 0xFF12 => self.sound_control_1 = val, 0xFF13 => self.sound_freq_low = val, 0xFF14 => self.sound_freq_high = val, + + 0xFF16 => self.channel2_sound_length = val, + 0xFF17 => self.channel2_volume = val, + 0xFF18 => self.channel2_freq_lo = val, + 0xFF19 => self.channel2_freq_hi = val, + 0xFF24 => self.sound_channel_volume_control = val, 0xFF25 => self.sound_output_terminal_selector = val, 0xFF26 => self.enabled = val, @@ -35,6 +46,12 @@ impl Sound { 0xFF12 => self.sound_control_1, 0xFF13 => self.sound_freq_low, 0xFF14 => self.sound_freq_high, + + 0xFF16 => self.channel2_sound_length, + 0xFF17 => self.channel2_volume, + 0xFF18 => self.channel2_freq_lo, + 0xFF19 => self.channel2_freq_hi, + 0xFF24 => self.sound_channel_volume_control, 0xFF25 => self.sound_output_terminal_selector, 0xFF26 => self.enabled,