automatic palettes work
This commit is contained in:
parent
7fba9cca89
commit
27e0374181
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -989,6 +989,7 @@ name = "gb-emu-lib"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-ringbuf",
|
"async-ringbuf",
|
||||||
|
"bytemuck",
|
||||||
"futures",
|
"futures",
|
||||||
"itertools",
|
"itertools",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
|
|
@ -15,3 +15,4 @@ once_cell = "1.17.1"
|
||||||
itertools = "0.10.5"
|
itertools = "0.10.5"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_with = "2.3.1"
|
serde_with = "2.3.1"
|
||||||
|
bytemuck = "1.13"
|
||||||
|
|
|
@ -5,8 +5,8 @@ use self::{
|
||||||
cgb::CgbData,
|
cgb::CgbData,
|
||||||
tile_window::TileWindow,
|
tile_window::TileWindow,
|
||||||
types::{
|
types::{
|
||||||
GpuInterrupts, Lcdc, Oam, ObjPalette, ObjSize, Object, ObjectFlags, Palette, Stat,
|
ColourInner, GpuInterrupts, Lcdc, Oam, ObjPalette, ObjSize, Object, ObjectFlags, Palette,
|
||||||
TiledataArea, TilemapArea, Vram,
|
Stat, TiledataArea, TilemapArea, Vram,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -132,7 +132,7 @@ where
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let buffer = vec![Colour::Error.into(); WIDTH * HEIGHT];
|
let buffer = vec![ColourInner::Error.rgb_bytes(None).into(); WIDTH * HEIGHT];
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
buffer,
|
buffer,
|
||||||
|
@ -315,7 +315,8 @@ where
|
||||||
*e = true;
|
*e = true;
|
||||||
}
|
}
|
||||||
for x in 0..WIDTH {
|
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 {
|
if self.lcdc.bg_window_enable {
|
||||||
self.render_scanline_bg(scanline);
|
self.render_scanline_bg(scanline);
|
||||||
|
@ -328,7 +329,8 @@ where
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for x in 0..WIDTH {
|
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 {
|
if self.lcdc.obj_enable {
|
||||||
|
@ -449,7 +451,9 @@ where
|
||||||
if x_coord < WIDTH {
|
if x_coord < WIDTH {
|
||||||
let buffer_index = (scanline as usize * WIDTH) + x_coord;
|
let buffer_index = (scanline as usize * WIDTH) + x_coord;
|
||||||
if !object.flags.behind_bg_and_window || self.is_bg_zero[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);
|
let (colour, is_zero) = self.bg_palette.map_bits(lsb, msb);
|
||||||
self.is_bg_zero[x] = is_zero;
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,8 @@ use super::{Colour, Gpu};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Copy)]
|
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||||
pub(super) struct CgbData {
|
pub(super) struct CgbData {
|
||||||
palettes: CgbPaletteRegisters,
|
pub(super) palettes: CgbPaletteRegisters,
|
||||||
object_priority_mode: ObjectPriorityMode,
|
pub(super) object_priority_mode: ObjectPriorityMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for CgbData {
|
impl Default for CgbData {
|
||||||
|
@ -24,24 +24,24 @@ impl Default for CgbData {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Copy)]
|
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||||
enum ObjectPriorityMode {
|
pub(super) enum ObjectPriorityMode {
|
||||||
OamLocation = 0,
|
OamLocation = 0,
|
||||||
Coordinate = 1,
|
Coordinate = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Copy, Default)]
|
#[derive(Serialize, Deserialize, Clone, Copy, Default)]
|
||||||
struct CgbPaletteRegisters {
|
pub(super) struct CgbPaletteRegisters {
|
||||||
bg: CgbPalette,
|
pub(super) bg: CgbPalette,
|
||||||
obj: CgbPalette,
|
pub(super) obj: CgbPalette,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde_with::serde_as]
|
#[serde_with::serde_as]
|
||||||
#[derive(Serialize, Deserialize, Clone, Copy)]
|
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||||
struct CgbPalette {
|
pub(super) struct CgbPalette {
|
||||||
auto_increment: bool,
|
auto_increment: bool,
|
||||||
index: u8,
|
index: u8,
|
||||||
#[serde_as(as = "[_; 0x40]")]
|
#[serde_as(as = "[_; 0x40]")]
|
||||||
data: [u8; 0x40],
|
pub(super) data: [u8; 0x40],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for CgbPalette {
|
impl Default for CgbPalette {
|
||||||
|
|
|
@ -4,7 +4,10 @@ use crate::{
|
||||||
util::get_bit,
|
util::get_bit,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{types::Vram, Colour};
|
use super::{
|
||||||
|
types::{ColourInner, Vram},
|
||||||
|
Colour,
|
||||||
|
};
|
||||||
|
|
||||||
pub(super) struct TileWindow<ColourFormat, R>
|
pub(super) struct TileWindow<ColourFormat, R>
|
||||||
where
|
where
|
||||||
|
@ -22,7 +25,10 @@ where
|
||||||
{
|
{
|
||||||
pub(super) fn new(window: R) -> Self {
|
pub(super) fn new(window: R) -> Self {
|
||||||
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,
|
sprite_renderer: window,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,7 +78,7 @@ where
|
||||||
let colour = palette.map_bits(lsb, msb);
|
let colour = palette.map_bits(lsb, msb);
|
||||||
|
|
||||||
self.sprite_buffer[real_px_x + (real_px_y * TILE_WINDOW_WIDTH)] =
|
self.sprite_buffer[real_px_x + (real_px_y * TILE_WINDOW_WIDTH)] =
|
||||||
colour.0.into();
|
colour.0.rgb_bytes(None).into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use bytemuck::from_bytes;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -5,6 +6,8 @@ use crate::{
|
||||||
util::{as_signed, get_bit},
|
util::{as_signed, get_bit},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::cgb::CgbPalette;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)]
|
||||||
pub(crate) enum DrawMode {
|
pub(crate) enum DrawMode {
|
||||||
HBlank,
|
HBlank,
|
||||||
|
@ -89,75 +92,92 @@ impl Default for Lcdc {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum Colour {
|
pub enum ColourInner {
|
||||||
White,
|
Zero = 0,
|
||||||
LightGray,
|
One = 1,
|
||||||
DarkGray,
|
Two = 2,
|
||||||
Black,
|
Three = 3,
|
||||||
Error,
|
Error = 255,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Colour(u8, u8, u8);
|
||||||
|
|
||||||
impl From<Colour> for u32 {
|
impl From<Colour> for u32 {
|
||||||
fn from(value: Colour) -> Self {
|
fn from(value: Colour) -> Self {
|
||||||
let rgb = value.rgb_bytes();
|
let (r, g, b) = (value.0 as u32, value.1 as u32, value.2 as u32);
|
||||||
let (r, g, b) = (rgb.0 as u32, rgb.1 as u32, rgb.2 as u32);
|
|
||||||
(r << 16) | (g << 8) | b
|
(r << 16) | (g << 8) | b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Colour> for [u8; 4] {
|
impl From<Colour> for [u8; 4] {
|
||||||
fn from(value: Colour) -> Self {
|
fn from(value: Colour) -> Self {
|
||||||
let (r, g, b) = value.rgb_bytes();
|
let Colour(r, g, b) = value;
|
||||||
[r, g, b, 0xFF]
|
[r, g, b, 0xFF]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Colour {
|
fn rgb_from_bytes(bytes: u16) -> Colour {
|
||||||
fn rgb_bytes(&self) -> (u8, u8, u8) {
|
let blue = (((bytes & (0b11111 << 10)) >> 10) << 3) as u8;
|
||||||
match self {
|
let green = (((bytes & (0b11111 << 5)) >> 5) << 3) as u8;
|
||||||
Colour::White => (0xFF, 0xFF, 0xFF),
|
let red = ((bytes & 0b11111) << 3) as u8;
|
||||||
Colour::LightGray => (0xAA, 0xAA, 0xAA),
|
Colour(red, green, blue)
|
||||||
Colour::DarkGray => (0x55, 0x55, 0x55),
|
}
|
||||||
Colour::Black => (0x00, 0x00, 0x00),
|
|
||||||
Colour::Error => (0xFF, 0x00, 0x00),
|
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) {
|
match (first, second) {
|
||||||
(true, true) => Colour::Black,
|
(true, true) => ColourInner::Three,
|
||||||
(true, false) => Colour::LightGray,
|
(true, false) => ColourInner::One,
|
||||||
(false, true) => Colour::DarkGray,
|
(false, true) => ColourInner::Two,
|
||||||
(false, false) => Colour::White,
|
(false, false) => ColourInner::Zero,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_bits(&self) -> u8 {
|
fn as_bits(&self) -> u8 {
|
||||||
match self {
|
match self {
|
||||||
Colour::White => 0b00,
|
ColourInner::Zero => 0b00,
|
||||||
Colour::LightGray => 0b01,
|
ColourInner::One => 0b01,
|
||||||
Colour::DarkGray => 0b10,
|
ColourInner::Two => 0b10,
|
||||||
Colour::Black => 0b11,
|
ColourInner::Three => 0b11,
|
||||||
Colour::Error => 0b00,
|
ColourInner::Error => 0b00,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||||
pub(super) struct Palette {
|
pub(super) struct Palette {
|
||||||
pub(super) zero: Colour,
|
pub(super) zero: ColourInner,
|
||||||
pub(super) one: Colour,
|
pub(super) one: ColourInner,
|
||||||
pub(super) two: Colour,
|
pub(super) two: ColourInner,
|
||||||
pub(super) three: Colour,
|
pub(super) three: ColourInner,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Palette {
|
impl Palette {
|
||||||
pub(super) fn from_byte(byte: u8) -> Palette {
|
pub(super) fn from_byte(byte: u8) -> Palette {
|
||||||
Palette {
|
Palette {
|
||||||
zero: Colour::from_bits(get_bit(byte, 0), get_bit(byte, 1)),
|
zero: ColourInner::from_bits(get_bit(byte, 0), get_bit(byte, 1)),
|
||||||
one: Colour::from_bits(get_bit(byte, 2), get_bit(byte, 3)),
|
one: ColourInner::from_bits(get_bit(byte, 2), get_bit(byte, 3)),
|
||||||
two: Colour::from_bits(get_bit(byte, 4), get_bit(byte, 5)),
|
two: ColourInner::from_bits(get_bit(byte, 4), get_bit(byte, 5)),
|
||||||
three: Colour::from_bits(get_bit(byte, 6), get_bit(byte, 7)),
|
three: ColourInner::from_bits(get_bit(byte, 6), get_bit(byte, 7)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +188,7 @@ impl Palette {
|
||||||
| (self.three.as_bits() << 6)
|
| (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) {
|
match (lsb, msb) {
|
||||||
(true, true) => (self.three, false),
|
(true, true) => (self.three, false),
|
||||||
(true, false) => (self.one, false),
|
(true, false) => (self.one, false),
|
||||||
|
|
Loading…
Reference in a new issue