tetanes-core 0.14.0

A NES Emulator written in Rust
//! PPU frame implementation.

use crate::{
    common::{Reset, ResetKind},
    mem::ConstArray,
    ppu::{self, Ppu},
};
use serde::{Deserialize, Serialize};
use std::ops::{Deref, DerefMut};

/// PPU frame.
#[derive(Clone, Serialize, Deserialize)]
#[serde(transparent)]
#[repr(transparent)]
#[must_use]
pub struct Buffer(Box<ConstArray<u16, { ppu::size::FRAME }>>);

impl std::fmt::Debug for Buffer {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Buffer({} elements)", self.0.len())
    }
}

impl Default for Buffer {
    fn default() -> Self {
        Self(Box::new(ConstArray::new()))
    }
}

impl Deref for Buffer {
    type Target = [u16; ppu::size::FRAME];
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for Buffer {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

/// PPU frame.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[must_use]
#[repr(C)]
pub struct Frame {
    #[serde(skip)]
    pub buffer: Buffer,
    pub count: u32,
}

impl Default for Frame {
    fn default() -> Self {
        Self::new()
    }
}

impl Frame {
    pub fn new() -> Self {
        Self {
            count: 0,
            buffer: Buffer::default(),
        }
    }

    #[inline(always)]
    pub const fn increment(&mut self) {
        self.count = self.count.wrapping_add(1);
    }

    #[inline(always)]
    #[must_use]
    pub fn pixel(&self, x: u16, y: u16) -> u16 {
        self.buffer[usize::from(x) + (usize::from(y) << 8)]
    }

    #[inline(always)]
    pub fn set_pixel(&mut self, x: u16, y: u16, color: u16) {
        self.buffer[usize::from(x) + (usize::from(y) << 8)] = color;
    }

    #[must_use]
    pub fn pixel_brightness(&self, x: u16, y: u16) -> u32 {
        let pixel = self.pixel(x, y);
        let index = (pixel as usize) * 3;
        let red = Ppu::NTSC_PALETTE[index];
        let green = Ppu::NTSC_PALETTE[index + 1];
        let blue = Ppu::NTSC_PALETTE[index + 2];
        u32::from(red) + u32::from(green) + u32::from(blue)
    }

    #[inline(always)]
    #[must_use]
    pub const fn number(&self) -> u32 {
        self.count
    }

    #[inline(always)]
    pub const fn is_odd(&self) -> bool {
        self.count & 0x01 == 0x01
    }

    #[inline(always)]
    #[must_use]
    pub fn buffer(&self) -> &[u16; ppu::size::FRAME] {
        &self.buffer
    }
}

impl Reset for Frame {
    fn reset(&mut self, _kind: ResetKind) {
        self.count = 0;
        self.buffer = Buffer::default();
    }
}