From 52194cd38b7c7bae35abd3c1f6fafb95e73e6e85 Mon Sep 17 00:00:00 2001 From: 0xrsydn Date: Mon, 5 Oct 2026 12:55:35 +0700 Subject: [PATCH] feat(demo): exercise Mode 4 and 5 page switching --- src/bitmap_demo.rs | 75 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 src/bitmap_demo.rs diff --git a/src/bitmap_demo.rs b/src/bitmap_demo.rs new file mode 100644 index 0000000..5e44035 --- /dev/null +++ b/src/bitmap_demo.rs @@ -0,0 +1,75 @@ +//! Original Mode 4/5 page-flipping demos. ARM code copies both images through +//! BIOS services, samples input, and switches the displayed page during VBlank. + +use crate::{ + affine_demo, + graphics_demo::{GraphicsDemo, GraphicsError}, + input::Buttons, + machine::Machine, + memory::MemoryError, + video::Framebuffer, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u16)] +pub enum BitmapMode { + Mode4 = 4, + Mode5 = 5, +} + +/// Debug words: completed updates, signed pan X, signed pan Y. +pub const BITMAP_STATE: u32 = 0x0200_0000; + +pub struct BitmapDemo { + runner: GraphicsDemo, + mode: BitmapMode, +} +impl BitmapDemo { + pub fn new(mode: BitmapMode) -> Result { + Ok(Self { + runner: GraphicsDemo::with_program(affine_demo::bitmap_program(mode as u16))?, + mode, + }) + } + pub fn machine(&self) -> &Machine { + self.runner.machine() + } + pub fn frame( + &mut self, + buttons: Buttons, + output: &mut Framebuffer, + ) -> Result { + self.runner + .frame_with_control(buttons, output, 0x400 | self.mode as u16) + } +} + +pub(crate) fn assets(mode: u16) -> Vec { + let mut palette = [0_u16; 256]; + palette[0] = 0x4000; + for (i, color) in palette.iter_mut().enumerate().skip(1) { + *color = ((i & 31) | (((i >> 3) & 31) << 5) | (((i * 3) & 31) << 10)) as u16; + } + let mut data: Vec = palette.into_iter().flat_map(u16::to_le_bytes).collect(); + let mut vram = vec![0_u8; 0x14000]; + let (width, height) = if mode == 4 { (240, 160) } else { (160, 128) }; + for page in 0..2 { + for y in 0..height { + for x in 0..width { + let offset = y * width + x; + if mode == 4 { + vram[page * 0xa000 + offset] = ((x / 8 + 3 * (y / 8) + page * 64) & 255) as u8; + } else { + let color = (((x / 5 + page * 11) & 31) + | (((y / 4 + page * 7) & 31) << 5) + | (((x / 8 + y / 8 + page * 5) & 31) << 10)) + as u16; + let address = page * 0xa000 + offset * 2; + vram[address..address + 2].copy_from_slice(&color.to_le_bytes()); + } + } + } + } + data.extend(vram); + data +}