chore(ppu): rename types and improve code quality
This commit is contained in:
parent
b43c8ac7c9
commit
2acdaaeec2
160
src/ppu.rs
160
src/ppu.rs
|
@ -10,7 +10,7 @@ const OAM_SIZE: usize = 0xA0;
|
|||
const PPU_START_ADDRESS: usize = 0x8000;
|
||||
|
||||
// OAM Scan
|
||||
const SPRITE_BUFFER_LIMIT: usize = 10;
|
||||
const OBJECT_LIMIT: usize = 10;
|
||||
|
||||
const WHITE: [u8; 4] = [0xFF, 0xFF, 0xFF, 0xFF];
|
||||
const LIGHT_GRAY: [u8; 4] = [0xCC, 0xCC, 0xCC, 0xFF];
|
||||
|
@ -25,10 +25,10 @@ pub struct Ppu {
|
|||
pub pos: ScreenPosition,
|
||||
pub vram: Box<[u8; VRAM_SIZE]>,
|
||||
pub stat: LCDStatus,
|
||||
pub oam: SpriteAttributeTable,
|
||||
pub oam: ObjectAttributeTable,
|
||||
fetcher: PixelFetcher,
|
||||
fifo: FifoRenderer,
|
||||
sprite_buffer: SpriteBuffer,
|
||||
obj_buffer: ObjectBuffer,
|
||||
frame_buf: Box<[u8; GB_WIDTH * GB_HEIGHT * 4]>,
|
||||
x_pos: u8,
|
||||
cycles: Cycle,
|
||||
|
@ -158,9 +158,9 @@ impl Ppu {
|
|||
if attr.x > 0
|
||||
&& line_y >= attr.y
|
||||
&& line_y < (attr.y + sprite_height)
|
||||
&& !self.sprite_buffer.full()
|
||||
&& !self.obj_buffer.full()
|
||||
{
|
||||
self.sprite_buffer.add(attr);
|
||||
self.obj_buffer.add(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ impl Ppu {
|
|||
|
||||
// Increment Window line counter if scanline had any window pixels on it
|
||||
// only increment once per scanline though
|
||||
if window_present && !self.fetcher.window_line.already_checked() {
|
||||
if window_present && !self.fetcher.window_line.checked() {
|
||||
self.fetcher.window_line.increment();
|
||||
}
|
||||
|
||||
|
@ -203,7 +203,7 @@ impl Ppu {
|
|||
let scx_offset = if window_present { 0 } else { scroll_x / 8 } & 0x1F;
|
||||
|
||||
let offset = if window_present {
|
||||
32 * (self.fetcher.window_line.value() as u16 / 8)
|
||||
32 * (self.fetcher.window_line.count() as u16 / 8)
|
||||
} else {
|
||||
32 * (((y_offset) & 0x00FF) / 8)
|
||||
};
|
||||
|
@ -211,7 +211,7 @@ impl Ppu {
|
|||
let addr = tile_map_addr + offset + x_offset + scx_offset as u16;
|
||||
|
||||
let id = self.read_byte(addr);
|
||||
self.fetcher.builder.with_id(id);
|
||||
self.fetcher.tile.with_id(id);
|
||||
|
||||
// Move on to the Next state in 2 T-cycles
|
||||
self.fetcher.state = TileDataLow;
|
||||
|
@ -219,7 +219,7 @@ impl Ppu {
|
|||
TileDataLow => {
|
||||
let id = self
|
||||
.fetcher
|
||||
.builder
|
||||
.tile
|
||||
.id
|
||||
.expect("Tile Number unexpectedly missing");
|
||||
|
||||
|
@ -229,21 +229,21 @@ impl Ppu {
|
|||
};
|
||||
|
||||
let offset = if window_present {
|
||||
2 * (self.fetcher.window_line.value() % 8)
|
||||
2 * (self.fetcher.window_line.count() % 8)
|
||||
} else {
|
||||
2 * ((line_y + scroll_y) % 8)
|
||||
};
|
||||
|
||||
let addr = tile_data_addr + offset as u16;
|
||||
let low = self.read_byte(addr);
|
||||
self.fetcher.builder.with_data_low(low);
|
||||
self.fetcher.tile.with_low_byte(low);
|
||||
|
||||
self.fetcher.state = TileDataHigh;
|
||||
}
|
||||
TileDataHigh => {
|
||||
let id = self
|
||||
.fetcher
|
||||
.builder
|
||||
.tile
|
||||
.id
|
||||
.expect("Tile Number unexpectedly missing");
|
||||
|
||||
|
@ -253,21 +253,21 @@ impl Ppu {
|
|||
};
|
||||
|
||||
let offset = if window_present {
|
||||
2 * (self.fetcher.window_line.value() % 8)
|
||||
2 * (self.fetcher.window_line.count() % 8)
|
||||
} else {
|
||||
2 * ((line_y + scroll_y) % 8)
|
||||
};
|
||||
|
||||
let addr = tile_data_addr + offset as u16;
|
||||
let high = self.read_byte(addr + 1);
|
||||
self.fetcher.builder.with_data_high(high);
|
||||
self.fetcher.tile.with_high_byte(high);
|
||||
|
||||
self.fetcher.state = SendToFifo;
|
||||
}
|
||||
SendToFifo => {
|
||||
if let Some(low) = self.fetcher.builder.low {
|
||||
if let Some(high) = self.fetcher.builder.high {
|
||||
let pixel = Pixels::from_bytes(high, low);
|
||||
if let Some(low) = self.fetcher.tile.low {
|
||||
if let Some(high) = self.fetcher.tile.high {
|
||||
let pixel = TwoBitsPerPixel::from_bytes(high, low);
|
||||
let palette = self.monochrome.bg_palette;
|
||||
|
||||
if self.fifo.background.is_empty() {
|
||||
|
@ -296,9 +296,9 @@ impl Ppu {
|
|||
}
|
||||
}
|
||||
|
||||
// Handle Pixel and Sprite FIFO
|
||||
// Handle Background Pixel and Sprite FIFO
|
||||
if let Some(bg_pixel) = self.fifo.background.pop_front() {
|
||||
if let Some(_sprite_pixel) = self.fifo.sprite.pop_front() {
|
||||
if let Some(_object_pixel) = self.fifo.object.pop_front() {
|
||||
todo!("Mix the pixels or whatever I'm supposed todo here");
|
||||
} else {
|
||||
// Only Background Pixels will be rendered
|
||||
|
@ -334,7 +334,7 @@ impl Default for Ppu {
|
|||
oam: Default::default(),
|
||||
fetcher: Default::default(),
|
||||
fifo: Default::default(),
|
||||
sprite_buffer: Default::default(),
|
||||
obj_buffer: Default::default(),
|
||||
x_pos: Default::default(),
|
||||
}
|
||||
}
|
||||
|
@ -734,9 +734,9 @@ impl From<ObjectPalette> for u8 {
|
|||
}
|
||||
}
|
||||
|
||||
struct Pixels(u8, u8);
|
||||
struct TwoBitsPerPixel(u8, u8);
|
||||
|
||||
impl Pixels {
|
||||
impl TwoBitsPerPixel {
|
||||
pub fn from_bytes(higher: u8, lower: u8) -> Self {
|
||||
Self(higher, lower)
|
||||
}
|
||||
|
@ -750,11 +750,11 @@ impl Pixels {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SpriteAttributeTable {
|
||||
pub struct ObjectAttributeTable {
|
||||
buf: Box<[u8; OAM_SIZE]>,
|
||||
}
|
||||
|
||||
impl SpriteAttributeTable {
|
||||
impl ObjectAttributeTable {
|
||||
pub fn read_byte(&self, addr: u16) -> u8 {
|
||||
let index = (addr - 0xFE00) as usize;
|
||||
self.buf[index]
|
||||
|
@ -765,7 +765,7 @@ impl SpriteAttributeTable {
|
|||
self.buf[index] = byte;
|
||||
}
|
||||
|
||||
pub fn attribute(&self, index: usize) -> SpriteAttribute {
|
||||
pub fn attribute(&self, index: usize) -> ObjectAttribute {
|
||||
let slice: &[u8; 4] = self.buf[index..(index + 4)]
|
||||
.try_into()
|
||||
.expect("Could not interpret &[u8] as a &[u8; 4]");
|
||||
|
@ -774,7 +774,7 @@ impl SpriteAttributeTable {
|
|||
}
|
||||
}
|
||||
|
||||
impl Default for SpriteAttributeTable {
|
||||
impl Default for ObjectAttributeTable {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
buf: Box::new([0; OAM_SIZE]),
|
||||
|
@ -783,14 +783,14 @@ impl Default for SpriteAttributeTable {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct SpriteAttribute {
|
||||
pub struct ObjectAttribute {
|
||||
y: u8,
|
||||
x: u8,
|
||||
tile_index: u8,
|
||||
flags: SpriteFlag,
|
||||
flags: ObjectFlags,
|
||||
}
|
||||
|
||||
impl From<[u8; 4]> for SpriteAttribute {
|
||||
impl From<[u8; 4]> for ObjectAttribute {
|
||||
fn from(bytes: [u8; 4]) -> Self {
|
||||
Self {
|
||||
y: bytes[0],
|
||||
|
@ -801,7 +801,7 @@ impl From<[u8; 4]> for SpriteAttribute {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a [u8; 4]> for SpriteAttribute {
|
||||
impl<'a> From<&'a [u8; 4]> for ObjectAttribute {
|
||||
fn from(bytes: &'a [u8; 4]) -> Self {
|
||||
Self {
|
||||
y: bytes[0],
|
||||
|
@ -813,35 +813,35 @@ impl<'a> From<&'a [u8; 4]> for SpriteAttribute {
|
|||
}
|
||||
|
||||
bitfield! {
|
||||
pub struct SpriteFlag(u8);
|
||||
pub struct ObjectFlags(u8);
|
||||
impl Debug;
|
||||
|
||||
from into RenderPriority, priority, set_priority: 7, 7;
|
||||
y_flip, set_y_flip: 6;
|
||||
x_flip, set_x_flip: 5;
|
||||
from into SpritePaletteNumber, palette, set_palette: 4, 4;
|
||||
from into ObjectPaletteId, palette, set_palette: 4, 4;
|
||||
}
|
||||
|
||||
impl Copy for SpriteFlag {}
|
||||
impl Clone for SpriteFlag {
|
||||
impl Copy for ObjectFlags {}
|
||||
impl Clone for ObjectFlags {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for SpriteFlag {
|
||||
impl From<u8> for ObjectFlags {
|
||||
fn from(byte: u8) -> Self {
|
||||
Self(byte)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SpriteFlag> for u8 {
|
||||
fn from(flags: SpriteFlag) -> Self {
|
||||
impl From<ObjectFlags> for u8 {
|
||||
fn from(flags: ObjectFlags) -> Self {
|
||||
flags.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SpriteFlag {
|
||||
impl Default for ObjectFlags {
|
||||
fn default() -> Self {
|
||||
Self(0)
|
||||
}
|
||||
|
@ -849,14 +849,14 @@ impl Default for SpriteFlag {
|
|||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum RenderPriority {
|
||||
Sprite = 0,
|
||||
Object = 0,
|
||||
BackgroundAndWindow = 1,
|
||||
}
|
||||
|
||||
impl From<u8> for RenderPriority {
|
||||
fn from(byte: u8) -> Self {
|
||||
match byte {
|
||||
0b00 => Self::Sprite,
|
||||
0b00 => Self::Object,
|
||||
0b01 => Self::BackgroundAndWindow,
|
||||
_ => unreachable!("{:#04X} is not a valid value for RenderPriority", byte),
|
||||
}
|
||||
|
@ -871,39 +871,39 @@ impl From<RenderPriority> for u8 {
|
|||
|
||||
impl Default for RenderPriority {
|
||||
fn default() -> Self {
|
||||
Self::Sprite
|
||||
Self::Object
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum SpritePaletteNumber {
|
||||
SpritePalette0 = 0,
|
||||
SpritePalette1 = 1,
|
||||
pub enum ObjectPaletteId {
|
||||
Palette0 = 0,
|
||||
Palette1 = 1,
|
||||
}
|
||||
|
||||
impl From<u8> for SpritePaletteNumber {
|
||||
impl From<u8> for ObjectPaletteId {
|
||||
fn from(byte: u8) -> Self {
|
||||
match byte {
|
||||
0b00 => SpritePaletteNumber::SpritePalette0,
|
||||
0b01 => SpritePaletteNumber::SpritePalette1,
|
||||
0b00 => ObjectPaletteId::Palette0,
|
||||
0b01 => ObjectPaletteId::Palette1,
|
||||
_ => unreachable!("{:#04X} is not a valid value for BgPaletteNumber", byte),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SpritePaletteNumber> for u8 {
|
||||
fn from(flip: SpritePaletteNumber) -> Self {
|
||||
flip as u8
|
||||
impl From<ObjectPaletteId> for u8 {
|
||||
fn from(palette_num: ObjectPaletteId) -> Self {
|
||||
palette_num as u8
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct SpriteBuffer {
|
||||
buf: [SpriteAttribute; 10],
|
||||
struct ObjectBuffer {
|
||||
buf: [ObjectAttribute; 10],
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl SpriteBuffer {
|
||||
impl ObjectBuffer {
|
||||
pub fn full(&self) -> bool {
|
||||
self.len == self.buf.len()
|
||||
}
|
||||
|
@ -913,16 +913,16 @@ impl SpriteBuffer {
|
|||
self.len = 0;
|
||||
}
|
||||
|
||||
pub fn add(&mut self, attr: SpriteAttribute) {
|
||||
pub fn add(&mut self, attr: ObjectAttribute) {
|
||||
self.buf[self.len] = attr;
|
||||
self.len += 1;
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SpriteBuffer {
|
||||
impl Default for ObjectBuffer {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
buf: [Default::default(); SPRITE_BUFFER_LIMIT],
|
||||
buf: [Default::default(); OBJECT_LIMIT],
|
||||
len: 0,
|
||||
}
|
||||
}
|
||||
|
@ -930,17 +930,17 @@ impl Default for SpriteBuffer {
|
|||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
struct PixelFetcher {
|
||||
state: FetcherState,
|
||||
x_pos: u8,
|
||||
state: FetcherState,
|
||||
window_line: WindowLineCounter,
|
||||
builder: TileBuilder,
|
||||
tile: TileBuilder,
|
||||
}
|
||||
|
||||
impl PixelFetcher {
|
||||
pub fn hblank_reset(&mut self) {
|
||||
self.window_line.hblank_reset();
|
||||
|
||||
self.builder = Default::default();
|
||||
self.tile = Default::default();
|
||||
self.state = Default::default();
|
||||
self.x_pos = 0;
|
||||
}
|
||||
|
@ -952,31 +952,31 @@ impl PixelFetcher {
|
|||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
struct WindowLineCounter {
|
||||
value: u8,
|
||||
already_checked: bool,
|
||||
count: u8,
|
||||
checked: bool,
|
||||
}
|
||||
|
||||
impl WindowLineCounter {
|
||||
pub fn already_checked(&self) -> bool {
|
||||
self.already_checked
|
||||
pub fn checked(&self) -> bool {
|
||||
self.checked
|
||||
}
|
||||
|
||||
pub fn increment(&mut self) {
|
||||
self.value += 1;
|
||||
self.already_checked = true;
|
||||
self.count += 1;
|
||||
self.checked = true;
|
||||
}
|
||||
|
||||
pub fn hblank_reset(&mut self) {
|
||||
self.already_checked = false;
|
||||
self.checked = false;
|
||||
}
|
||||
|
||||
pub fn vblank_reset(&mut self) {
|
||||
self.value = 0;
|
||||
self.already_checked = false;
|
||||
self.count = 0;
|
||||
self.checked = false;
|
||||
}
|
||||
|
||||
pub fn value(&self) -> u8 {
|
||||
self.value
|
||||
pub fn count(&self) -> u8 {
|
||||
self.count
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -997,7 +997,7 @@ impl Default for FetcherState {
|
|||
#[derive(Debug, Clone, Copy)]
|
||||
enum FifoPixelKind {
|
||||
Background,
|
||||
Sprite,
|
||||
Object,
|
||||
}
|
||||
|
||||
impl Default for FifoPixelKind {
|
||||
|
@ -1014,19 +1014,29 @@ struct FifoPixel {
|
|||
priority: Option<RenderPriority>,
|
||||
}
|
||||
|
||||
impl FifoPixel {
|
||||
pub fn new_background(shade: GrayShade) -> Self {
|
||||
Self {
|
||||
kind: FifoPixelKind::Background,
|
||||
shade,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Fifo Registers have a known size. Are heap allocations
|
||||
// really necessary here?
|
||||
#[derive(Debug, Clone)]
|
||||
struct FifoRenderer {
|
||||
background: VecDeque<FifoPixel>,
|
||||
sprite: VecDeque<FifoPixel>,
|
||||
object: VecDeque<FifoPixel>,
|
||||
}
|
||||
|
||||
impl Default for FifoRenderer {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
background: VecDeque::with_capacity(8),
|
||||
sprite: VecDeque::with_capacity(8),
|
||||
object: VecDeque::with_capacity(8),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1043,11 +1053,11 @@ impl TileBuilder {
|
|||
self.id = Some(id);
|
||||
}
|
||||
|
||||
pub fn with_data_low(&mut self, data: u8) {
|
||||
pub fn with_low_byte(&mut self, data: u8) {
|
||||
self.low = Some(data);
|
||||
}
|
||||
|
||||
pub fn with_data_high(&mut self, data: u8) {
|
||||
pub fn with_high_byte(&mut self, data: u8) {
|
||||
self.high = Some(data);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue