diff --git a/agb/examples/animated_background.rs b/agb/examples/animated_background.rs new file mode 100644 index 00000000..d0dab120 --- /dev/null +++ b/agb/examples/animated_background.rs @@ -0,0 +1,48 @@ +#![no_std] +#![no_main] + +use agb::{ + display::{ + tiled::{TileFormat, TileSet, TileSetting}, + Priority, + }, + include_gfx, +}; + +include_gfx!("examples/water_tiles.toml"); + +#[agb::entry] +fn main(mut gba: agb::Gba) -> ! { + let (gfx, mut vram) = gba.display.video.tiled0(); + let vblank = agb::interrupt::VBlank::get(); + + let tileset = TileSet::new(water_tiles::water_tiles.tiles, TileFormat::FourBpp); + let tileset_ref = vram.add_tileset(tileset); + + vram.set_background_palettes(water_tiles::water_tiles.palettes); + + let mut bg = gfx.background(Priority::P0); + + for y in 0..20u16 { + for x in 0..30u16 { + bg.set_tile( + &mut vram, + (x, y).into(), + tileset_ref, + TileSetting::new(0, false, false, 0), + ); + } + } + + bg.commit(); + bg.show(); + + let mut i = 0; + loop { + i = (i + 1) % 8; + + vram.replace_tile(tileset_ref, 0, tileset_ref, i); + + vblank.wait_for_vblank(); + } +} diff --git a/agb/examples/water_tiles.png b/agb/examples/water_tiles.png new file mode 100644 index 00000000..ce846ee6 Binary files /dev/null and b/agb/examples/water_tiles.png differ diff --git a/agb/examples/water_tiles.toml b/agb/examples/water_tiles.toml new file mode 100644 index 00000000..9981e521 --- /dev/null +++ b/agb/examples/water_tiles.toml @@ -0,0 +1,5 @@ +version = "1.0" + +[image.water_tiles] +filename = "water_tiles.png" +tile_size = "8x8" \ No newline at end of file diff --git a/agb/src/display/tiled/vram_manager.rs b/agb/src/display/tiled/vram_manager.rs index dd71d3c9..d5110982 100644 --- a/agb/src/display/tiled/vram_manager.rs +++ b/agb/src/display/tiled/vram_manager.rs @@ -177,6 +177,45 @@ impl<'a> VRamManager<'a> { TileReference(NonNull::new(ptr as *mut _).unwrap()) } + pub fn replace_tile( + &mut self, + source_tile_set_ref: TileSetReference, + source_tile: u16, + target_tile_set_ref: TileSetReference, + target_tile: u16, + ) { + if let Some(&reference) = self + .tile_set_to_vram + .get(&(source_tile_set_ref.id, source_tile)) + { + let tile_slice = if let ArenaStorageItem::Data(data, generation) = + &self.tilesets[target_tile_set_ref.id as usize] + { + debug_assert_eq!( + *generation, target_tile_set_ref.generation, + "Stale tile data requested" + ); + + let tile_offset = (target_tile as usize) * data.format.tile_size(); + &data.tiles[tile_offset..(tile_offset + data.format.tile_size())] + } else { + panic!("Target tile set ref must point to an existing tile set reference") + }; + + let tile_size_in_half_words = tile_slice.len() / 2; + + let target_location = reference.0.as_ptr() as *mut _; + + unsafe { + dma_copy16( + tile_slice.as_ptr() as *const u16, + target_location, + tile_size_in_half_words, + ) + }; + } + } + pub(crate) fn add_tile(&mut self, tile_set_ref: TileSetReference, tile: u16) -> TileIndex { let reference = self.tile_set_to_vram.get(&(tile_set_ref.id, tile));