tetanes_core/ppu/
frame.rs

1//! PPU frame implementation.
2
3use crate::{
4    common::{Reset, ResetKind},
5    ppu::Ppu,
6};
7use serde::{Deserialize, Serialize};
8use std::ops::{Deref, DerefMut};
9
10/// PPU frame.
11#[derive(Clone, Serialize, Deserialize)]
12#[serde(transparent)]
13#[must_use]
14pub struct Buffer(Vec<u16>);
15
16impl std::fmt::Debug for Buffer {
17    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18        write!(f, "Buffer({} elements)", self.0.len())
19    }
20}
21
22impl Default for Buffer {
23    fn default() -> Self {
24        Self(vec![0x00; Ppu::SIZE])
25    }
26}
27
28impl Deref for Buffer {
29    type Target = [u16];
30    fn deref(&self) -> &Self::Target {
31        &self.0
32    }
33}
34
35impl DerefMut for Buffer {
36    fn deref_mut(&mut self) -> &mut Self::Target {
37        &mut self.0
38    }
39}
40
41/// PPU frame.
42#[derive(Debug, Clone, Serialize, Deserialize)]
43#[must_use]
44pub struct Frame {
45    pub count: u32,
46    pub is_odd: bool,
47    #[serde(skip)]
48    pub buffer: Buffer,
49}
50
51impl Default for Frame {
52    fn default() -> Self {
53        Self::new()
54    }
55}
56
57impl Frame {
58    pub fn new() -> Self {
59        Self {
60            count: 0,
61            is_odd: false,
62            buffer: Buffer::default(),
63        }
64    }
65
66    pub const fn increment(&mut self) {
67        self.count = self.count.wrapping_add(1);
68        self.is_odd = self.count & 0x01 == 0x01;
69    }
70
71    #[must_use]
72    pub fn pixel(&self, x: u32, y: u32) -> u16 {
73        self.buffer[(x + (y << 8)) as usize]
74    }
75
76    #[inline]
77    pub fn set_pixel(&mut self, x: u32, y: u32, color: u16) {
78        self.buffer[(x + (y << 8)) as usize] = color;
79    }
80
81    #[must_use]
82    pub fn pixel_brightness(&self, x: u32, y: u32) -> u32 {
83        let pixel = self.pixel(x, y);
84        let index = (pixel as usize) * 3;
85        let red = Ppu::NTSC_PALETTE[index];
86        let green = Ppu::NTSC_PALETTE[index + 1];
87        let blue = Ppu::NTSC_PALETTE[index + 2];
88        u32::from(red) + u32::from(green) + u32::from(blue)
89    }
90
91    #[must_use]
92    pub const fn number(&self) -> u32 {
93        self.count
94    }
95
96    #[must_use]
97    pub const fn is_odd(&self) -> bool {
98        self.is_odd
99    }
100
101    #[must_use]
102    #[allow(clippy::missing_const_for_fn)] // false positive on non-const deref coercion
103    pub fn buffer(&self) -> &[u16] {
104        &self.buffer
105    }
106}
107
108impl Reset for Frame {
109    fn reset(&mut self, _kind: ResetKind) {
110        self.count = 0;
111        self.buffer = Buffer::default();
112    }
113}