From 4a059db349eeece7c1f14ff37692792c993531e9 Mon Sep 17 00:00:00 2001 From: velllu <91963404+velllu@users.noreply.github.com> Date: Wed, 13 Dec 2023 18:10:17 +0100 Subject: [PATCH] Implemented sprite `OBP0` and `OBP1` palette support --- src/consts.rs | 6 ++++-- src/gpu/mod.rs | 1 + src/gpu/oam_parser.rs | 26 +++++++++++++++----------- src/gpu/palette.rs | 40 ++++++++++++++++++++++++++++++++++++++++ src/gpu/states.rs | 8 +++++--- src/gpu/tile_parser.rs | 9 ++------- 6 files changed, 67 insertions(+), 23 deletions(-) create mode 100644 src/gpu/palette.rs diff --git a/src/consts.rs b/src/consts.rs index 201aebd..d4430cf 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -11,10 +11,12 @@ pub(crate) mod bus { } pub(crate) mod gpu { - pub(crate) const LY: u16 = 0xFF44; + pub(crate) const LCDC: u16 = 0xFF40; pub(crate) const SCY: u16 = 0xFF42; pub(crate) const SCX: u16 = 0xFF43; - pub(crate) const LCDC: u16 = 0xFF40; + pub(crate) const LY: u16 = 0xFF44; + pub(crate) const OBP0: u16 = 0xFF48; + pub(crate) const OBP1: u16 = 0xFF49; } pub(crate) mod display { diff --git a/src/gpu/mod.rs b/src/gpu/mod.rs index 2a3b3df..078f54b 100644 --- a/src/gpu/mod.rs +++ b/src/gpu/mod.rs @@ -1,4 +1,5 @@ pub(crate) mod oam_parser; +pub(crate) mod palette; pub(crate) mod states; pub mod tile_parser; diff --git a/src/gpu/oam_parser.rs b/src/gpu/oam_parser.rs index f3fb9d8..3dbacce 100644 --- a/src/gpu/oam_parser.rs +++ b/src/gpu/oam_parser.rs @@ -8,8 +8,8 @@ pub(crate) enum Priority { } pub(crate) enum Palette { - _0BP0, - _0BP1, + OBP0, + OBP1, } pub(crate) struct SpriteData { @@ -40,16 +40,17 @@ impl GameBoy { true => Priority::AboveLightColor, }, palette: match flags.get_bit(4) { - false => Palette::_0BP0, - true => Palette::_0BP1, + false => Palette::OBP0, + true => Palette::OBP1, }, x_flip: flags.get_bit(5), y_flip: flags.get_bit(6), } } - pub(crate) fn get_sprite_fifo(&self, x: u8, y: u8) -> Option { - let mut sprite_fifo: Option = None; + pub(crate) fn get_sprite_fifo(&self, x: u8, y: u8) -> Option<(Line, &SpriteData)> { + let mut sprite_fifo: Option<(Line, &SpriteData)> = None; + for sprite in &self.gpu.sprites { if sprite.y < 16 || sprite.x < 8 { continue; @@ -66,11 +67,14 @@ impl GameBoy { let y_condition = ((sprite_y)..(sprite_y + 7)).contains(&y); if x_condition && y_condition { - sprite_fifo = Some(self.get_line_rotation( - sprite.tile_number, - y as u16 % 8, - sprite.x_flip, - sprite.y_flip, + sprite_fifo = Some(( + self.get_line_rotation( + sprite.tile_number, + y as u16 % 8, + sprite.x_flip, + sprite.y_flip, + ), + sprite, )); } } diff --git a/src/gpu/palette.rs b/src/gpu/palette.rs new file mode 100644 index 0000000..77b7731 --- /dev/null +++ b/src/gpu/palette.rs @@ -0,0 +1,40 @@ +use crate::{ + common::Bit, + consts::gpu::{OBP0, OBP1}, + GameBoy, +}; + +use super::{oam_parser::Palette, tile_parser::Line, Color}; + +pub(crate) fn bools_to_color(bool1: bool, bool2: bool) -> Color { + match (bool1, bool2) { + (false, false) => Color::Light, + (false, true) => Color::MediumlyLight, + (true, false) => Color::MediumlyDark, + (true, true) => Color::Dark, + } +} + +impl GameBoy { + pub(crate) fn apply_palette_to_sprite(&self, line: &mut Line, palette: &Palette) { + let palette = match palette { + Palette::OBP0 => self.bus[OBP0], + Palette::OBP1 => self.bus[OBP1], + }; + + let id_1 = bools_to_color(palette.get_bit(3), palette.get_bit(2)); + let id_2 = bools_to_color(palette.get_bit(5), palette.get_bit(4)); + let id_3 = bools_to_color(palette.get_bit(7), palette.get_bit(6)); + + for pixel in line.colors.iter_mut() { + *pixel = match pixel { + Color::MediumlyLight => id_1, + Color::MediumlyDark => id_2, + Color::Dark => id_3, + + // Light will not change because light just means transparent in a sprite + Color::Light => Color::Light, + } + } + } +} diff --git a/src/gpu/states.rs b/src/gpu/states.rs index 1f3a822..52205ec 100644 --- a/src/gpu/states.rs +++ b/src/gpu/states.rs @@ -7,7 +7,7 @@ use crate::{ GameBoy, }; -use super::{oam_parser::SpriteData, tile_parser::Line, Color}; +use super::{oam_parser::SpriteData, Color}; #[derive(PartialEq)] pub enum GPUState { @@ -96,10 +96,12 @@ impl GameBoy { // And we get both background/window fifo and the sprite fifo let background_fifo = self.get_line(self.bus[tile_map_address], self.gpu.y as u16 % 8); - let sprite_fifo: Option = self.get_sprite_fifo(self.gpu.x, self.gpu.y); + let mut sprite_fifo = self.get_sprite_fifo(self.gpu.x, self.gpu.y); // TODO: Implement fifo mixing - if let Some(sprite_fifo) = sprite_fifo { + if let Some((sprite_fifo, sprite_data)) = &mut sprite_fifo { + self.apply_palette_to_sprite(sprite_fifo, &sprite_data.palette); + if self.gpu.rendered_sprites_on_line < 10 { self.draw_line(&sprite_fifo, self.gpu.x as usize, self.gpu.y as usize); self.gpu.rendered_sprites_on_line += 1; diff --git a/src/gpu/tile_parser.rs b/src/gpu/tile_parser.rs index ab77c15..6bd7f69 100644 --- a/src/gpu/tile_parser.rs +++ b/src/gpu/tile_parser.rs @@ -1,6 +1,6 @@ use crate::{common::Bit, consts::gpu::LCDC, GameBoy}; -use super::Color; +use super::{palette::bools_to_color, Color}; pub struct Line { pub colors: [Color; 8], @@ -37,12 +37,7 @@ impl Line { let num1_bit = num1.get_bit(7 - bit_offset); let num2_bit = num2.get_bit(7 - bit_offset); - self.colors[bit_offset as usize] = match (num1_bit, num2_bit) { - (false, false) => Color::Light, - (false, true) => Color::MediumlyLight, - (true, false) => Color::MediumlyDark, - (true, true) => Color::Dark, - }; + self.colors[bit_offset as usize] = bools_to_color(num1_bit, num2_bit); } } }