diff --git a/Cargo.lock b/Cargo.lock index 60e06d4..046f41c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -989,6 +989,7 @@ name = "gb-emu-lib" version = "0.1.0" dependencies = [ "async-ringbuf", + "bytemuck", "futures", "itertools", "once_cell", diff --git a/lib/Cargo.toml b/lib/Cargo.toml index e5c7cbc..29d72ce 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -15,3 +15,4 @@ once_cell = "1.17.1" itertools = "0.10.5" serde = { version = "1.0", features = ["derive"] } serde_with = "2.3.1" +bytemuck = "1.13" diff --git a/lib/src/processor/memory/mmio/gpu.rs b/lib/src/processor/memory/mmio/gpu.rs index 24ef072..bd19c06 100644 --- a/lib/src/processor/memory/mmio/gpu.rs +++ b/lib/src/processor/memory/mmio/gpu.rs @@ -5,8 +5,8 @@ use self::{ cgb::CgbData, tile_window::TileWindow, types::{ - GpuInterrupts, Lcdc, Oam, ObjPalette, ObjSize, Object, ObjectFlags, Palette, Stat, - TiledataArea, TilemapArea, Vram, + ColourInner, GpuInterrupts, Lcdc, Oam, ObjPalette, ObjSize, Object, ObjectFlags, Palette, + Stat, TiledataArea, TilemapArea, Vram, }, }; use crate::{ @@ -132,7 +132,7 @@ where } else { None }; - let buffer = vec![Colour::Error.into(); WIDTH * HEIGHT]; + let buffer = vec![ColourInner::Error.rgb_bytes(None).into(); WIDTH * HEIGHT]; Self { buffer, @@ -315,7 +315,8 @@ where *e = true; } for x in 0..WIDTH { - self.buffer[(scanline as usize * WIDTH) + x] = Colour::Error.into(); + self.buffer[(scanline as usize * WIDTH) + x] = + ColourInner::Error.rgb_bytes(None).into(); } if self.lcdc.bg_window_enable { self.render_scanline_bg(scanline); @@ -328,7 +329,8 @@ where } } else { for x in 0..WIDTH { - self.buffer[(scanline as usize * WIDTH) + x] = Colour::Error.into(); + self.buffer[(scanline as usize * WIDTH) + x] = + ColourInner::Error.rgb_bytes(None).into(); } } if self.lcdc.obj_enable { @@ -449,7 +451,9 @@ where if x_coord < WIDTH { let buffer_index = (scanline as usize * WIDTH) + x_coord; if !object.flags.behind_bg_and_window || self.is_bg_zero[x_coord] { - self.buffer[buffer_index] = colour.into(); + let cgb_data = self.cgb_data.as_ref().map(|v| (v.palettes.obj, 0)); + + self.buffer[buffer_index] = colour.rgb_bytes(cgb_data).into(); } } } @@ -495,7 +499,9 @@ where let (colour, is_zero) = self.bg_palette.map_bits(lsb, msb); self.is_bg_zero[x] = is_zero; - self.buffer[(scanline as usize * WIDTH) + x] = colour.into(); + let cgb_data = self.cgb_data.as_ref().map(|v| (v.palettes.bg, 0)); + + self.buffer[(scanline as usize * WIDTH) + x] = colour.rgb_bytes(cgb_data).into(); } } diff --git a/lib/src/processor/memory/mmio/gpu/cgb.rs b/lib/src/processor/memory/mmio/gpu/cgb.rs index e4a819b..bde2341 100644 --- a/lib/src/processor/memory/mmio/gpu/cgb.rs +++ b/lib/src/processor/memory/mmio/gpu/cgb.rs @@ -10,8 +10,8 @@ use super::{Colour, Gpu}; #[derive(Serialize, Deserialize, Clone, Copy)] pub(super) struct CgbData { - palettes: CgbPaletteRegisters, - object_priority_mode: ObjectPriorityMode, + pub(super) palettes: CgbPaletteRegisters, + pub(super) object_priority_mode: ObjectPriorityMode, } impl Default for CgbData { @@ -24,24 +24,24 @@ impl Default for CgbData { } #[derive(Serialize, Deserialize, Clone, Copy)] -enum ObjectPriorityMode { +pub(super) enum ObjectPriorityMode { OamLocation = 0, Coordinate = 1, } #[derive(Serialize, Deserialize, Clone, Copy, Default)] -struct CgbPaletteRegisters { - bg: CgbPalette, - obj: CgbPalette, +pub(super) struct CgbPaletteRegisters { + pub(super) bg: CgbPalette, + pub(super) obj: CgbPalette, } #[serde_with::serde_as] #[derive(Serialize, Deserialize, Clone, Copy)] -struct CgbPalette { +pub(super) struct CgbPalette { auto_increment: bool, index: u8, #[serde_as(as = "[_; 0x40]")] - data: [u8; 0x40], + pub(super) data: [u8; 0x40], } impl Default for CgbPalette { diff --git a/lib/src/processor/memory/mmio/gpu/tile_window.rs b/lib/src/processor/memory/mmio/gpu/tile_window.rs index eac80cd..dd1e3c4 100644 --- a/lib/src/processor/memory/mmio/gpu/tile_window.rs +++ b/lib/src/processor/memory/mmio/gpu/tile_window.rs @@ -4,7 +4,10 @@ use crate::{ util::get_bit, }; -use super::{types::Vram, Colour}; +use super::{ + types::{ColourInner, Vram}, + Colour, +}; pub(super) struct TileWindow where @@ -22,7 +25,10 @@ where { pub(super) fn new(window: R) -> Self { Self { - sprite_buffer: vec![Colour::Error.into(); TILE_WINDOW_WIDTH * TILE_WINDOW_HEIGHT], + sprite_buffer: vec![ + ColourInner::Error.rgb_bytes(None).into(); + TILE_WINDOW_WIDTH * TILE_WINDOW_HEIGHT + ], sprite_renderer: window, } } @@ -72,7 +78,7 @@ where let colour = palette.map_bits(lsb, msb); self.sprite_buffer[real_px_x + (real_px_y * TILE_WINDOW_WIDTH)] = - colour.0.into(); + colour.0.rgb_bytes(None).into(); } } } diff --git a/lib/src/processor/memory/mmio/gpu/types.rs b/lib/src/processor/memory/mmio/gpu/types.rs index cfca622..62f1600 100644 --- a/lib/src/processor/memory/mmio/gpu/types.rs +++ b/lib/src/processor/memory/mmio/gpu/types.rs @@ -1,3 +1,4 @@ +use bytemuck::from_bytes; use serde::{Deserialize, Serialize}; use crate::{ @@ -5,6 +6,8 @@ use crate::{ util::{as_signed, get_bit}, }; +use super::cgb::CgbPalette; + #[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)] pub(crate) enum DrawMode { HBlank, @@ -89,75 +92,92 @@ impl Default for Lcdc { } #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] -pub enum Colour { - White, - LightGray, - DarkGray, - Black, - Error, +pub enum ColourInner { + Zero = 0, + One = 1, + Two = 2, + Three = 3, + Error = 255, } +pub struct Colour(u8, u8, u8); + impl From for u32 { fn from(value: Colour) -> Self { - let rgb = value.rgb_bytes(); - let (r, g, b) = (rgb.0 as u32, rgb.1 as u32, rgb.2 as u32); + let (r, g, b) = (value.0 as u32, value.1 as u32, value.2 as u32); (r << 16) | (g << 8) | b } } impl From for [u8; 4] { fn from(value: Colour) -> Self { - let (r, g, b) = value.rgb_bytes(); + let Colour(r, g, b) = value; [r, g, b, 0xFF] } } -impl Colour { - fn rgb_bytes(&self) -> (u8, u8, u8) { - match self { - Colour::White => (0xFF, 0xFF, 0xFF), - Colour::LightGray => (0xAA, 0xAA, 0xAA), - Colour::DarkGray => (0x55, 0x55, 0x55), - Colour::Black => (0x00, 0x00, 0x00), - Colour::Error => (0xFF, 0x00, 0x00), +fn rgb_from_bytes(bytes: u16) -> Colour { + let blue = (((bytes & (0b11111 << 10)) >> 10) << 3) as u8; + let green = (((bytes & (0b11111 << 5)) >> 5) << 3) as u8; + let red = ((bytes & 0b11111) << 3) as u8; + Colour(red, green, blue) +} + +impl ColourInner { + pub(super) fn rgb_bytes(&self, cgb_data: Option<(CgbPalette, u8)>) -> Colour { + if let Some((cgb_palette, pallete_num)) = cgb_data { + if *self == ColourInner::Error { + return Colour(0xFF, 0, 0); + } + let offset: usize = (pallete_num as usize * 2 * 4) + (*self as usize * 2); + + rgb_from_bytes(*from_bytes(&cgb_palette.data[offset..=offset + 1])) + } else { + match self { + ColourInner::Zero => Colour(0xFF, 0xFF, 0xFF), + ColourInner::One => Colour(0xAA, 0xAA, 0xAA), + ColourInner::Two => Colour(0x55, 0x55, 0x55), + ColourInner::Three => Colour(0x00, 0x00, 0x00), + ColourInner::Error => Colour(0xFF, 0x00, 0x00), + } } } - pub(super) fn from_bits(first: bool, second: bool) -> Colour { + pub(super) fn from_bits(first: bool, second: bool) -> ColourInner { match (first, second) { - (true, true) => Colour::Black, - (true, false) => Colour::LightGray, - (false, true) => Colour::DarkGray, - (false, false) => Colour::White, + (true, true) => ColourInner::Three, + (true, false) => ColourInner::One, + (false, true) => ColourInner::Two, + (false, false) => ColourInner::Zero, } } fn as_bits(&self) -> u8 { match self { - Colour::White => 0b00, - Colour::LightGray => 0b01, - Colour::DarkGray => 0b10, - Colour::Black => 0b11, - Colour::Error => 0b00, + ColourInner::Zero => 0b00, + ColourInner::One => 0b01, + ColourInner::Two => 0b10, + ColourInner::Three => 0b11, + ColourInner::Error => 0b00, } } } #[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub(super) struct Palette { - pub(super) zero: Colour, - pub(super) one: Colour, - pub(super) two: Colour, - pub(super) three: Colour, + pub(super) zero: ColourInner, + pub(super) one: ColourInner, + pub(super) two: ColourInner, + pub(super) three: ColourInner, } impl Palette { pub(super) fn from_byte(byte: u8) -> Palette { Palette { - zero: Colour::from_bits(get_bit(byte, 0), get_bit(byte, 1)), - one: Colour::from_bits(get_bit(byte, 2), get_bit(byte, 3)), - two: Colour::from_bits(get_bit(byte, 4), get_bit(byte, 5)), - three: Colour::from_bits(get_bit(byte, 6), get_bit(byte, 7)), + zero: ColourInner::from_bits(get_bit(byte, 0), get_bit(byte, 1)), + one: ColourInner::from_bits(get_bit(byte, 2), get_bit(byte, 3)), + two: ColourInner::from_bits(get_bit(byte, 4), get_bit(byte, 5)), + three: ColourInner::from_bits(get_bit(byte, 6), get_bit(byte, 7)), } } @@ -168,7 +188,7 @@ impl Palette { | (self.three.as_bits() << 6) } - pub(super) fn map_bits(&self, lsb: bool, msb: bool) -> (Colour, bool) { + pub(super) fn map_bits(&self, lsb: bool, msb: bool) -> (ColourInner, bool) { match (lsb, msb) { (true, true) => (self.three, false), (true, false) => (self.one, false),