use std::convert::TryInto;
use std::mem;
use std::ops::Index;
use bytes::{Buf, Bytes};
use crate::wad::{self, Cursor, Wad};
#[derive(Debug)]
pub struct PaletteBank {
palettes: Vec<Palette>,
active: usize,
}
impl PaletteBank {
pub fn load(wad: &Wad) -> wad::Result<Self> {
let lump = wad.lump("PLAYPAL")?;
let mut cursor = lump.cursor();
let mut palettes = Vec::with_capacity(lump.size() / PALETTE_BYTES);
cursor.need(1)?;
while cursor.has_remaining() {
palettes.push(Palette::load(&mut cursor)?);
}
cursor.done()?;
Ok(PaletteBank {
palettes,
active: 0,
})
}
pub fn count(&self) -> usize {
self.palettes.len()
}
pub fn active(&self) -> &Palette {
&self.palettes[self.active]
}
pub fn switch(&mut self, index: usize) -> &Palette {
assert!(index < self.count());
self.active = index;
self.active()
}
}
#[derive(Debug, Clone)]
pub struct Palette {
raw: Bytes,
}
const PALETTE_COLORS: usize = 256;
const PALETTE_BYTES: usize = 3 * PALETTE_COLORS;
impl Palette {
fn load(cursor: &mut Cursor) -> wad::Result<Self> {
cursor.need(PALETTE_BYTES)?;
let raw = cursor.split_to(PALETTE_BYTES);
Ok(Self { raw })
}
}
impl Index<u8> for Palette {
type Output = (u8, u8, u8);
fn index(&self, index: u8) -> &Self::Output {
let index: usize = index.into();
let rgb: &[u8; 3] = self.raw[index * 3..index * 3 + 3].try_into().unwrap();
unsafe { mem::transmute(rgb) }
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::wad::test::*;
#[test]
fn load() {
let mut palettes = PaletteBank::load(&DOOM_WAD).unwrap();
assert_eq!(palettes.count(), 14);
let p0 = palettes.switch(0);
assert_eq!(p0[0], (0, 0, 0));
assert_eq!(p0[255], (167, 107, 107));
let p13 = palettes.switch(13);
assert_eq!(p13[0], (0, 32, 0));
assert_eq!(p13[255], (147, 125, 94));
}
}