From 1af762bde6ccbfa9dc0bdf122af31795fb58d072 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Sun, 9 Oct 2022 01:40:26 -0600 Subject: [PATCH] make the tile layout during const time. --- examples/hello.rs | 38 ++++++++++++++++++++++++++++++-------- src/mmio.rs | 15 +++++++++++++++ src/video/mod.rs | 11 +++++++++-- 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/examples/hello.rs b/examples/hello.rs index 7cfccb0..0ff0253 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -15,13 +15,41 @@ fn panic_handler(info: &core::panic::PanicInfo) -> ! { loop {} } +#[link_section = ".ewram"] static FRAME_KEYS: GbaCell = GbaCell::new(KeyInput::new()); +#[link_section = ".iwram"] extern "C" fn irq_handler(_: IrqBits) { // We'll read the keys during vblank and store it for later. FRAME_KEYS.write(KEYINPUT.read()); } +const TILE_LAYOUT: [u32; 512] = { + // Rust's const eval is limited at the moment, but with a bit of careful math + // we can set up `u32` values that store the right data. Tile maps are 32x32 + // `u16` values, so when packing it as `u32` instead we have to throw in some + // `/2` stuff in a few places. Seperately, the tiles that we're using come + // from an image that was drawn as a 16 by 16 tile sheet, so most of the + // layout's area will be left as zero. Thankfully, tile index 0 is a blank + // tile in this tileset, so it all works out. + let mut data = [0; 512]; + let mut r = 0; + while r < 16 { + let mut c = 0; + while c < 16 { + let index = r * (32 / 2) + (c / 2); + let a = r * 16 + c; + let b = r * 16 + c + 1; + data[index] = (a as u32) | ((b as u32) << 16); + // + c += 2; + } + // + r += 1; + } + data +}; + #[no_mangle] extern "C" fn main() -> ! { RUST_IRQ_HANDLER.write(Some(irq_handler)); @@ -47,15 +75,9 @@ extern "C" fn main() -> ! { } { - // the the tilemap set up + // get the the tilemap copied into place let tsb = TextScreenblock::new(31); - for row in 0..16_usize { - for col in 0..16_usize { - let id = row * 16 + col; - let entry = TextEntry::new().with_tile_id(id as u16); - tsb.row_col(row, col).write(entry); - } - } + tsb.write_words(&TILE_LAYOUT); } { diff --git a/src/mmio.rs b/src/mmio.rs index 35d9b3f..8dfcced 100644 --- a/src/mmio.rs +++ b/src/mmio.rs @@ -255,6 +255,21 @@ macro_rules! make_me_a_screenblock { assert!(col < $size, concat!("`col` must be less than ", $size)); self.block.index(row * $size + col) } + + const WORD_COUNT: usize = (size_of::<$t>() * $size * $size)/4; + const _DEBUG_CHECK: () = { + assert!((size_of::<$t>() * $size * $size) % 4 == 0); + () + }; + + /// Overwrites the entire screenblock with the data provided. + pub fn write_words(self, words: &[u32; Self::WORD_COUNT]) { + use crate::prelude::__aeabi_memcpy4; + let dest: *mut u32 = self.block.index(0).as_usize() as *mut u32; + let src: *const u32 = words.as_ptr(); + let byte_count = size_of::<[u32; Self::WORD_COUNT]>(); + unsafe { __aeabi_memcpy4(dest.cast(), src.cast(), byte_count) }; + } } } } diff --git a/src/video/mod.rs b/src/video/mod.rs index 6775f71..1f2a65d 100644 --- a/src/video/mod.rs +++ b/src/video/mod.rs @@ -264,7 +264,7 @@ pub type Tile8 = [u32; 16]; /// An entry within a tile mode tilemap. /// -/// * `tile_id` is the index of the tile, offset from the `charblock` that the +/// * `tile` is the index of the tile, offset from the `charblock` that the /// background is using. This is a 10-bit value, so indexes are in the range /// `0..=1023`. You *cannot* index past the end of background VRAM into object /// VRAM (it just won't draw properly), but you *can* index past the end of @@ -278,10 +278,17 @@ pub type Tile8 = [u32; 16]; pub struct TextEntry(u16); impl TextEntry { pub_const_fn_new_zeroed!(); - u16_int_field!(0 - 9, tile_id, with_tile_id); + u16_int_field!(0 - 9, tile, with_tile); u16_bool_field!(10, hflip, with_hflip); u16_bool_field!(11, vflip, with_vflip); u16_int_field!(12 - 15, palbank, with_palbank); + + /// Shorthand for `TextEntry::new().with_tile(id)` + #[inline] + #[must_use] + pub const fn from_tile(id: u16) -> Self { + Self(id & 0b11_1111_1111) + } } #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]