pub const PALETTE_ENTRIES: usize = 512;
#[derive(Clone, Debug)]
pub struct Vce {
control: u8,
address: u16,
palette: [u16; PALETTE_ENTRIES],
}
impl Default for Vce {
fn default() -> Self {
Self::new()
}
}
impl Vce {
#[must_use]
pub fn new() -> Self {
Self {
control: 0,
address: 0,
palette: [0; PALETTE_ENTRIES],
}
}
pub fn write(&mut self, offset: u16, value: u8) {
match offset & 0x07 {
0x00 => self.control = value,
0x02 => self.address = (self.address & 0x0100) | u16::from(value),
0x03 => self.address = (self.address & 0x00FF) | (u16::from(value & 0x01) << 8),
0x04 => {
let entry = self.address as usize % PALETTE_ENTRIES;
self.palette[entry] = (self.palette[entry] & 0x0100) | u16::from(value);
}
0x05 => {
let entry = self.address as usize % PALETTE_ENTRIES;
self.palette[entry] =
(self.palette[entry] & 0x00FF) | (u16::from(value & 0x01) << 8);
self.address = (self.address + 1) & 0x01FF;
}
_ => {}
}
}
#[must_use]
pub fn read(&self, offset: u16) -> u8 {
match offset & 0x07 {
0x04 => {
let entry = self.address as usize % PALETTE_ENTRIES;
(self.palette[entry] & 0xFF) as u8
}
0x05 => {
let entry = self.address as usize % PALETTE_ENTRIES;
((self.palette[entry] >> 8) & 0x01) as u8 | 0xFE
}
_ => 0xFF,
}
}
#[must_use]
pub const fn dot_clock_select(&self) -> u8 {
self.control & 0x03
}
#[must_use]
pub fn color_raw(&self, entry: usize) -> u16 {
self.palette[entry % PALETTE_ENTRIES]
}
#[must_use]
pub fn color_argb(&self, entry: usize) -> u32 {
let raw = self.palette[entry % PALETTE_ENTRIES];
let g = ((raw >> 6) & 0x07) as u32;
let r = ((raw >> 3) & 0x07) as u32;
let b = (raw & 0x07) as u32;
let expand = |c: u32| (c * 255 / 7) & 0xFF;
0xFF00_0000 | (expand(r) << 16) | (expand(g) << 8) | expand(b)
}
}