use save_state::Savable;
use super::colors::ColorPalette;
use super::sprite::SelectedSprite;
use fixed_vec_deque::FixedVecDeque;
#[derive(PartialEq, Clone, Copy, Savable)]
pub enum SpritePriorityMode {
ByIndex, ByCoord, }
#[derive(Clone, Copy, Default, Savable)]
pub struct BgFifoPixel {
pub color: u8,
pub palette: ColorPalette,
pub bg_priority: bool,
}
#[derive(Clone, Copy, Default, Savable)]
pub struct SpriteFifoPixel {
pub color: u8,
pub palette: ColorPalette,
pub dmg_palette: u8,
pub index: u8,
pub oam_bg_priority: bool,
}
pub struct BgFifo {
pixels: FixedVecDeque<[BgFifoPixel; 16]>,
}
impl Default for BgFifo {
fn default() -> Self {
Self {
pixels: FixedVecDeque::new(),
}
}
}
impl BgFifo {
pub fn pop(&mut self) -> BgFifoPixel {
*self.pixels.pop_front().unwrap()
}
pub fn push(&mut self, colors: [u8; 8], palette: ColorPalette, bg_priority: bool) {
for &color in colors.iter() {
*self.pixels.push_back() = BgFifoPixel {
color,
palette,
bg_priority,
};
}
}
pub fn len(&self) -> usize {
self.pixels.len()
}
pub fn clear(&mut self) {
self.pixels.clear();
}
}
impl Savable for BgFifo {
fn save<W: std::io::Write>(&self, mut writer: &mut W) -> save_state::Result<()> {
<usize as Savable>::save(&self.pixels.len(), &mut writer)?;
for pixel in self.pixels.iter() {
Savable::save(pixel, &mut writer)?;
}
Ok(())
}
fn load<R: std::io::Read>(&mut self, mut reader: &mut R) -> save_state::Result<()> {
let mut size = 0;
<usize as Savable>::load(&mut size, &mut reader)?;
assert!(size <= 16);
self.pixels.clear();
for _ in 0..size {
let pixel = self.pixels.push_back();
pixel.load(&mut reader)?;
}
Ok(())
}
}
pub struct SpriteFifo {
pixels: FixedVecDeque<[SpriteFifoPixel; 8]>,
sprite_priority_mode: SpritePriorityMode,
}
impl SpriteFifo {
pub fn new(sprite_priority_mode: SpritePriorityMode) -> Self {
Self {
pixels: FixedVecDeque::new(),
sprite_priority_mode,
}
}
pub fn update_sprite_priority_mode(&mut self, sprite_priority_mode: SpritePriorityMode) {
self.sprite_priority_mode = sprite_priority_mode;
}
pub fn pop(&mut self) -> Option<SpriteFifoPixel> {
self.pixels.pop_front().map(|x| *x)
}
pub fn push(&mut self, colors: [u8; 8], sprite: &SelectedSprite, palette: ColorPalette) {
let dmg_palette = sprite.sprite().dmg_palette();
let index = sprite.index();
let oam_bg_priority = sprite.sprite().bg_priority();
let mut to_mix = self.len();
for (i, &new_color) in colors.iter().enumerate() {
let new_sprite_pixel = SpriteFifoPixel {
color: new_color,
palette,
dmg_palette,
index,
oam_bg_priority,
};
if to_mix > 0 {
to_mix -= 1;
let old_pixel = &mut self.pixels[i];
if ((self.sprite_priority_mode == SpritePriorityMode::ByIndex
&& index < old_pixel.index)
|| old_pixel.color == 0)
&& new_color != 0
{
*old_pixel = new_sprite_pixel;
}
} else {
*self.pixels.push_back() = new_sprite_pixel;
}
}
}
pub fn len(&self) -> usize {
self.pixels.len()
}
pub fn clear(&mut self) {
self.pixels.clear();
}
}
impl Savable for SpriteFifo {
fn save<W: std::io::Write>(&self, mut writer: &mut W) -> save_state::Result<()> {
<usize as Savable>::save(&self.pixels.len(), &mut writer)?;
for pixel in self.pixels.iter() {
Savable::save(pixel, &mut writer)?;
}
self.sprite_priority_mode.save(&mut writer)?;
Ok(())
}
fn load<R: std::io::Read>(&mut self, mut reader: &mut R) -> save_state::Result<()> {
let mut size = 0;
<usize as Savable>::load(&mut size, &mut reader)?;
assert!(size <= 8);
self.pixels.clear();
for _ in 0..size {
let pixel = self.pixels.push_back();
pixel.load(&mut reader)?;
}
self.sprite_priority_mode.load(&mut reader)?;
Ok(())
}
}