mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-24 00:31:34 +11:00
Merge pull request #207 from gwilymk/dynamic-tileset
Add a slightly crappy dynamic tiles API
This commit is contained in:
commit
c3a64690cd
43
agb/examples/dynamic_tiles.rs
Normal file
43
agb/examples/dynamic_tiles.rs
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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<TileInTileSetReference, TileReference>,
|
||||
reference_counts: Vec<TileReferenceCount>,
|
||||
|
@ -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<u32> =
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue