From 441c839ba7cf9ca8a6a4b9f79574898a9c0e2b13 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 31 Mar 2022 23:58:28 +0100 Subject: [PATCH] Add a slightly crappy dynamic tiles API --- agb/examples/dynamic_tiles.rs | 43 ++++++++++++++++++ agb/src/display/tiled/vram_manager.rs | 65 ++++++++++++++++++++++++++- 2 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 agb/examples/dynamic_tiles.rs diff --git a/agb/examples/dynamic_tiles.rs b/agb/examples/dynamic_tiles.rs new file mode 100644 index 00000000..aa70681b --- /dev/null +++ b/agb/examples/dynamic_tiles.rs @@ -0,0 +1,43 @@ +#![no_std] +#![no_main] + +use agb::display::{palette16::Palette16, tiled::TileSetting, Priority}; + +#[agb::entry] +fn main(mut gba: agb::Gba) -> ! { + let (gfx, mut vram) = gba.display.video.tiled0(); + let vblank = agb::interrupt::VBlank::get(); + + vram.set_background_palettes(&[Palette16::new([ + 0xff00, 0x0ff0, 0x00ff, 0xf00f, 0xf0f0, 0x0f0f, 0xaaaa, 0x5555, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + ])]); + + let mut bg = gfx.background(Priority::P0); + + for y in 0..20u16 { + for x in 0..30u16 { + let dynamic_tile = vram.new_dynamic_tile(); + + for (i, bit) in dynamic_tile.tile_data.iter_mut().enumerate() { + *bit = ((((x + i as u16) % 8) << 4) | ((y + i as u16) % 8)) as u8 + } + + bg.set_tile( + &mut vram, + (x, y).into(), + &dynamic_tile.tile_set(), + TileSetting::from_raw(dynamic_tile.tile_index()), + ); + + vram.remove_dynamic_tile(dynamic_tile); + } + } + + bg.commit(); + bg.show(); + + loop { + vblank.wait_for_vblank(); + } +} diff --git a/agb/src/display/tiled/vram_manager.rs b/agb/src/display/tiled/vram_manager.rs index 3fa5689d..acf9d39f 100644 --- a/agb/src/display/tiled/vram_manager.rs +++ b/agb/src/display/tiled/vram_manager.rs @@ -1,6 +1,6 @@ use core::{alloc::Layout, ptr::NonNull}; -use alloc::vec::Vec; +use alloc::{slice, vec::Vec}; use crate::{ agb_alloc::{block_allocator::BlockAllocator, bump_allocator::StartEnd}, @@ -118,6 +118,29 @@ impl TileReferenceCount { } } +#[non_exhaustive] +pub struct DynamicTile<'a> { + pub tile_data: &'a mut [u8], +} + +impl DynamicTile<'_> { + pub fn tile_set(&self) -> TileSet<'_> { + let tiles = unsafe { + slice::from_raw_parts_mut( + TILE_RAM_START as *mut u8, + 1024 * TileFormat::FourBpp.tile_size(), + ) + }; + + TileSet::new(tiles, TileFormat::FourBpp) + } + + pub fn tile_index(&self) -> u16 { + let difference = self.tile_data.as_ptr() as usize - TILE_RAM_START; + (difference / (8 * 8 / 2)) as u16 + } +} + pub struct VRamManager { tile_set_to_vram: HashMap, reference_counts: Vec, @@ -144,6 +167,46 @@ impl VRamManager { TileReference(NonNull::new(ptr as *mut _).unwrap()) } + pub fn new_dynamic_tile<'a>(&mut self) -> DynamicTile<'a> { + let tile_format = TileFormat::FourBpp; + let new_reference: NonNull = + unsafe { TILE_ALLOCATOR.alloc(TILE_LAYOUT) }.unwrap().cast(); + let tile_reference = TileReference(new_reference); + + let index = Self::index_from_reference(tile_reference); + + let tiles = unsafe { + slice::from_raw_parts_mut(TILE_RAM_START as *mut u8, 1024 * tile_format.tile_size()) + }; + + let tile_set = TileSet::new(tiles, tile_format); + + self.tile_set_to_vram.insert( + TileInTileSetReference::new(&tile_set, index as u16), + tile_reference, + ); + + self.reference_counts.resize( + self.reference_counts.len().max(index + 1), + Default::default(), + ); + self.reference_counts[index] = + TileReferenceCount::new(TileInTileSetReference::new(&tile_set, index as u16)); + + DynamicTile { + tile_data: &mut tiles + [index * tile_format.tile_size()..(index + 1) * tile_format.tile_size()], + } + } + + pub fn remove_dynamic_tile(&mut self, dynamic_tile: DynamicTile<'_>) { + let pointer = NonNull::new(dynamic_tile.tile_data.as_mut_ptr() as *mut _).unwrap(); + let tile_reference = TileReference(pointer); + + let tile_index = Self::index_from_reference(tile_reference); + self.remove_tile(TileIndex::new(tile_index)); + } + pub(crate) fn add_tile(&mut self, tile_set: &TileSet<'_>, tile: u16) -> TileIndex { let reference = self .tile_set_to_vram