manage sprites better

This commit is contained in:
Corwin 2023-04-03 17:54:15 +01:00
parent 63e87b046b
commit 26b9a50e4e
No known key found for this signature in database
2 changed files with 44 additions and 52 deletions

View file

@ -27,7 +27,6 @@ struct ObjectItem {
struct Store {
store: UnsafeCell<slotmap::SlotMap<ObjectKey, ObjectItem>>,
removal_list: UnsafeCell<Vec<ObjectKey>>,
first_z: Cell<Option<ObjectKey>>,
}
@ -113,45 +112,32 @@ impl Store {
}
fn remove_object(&self, object: ObjectKey) {
remove_from_linked_list(self, object);
let data = unsafe { &mut *self.store.get() };
data.remove(object);
}
fn remove_all_in_removal_list(&self) {
let removal_list = unsafe { &mut *self.removal_list.get() };
for object in removal_list.drain(..) {
self.remove_object(object);
}
}
fn mark_for_removal(&self, object: ObjectKey) {
let removal_list = unsafe { &mut *self.removal_list.get() };
removal_list.push(object);
remove_from_linked_list(self, object);
}
fn get_object(&self, key: ObjectKey) -> &ObjectItem {
&(unsafe { &*self.store.get() }[key])
}
}
pub struct OAMManager<'gba> {
phantom: PhantomData<&'gba ()>,
object_store: Store,
sprite_loader: UnsafeCell<StaticSpriteLoader>,
unmanaged: UnsafeCell<UnmanagedOAM<'gba>>,
}
impl OAMManager<'_> {
pub(crate) fn new() -> Self {
Self {
phantom: PhantomData,
object_store: Store {
store: UnsafeCell::new(SlotMap::with_key()),
removal_list: UnsafeCell::new(Vec::new()),
first_z: Cell::new(None),
},
sprite_loader: UnsafeCell::new(StaticSpriteLoader::new()),
unmanaged: UnsafeCell::new(UnmanagedOAM::new()),
}
}
@ -167,9 +153,8 @@ impl OAMManager<'_> {
}
pub fn commit(&self) {
let mut unmanaged = UnmanagedOAM::new();
// do interactions with OAM
// safety: commit is not reentrant
let unmanaged = unsafe { &mut *self.unmanaged.get() };
for (object, mut slot) in unsafe { self.object_store.iter() }
.map(|item| unsafe { &*item.object.get() })
@ -179,9 +164,6 @@ impl OAMManager<'_> {
slot.set(object);
}
// finished OAM interactions
self.object_store.remove_all_in_removal_list();
// safety: not reentrant
unsafe {
self.do_work_with_sprite_loader(StaticSpriteLoader::garbage_collect);
@ -212,7 +194,7 @@ pub struct Object<'controller> {
impl Drop for Object<'_> {
fn drop(&mut self) {
self.store.mark_for_removal(self.me);
self.store.remove_object(self.me);
}
}

View file

@ -1,9 +1,7 @@
use core::{
cell::{Cell, UnsafeCell},
marker::PhantomData,
};
use core::{cell::UnsafeCell, marker::PhantomData};
use agb_fixnum::Vector2D;
use alloc::vec::Vec;
use crate::display::{
object::{sprites::SpriteVram, OBJECT_ATTRIBUTE_MEMORY},
@ -12,31 +10,41 @@ use crate::display::{
use super::attributes::{AffineMode, Attributes};
#[derive(Default, Debug)]
struct OamFrameModifyables {
up_to: i32,
this_frame_sprites: Vec<SpriteVram>,
}
pub struct UnmanagedOAM<'gba> {
phantom: PhantomData<&'gba ()>,
up_to: Cell<i32>,
frame_data: UnsafeCell<OamFrameModifyables>,
previous_frame_sprites: Vec<SpriteVram>,
}
pub struct OAMIterator<'oam> {
index: usize,
up_to: &'oam Cell<i32>,
frame_data: &'oam UnsafeCell<OamFrameModifyables>,
}
pub struct OAMSlot<'oam> {
slot: usize,
up_to: &'oam Cell<i32>,
frame_data: &'oam UnsafeCell<OamFrameModifyables>,
}
impl OAMSlot<'_> {
pub fn set(&mut self, object: &UnmanagedObject) {
self.set_bytes(object.attributes.bytes());
// SAFETY: This function is not reentrant and we currently hold a mutable borrow of the [UnmanagedOAM].
let frame_data = unsafe { &mut *self.frame_data.get() };
// SAFETY: This is called here and in set_sprite, neither of which call the other.
let sprites = unsafe { &mut *object.sprites.get() };
let sprite = unsafe { &mut *object.sprites.get() };
sprites.previous_sprite = Some(sprites.sprite.clone());
frame_data.this_frame_sprites.push(sprite.clone());
self.up_to.set(self.slot as i32);
frame_data.up_to = self.slot as i32;
}
fn set_bytes(&mut self, bytes: [u8; 6]) {
@ -59,7 +67,7 @@ impl<'oam> Iterator for OAMIterator<'oam> {
} else {
Some(OAMSlot {
slot: idx,
up_to: self.up_to,
frame_data: self.frame_data,
})
}
}
@ -67,7 +75,7 @@ impl<'oam> Iterator for OAMIterator<'oam> {
impl Drop for OAMIterator<'_> {
fn drop(&mut self) {
let last_written = self.up_to.get();
let last_written = unsafe { &*self.frame_data.get() }.up_to;
let number_writen = (last_written + 1) as usize;
@ -82,31 +90,36 @@ impl Drop for OAMIterator<'_> {
impl UnmanagedOAM<'_> {
pub fn iter(&mut self) -> OAMIterator<'_> {
self.up_to.set(-1);
let frame_data = self.frame_data.get_mut();
frame_data.up_to = -1;
// We drain the previous frame sprites here to reuse the Vecs allocation and remove the now unused sprites.
// Any sprites currently being shown will now be put in the new Vec.
self.previous_frame_sprites.drain(..);
core::mem::swap(
&mut frame_data.this_frame_sprites,
&mut self.previous_frame_sprites,
);
OAMIterator {
index: 0,
up_to: &self.up_to,
frame_data: &self.frame_data,
}
}
pub(crate) fn new() -> Self {
Self {
up_to: Cell::new(-1),
frame_data: Default::default(),
phantom: PhantomData,
previous_frame_sprites: Default::default(),
}
}
}
#[derive(Debug)]
struct VramSprites {
sprite: SpriteVram,
previous_sprite: Option<SpriteVram>,
}
#[derive(Debug)]
pub struct UnmanagedObject {
attributes: Attributes,
sprites: UnsafeCell<VramSprites>,
sprites: UnsafeCell<SpriteVram>,
}
impl UnmanagedObject {
@ -118,10 +131,7 @@ impl UnmanagedObject {
let mut sprite = Self {
attributes: Attributes::default(),
sprites: UnsafeCell::new(VramSprites {
sprite,
previous_sprite: None,
}),
sprites: UnsafeCell::new(sprite),
};
sprite.attributes.set_sprite(sprite_location, shape, size);
@ -204,7 +214,7 @@ impl UnmanagedObject {
// SAFETY: This is called here and in OAMSlot set, neither of which call the other.
let sprites = unsafe { &mut *self.sprites.get() };
sprites.sprite = sprite;
*sprites = sprite;
self
}