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 core::{alloc::Layout, ptr::NonNull};
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::{slice, vec::Vec};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
agb_alloc::{block_allocator::BlockAllocator, bump_allocator::StartEnd},
|
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 {
|
pub struct VRamManager {
|
||||||
tile_set_to_vram: HashMap<TileInTileSetReference, TileReference>,
|
tile_set_to_vram: HashMap<TileInTileSetReference, TileReference>,
|
||||||
reference_counts: Vec<TileReferenceCount>,
|
reference_counts: Vec<TileReferenceCount>,
|
||||||
|
@ -144,6 +167,46 @@ impl VRamManager {
|
||||||
TileReference(NonNull::new(ptr as *mut _).unwrap())
|
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 {
|
pub(crate) fn add_tile(&mut self, tile_set: &TileSet<'_>, tile: u16) -> TileIndex {
|
||||||
let reference = self
|
let reference = self
|
||||||
.tile_set_to_vram
|
.tile_set_to_vram
|
||||||
|
|
Loading…
Reference in a new issue