use std::sync::LazyLock;
use arr_macro::arr;
use crate::ppu::cycle_action::cycle_action::CycleAction;
#[allow(clippy::identity_op)]
pub static VISIBLE_SCANLINE_ACTIONS: LazyLock<ScanlineActions> = LazyLock::new(|| {
use CycleAction::*;
let mut line = ScanlineActions::new();
line.add( 1, vec![ StartClearingSecondaryOam ]);
line.add( 65, vec![ StartSpriteEvaluation ]);
line.add( 257, vec![StopReadingBackgroundTiles ]);
line.add( 257, vec![ StartLoadingOamRegisters ]);
line.add( 321, vec![ StopLoadingOamRegisters ]);
line.add( 321, vec![StartReadingBackgroundTiles ]);
for tile in 0..31 {
let cycle = 8 * tile + 1;
line.add(cycle + 0, vec![ ReadOamByte , SetPixel, PrepareForNextPixel]);
line.add(cycle + 1, vec![GetPatternIndex , WriteSecondaryOamByte, SetPixel, PrepareForNextPixel]);
line.add(cycle + 2, vec![ ReadOamByte , SetPixel, PrepareForNextPixel]);
line.add(cycle + 3, vec![GetPaletteIndex , WriteSecondaryOamByte, SetPixel, PrepareForNextPixel]);
line.add(cycle + 4, vec![ ReadOamByte , SetPixel, PrepareForNextPixel]);
line.add(cycle + 5, vec![GetPatternLowByte , WriteSecondaryOamByte, SetPixel, PrepareForNextPixel]);
line.add(cycle + 6, vec![ ReadOamByte , SetPixel, PrepareForNextPixel]);
line.add(cycle + 7, vec![GetPatternHighByte , GotoNextTileColumn, WriteSecondaryOamByte, SetPixel, PrepareForNextPixel]);
line.add(cycle + 8, vec![PrepareForNextTile ]);
}
line.add( 249, vec![ ReadOamByte , SetPixel, PrepareForNextPixel]);
line.add( 250, vec![GetPatternIndex , WriteSecondaryOamByte, SetPixel, PrepareForNextPixel]);
line.add( 251, vec![ ReadOamByte , SetPixel, PrepareForNextPixel]);
line.add( 252, vec![GetPaletteIndex , WriteSecondaryOamByte, SetPixel, PrepareForNextPixel]);
line.add( 253, vec![ ReadOamByte , SetPixel, PrepareForNextPixel]);
line.add( 254, vec![GetPatternLowByte , WriteSecondaryOamByte, SetPixel, PrepareForNextPixel]);
line.add( 255, vec![ ReadOamByte , SetPixel, PrepareForNextPixel]);
line.add( 256, vec![GetPatternHighByte , GotoNextPixelRow , WriteSecondaryOamByte, SetPixel, PrepareForNextPixel]);
line.add( 257, vec![PrepareForNextTile , ResetTileColumn ]);
for sprite in 0..8 {
let cycle = 8 * sprite + 257;
line.add(cycle + 0, vec![ ReadSpriteY , ResetOamAddress ]);
line.add(cycle + 1, vec![GetPatternIndex , ReadSpritePatternIndex, ResetOamAddress ]);
line.add(cycle + 2, vec![ ReadSpriteAttributes , ResetOamAddress ]);
line.add(cycle + 3, vec![GetPatternIndex , ReadSpriteX , ResetOamAddress ]);
line.add(cycle + 4, vec![ DummyReadSpriteX , ResetOamAddress ]);
line.add(cycle + 5, vec![GetSpritePatternLowByte , DummyReadSpriteX , ResetOamAddress ]);
line.add(cycle + 6, vec![ DummyReadSpriteX , ResetOamAddress ]);
line.add(cycle + 7, vec![GetSpritePatternHighByte , DummyReadSpriteX , ResetOamAddress, IncrementOamRegisterIndex]);
}
line.add( 321, vec![ ReadSpriteY , PrepareForNextPixel]);
line.add( 322, vec![GetPatternIndex , ReadSpriteY , PrepareForNextPixel]);
line.add( 323, vec![ ReadSpriteY , PrepareForNextPixel]);
line.add( 324, vec![GetPaletteIndex , ReadSpriteY , PrepareForNextPixel]);
line.add( 325, vec![ ReadSpriteY , PrepareForNextPixel]);
line.add( 326, vec![GetPatternLowByte , ReadSpriteY , PrepareForNextPixel]);
line.add( 327, vec![ ReadSpriteY , PrepareForNextPixel]);
line.add( 328, vec![GetPatternHighByte , GotoNextTileColumn, ReadSpriteY , PrepareForNextPixel]);
line.add( 329, vec![PrepareForNextTile , ReadSpriteY , PrepareForNextPixel]);
line.add( 330, vec![GetPatternIndex , ReadSpriteY , PrepareForNextPixel]);
line.add( 331, vec![ ReadSpriteY , PrepareForNextPixel]);
line.add( 332, vec![GetPaletteIndex , ReadSpriteY , PrepareForNextPixel]);
line.add( 333, vec![ ReadSpriteY , PrepareForNextPixel]);
line.add( 334, vec![GetPatternLowByte , ReadSpriteY , PrepareForNextPixel]);
line.add( 335, vec![ ReadSpriteY , PrepareForNextPixel]);
line.add( 336, vec![GetPatternHighByte , GotoNextTileColumn, ReadSpriteY , PrepareForNextPixel]);
line.add( 337, vec![PrepareForNextTile , ReadSpriteY ]);
line.add( 338, vec![GetPatternIndex , ReadSpriteY ]);
line.add( 339, vec![ ReadSpriteY ]);
line.add( 340, vec![GetPatternIndex , ReadSpriteY ]);
line
});
pub static POST_RENDER_SCANLINE_ACTIONS: LazyLock<ScanlineActions> = LazyLock::new(|| {
let mut post_render_scanline = ScanlineActions::new();
post_render_scanline.prepend(0, CycleAction::StartPostRenderScanline);
post_render_scanline
});
pub static START_VBLANK_SCANLINE_ACTIONS: LazyLock<ScanlineActions> = LazyLock::new(|| {
use CycleAction::*;
let mut scanline = ScanlineActions::new();
scanline.add(0, vec![StartVblankScanlines]);
scanline.add(1, vec![StartVblank]);
scanline.add(3, vec![RequestNmi]);
scanline
});
pub static EMPTY_SCANLINE_ACTIONS: LazyLock<ScanlineActions> = LazyLock::new(ScanlineActions::new);
#[allow(clippy::identity_op)]
pub static PRE_RENDER_SCANLINE_ACTIONS: LazyLock<ScanlineActions> = LazyLock::new(|| {
use CycleAction::*;
let mut scanline = ScanlineActions::new();
scanline.add( 1, vec![ClearFlags ]);
scanline.add( 321, vec![StartReadingBackgroundTiles ]);
for cycle in 1..9 {
scanline.add(cycle , vec![MaybeCorruptOamStart ]);
}
for tile in 0..31 {
let cycle = 8 * tile + 1;
scanline.add(cycle + 1, vec![GetPatternIndex ]);
scanline.add(cycle + 3, vec![GetPaletteIndex ]);
scanline.add(cycle + 5, vec![GetPatternLowByte ]);
scanline.add(cycle + 7, vec![GetPatternHighByte , GotoNextTileColumn ]);
scanline.add(cycle + 8, vec![PrepareForNextTile ]);
}
scanline.add( 250, vec![GetPatternIndex ]);
scanline.add( 252, vec![GetPaletteIndex ]);
scanline.add( 254, vec![GetPatternLowByte ]);
scanline.add( 256, vec![GetPatternHighByte , GotoNextPixelRow ]);
scanline.add( 257, vec![PrepareForNextTile , ResetTileColumn ]);
for sprite in 0..8 {
let cycle = 8 * sprite + 257;
scanline.add(cycle + 0, vec![ ResetOamAddress ]);
scanline.add(cycle + 1, vec![ ResetOamAddress ]);
scanline.add(cycle + 2, vec![ ResetOamAddress ]);
scanline.add(cycle + 3, vec![ ResetOamAddress ]);
scanline.add(cycle + 4, vec![ ResetOamAddress ]);
scanline.add(cycle + 5, vec![GetSpritePatternLowByte , ResetOamAddress ]);
scanline.add(cycle + 6, vec![ ResetOamAddress ]);
scanline.add(cycle + 7, vec![GetSpritePatternHighByte , ResetOamAddress ]);
}
for cycle in 280..=304 {
scanline.add( cycle, vec![SetInitialYScroll ]);
}
scanline.add( 320, vec![SetInitialScrollOffsets ]);
scanline.add( 321, vec![ PrepareForNextPixel]);
scanline.add( 322, vec![GetPatternIndex , PrepareForNextPixel]);
scanline.add( 323, vec![ PrepareForNextPixel]);
scanline.add( 324, vec![GetPaletteIndex , PrepareForNextPixel]);
scanline.add( 325, vec![ PrepareForNextPixel]);
scanline.add( 326, vec![GetPatternLowByte , PrepareForNextPixel]);
scanline.add( 327, vec![ PrepareForNextPixel]);
scanline.add( 328, vec![GetPatternHighByte , GotoNextTileColumn, PrepareForNextPixel]);
scanline.add( 329, vec![PrepareForNextTile , PrepareForNextPixel]);
scanline.add( 330, vec![GetPatternIndex , PrepareForNextPixel]);
scanline.add( 331, vec![ PrepareForNextPixel]);
scanline.add( 332, vec![GetPaletteIndex , PrepareForNextPixel]);
scanline.add( 333, vec![ PrepareForNextPixel]);
scanline.add( 334, vec![GetPatternLowByte , PrepareForNextPixel]);
scanline.add( 335, vec![ PrepareForNextPixel]);
scanline.add( 336, vec![GetPatternHighByte , GotoNextTileColumn, PrepareForNextPixel]);
scanline.add( 337, vec![PrepareForNextTile ]);
scanline.add( 338, vec![GetPatternIndex ]);
scanline.add( 340, vec![GetPatternIndex ]);
scanline
});
pub static FIRST_VISIBLE_SCANLINE_ACTIONS: LazyLock<ScanlineActions> = LazyLock::new(|| {
let mut first_visible_scanline = VISIBLE_SCANLINE_ACTIONS.clone();
first_visible_scanline.prepend(1, CycleAction::StartVisibleScanlines);
first_visible_scanline
});
#[derive(Clone)]
pub struct ScanlineActions {
all_cycle_actions: Box<[Vec<CycleAction>; 341]>,
}
impl ScanlineActions {
pub fn actions_at_cycle(&self, cycle: u16) -> &Vec<CycleAction> {
&self.all_cycle_actions[usize::from(cycle)]
}
fn new() -> ScanlineActions {
ScanlineActions {
all_cycle_actions: Box::new(arr![Vec::new(); 341]),
}
}
fn add(&mut self, cycle: usize, mut actions: Vec<CycleAction>) {
self.all_cycle_actions[cycle].append(&mut actions);
}
pub(in crate::ppu::cycle_action) fn prepend(&mut self, cycle: usize, action: CycleAction) {
self.all_cycle_actions[cycle].insert(0, action);
}
}