mirror of
https://github.com/italicsjenga/agb.git
synced 2025-02-02 12:36:35 +11:00
z ordering moving to a global controller state
This commit is contained in:
parent
a73e27dc7e
commit
2ef1dd0bf2
1 changed files with 134 additions and 68 deletions
|
@ -310,6 +310,7 @@ impl Storage {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
struct Attributes {
|
||||
a0: ObjectAttribute0,
|
||||
a1s: ObjectAttribute1Standard,
|
||||
|
@ -326,13 +327,37 @@ impl Attributes {
|
|||
a2: ObjectAttribute2::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn commit(&self, location: usize) {
|
||||
let mode = self.a0.object_mode();
|
||||
let attrs: [[u8; 2]; 3] = match mode {
|
||||
ObjectMode::Normal => [
|
||||
self.a0.into_bytes(),
|
||||
self.a1s.into_bytes(),
|
||||
self.a2.into_bytes(),
|
||||
],
|
||||
_ => [
|
||||
self.a0.into_bytes(),
|
||||
self.a1a.into_bytes(),
|
||||
self.a2.into_bytes(),
|
||||
],
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let attrs: [u16; 3] = core::mem::transmute(attrs);
|
||||
let ptr = (OBJECT_ATTRIBUTE_MEMORY as *mut u16).add(location * 4);
|
||||
|
||||
ptr.add(0).write_volatile(attrs[0]);
|
||||
ptr.add(1).write_volatile(attrs[1]);
|
||||
ptr.add(2).write_volatile(attrs[2]);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Object<'a, 'b> {
|
||||
sprite: SpriteBorrow<'a>,
|
||||
previous_sprite: SpriteBorrow<'a>,
|
||||
loan: Loan<'b>,
|
||||
attrs: Attributes,
|
||||
}
|
||||
|
||||
struct SpriteControllerInner {
|
||||
|
@ -347,28 +372,51 @@ struct Loan<'a> {
|
|||
|
||||
impl Drop for Loan<'_> {
|
||||
fn drop(&mut self) {
|
||||
let list = unsafe { &mut get_object_controller().free_objects };
|
||||
list.push(self.index);
|
||||
let s = unsafe { get_object_controller() };
|
||||
s.free_object.push(self.index);
|
||||
s.shadow_oam[self.index as usize] = None;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
struct ObjectInner {
|
||||
attrs: Attributes,
|
||||
z: i32,
|
||||
}
|
||||
|
||||
struct ObjectControllerStatic {
|
||||
free_affine_matricies: Vec<u8>,
|
||||
free_objects: Vec<u8>,
|
||||
free_object: Vec<u8>,
|
||||
shadow_oam: Vec<Option<ObjectInner>>,
|
||||
z_order: Vec<u8>,
|
||||
sprite_controller: SpriteControllerInner,
|
||||
}
|
||||
|
||||
impl ObjectControllerStatic {
|
||||
unsafe fn new() -> Self {
|
||||
Self {
|
||||
free_objects: (0..128).collect(),
|
||||
shadow_oam: (0..128).map(|_| None).collect(),
|
||||
z_order: (0..128).collect(),
|
||||
free_object: (0..128).collect(),
|
||||
free_affine_matricies: (0..32).collect(),
|
||||
sprite_controller: SpriteControllerInner::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn update_z_ordering(&mut self) {
|
||||
let shadow_oam = &self.shadow_oam;
|
||||
self.z_order.sort_by_key(|&a| {
|
||||
shadow_oam[a as usize]
|
||||
.as_ref()
|
||||
.map(|s| s.z)
|
||||
.unwrap_or(i32::MAX)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ObjectController {}
|
||||
pub struct ObjectController {
|
||||
phantom: PhantomData<UnsafeCell<()>>,
|
||||
}
|
||||
|
||||
impl Drop for ObjectController {
|
||||
fn drop(&mut self) {
|
||||
|
@ -378,7 +426,25 @@ impl Drop for ObjectController {
|
|||
}
|
||||
}
|
||||
|
||||
const HIDDEN_VALUE: u16 = 0b10 << 8;
|
||||
|
||||
impl ObjectController {
|
||||
pub fn commit(&self) {
|
||||
let s = unsafe { get_object_controller() };
|
||||
|
||||
for (i, &z) in s.z_order.iter().enumerate() {
|
||||
if let Some(o) = &s.shadow_oam[z as usize] {
|
||||
o.attrs.commit(i);
|
||||
} else {
|
||||
unsafe {
|
||||
(OBJECT_ATTRIBUTE_MEMORY as *mut u16)
|
||||
.add(i * 4)
|
||||
.write_volatile(HIDDEN_VALUE)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new() -> Self {
|
||||
DISPLAY_CONTROL.set_bits(1, 1, 0x6);
|
||||
DISPLAY_CONTROL.set_bits(1, 1, 0xC);
|
||||
|
@ -388,12 +454,14 @@ impl ObjectController {
|
|||
unsafe {
|
||||
(OBJECT_ATTRIBUTE_MEMORY as *mut u16)
|
||||
.add(i * 4)
|
||||
.write_volatile(0b10 << 8)
|
||||
.write_volatile(HIDDEN_VALUE)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe { init_object_controller() };
|
||||
Self {}
|
||||
Self {
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn object<'a, 'b>(&'a self, sprite: SpriteBorrow<'b>) -> Object<'b, 'a> {
|
||||
|
@ -402,10 +470,6 @@ impl ObjectController {
|
|||
|
||||
pub fn try_get_object<'a, 'b>(&'a self, sprite: SpriteBorrow<'b>) -> Option<Object<'b, 'a>> {
|
||||
let s = unsafe { get_object_controller() };
|
||||
let loan = Loan {
|
||||
index: s.free_objects.pop()?,
|
||||
phantom: PhantomData,
|
||||
};
|
||||
|
||||
let mut attrs = Attributes::new();
|
||||
|
||||
|
@ -416,11 +480,21 @@ impl ObjectController {
|
|||
attrs.a1a.set_size(shape_size.1);
|
||||
attrs.a1s.set_size(shape_size.1);
|
||||
|
||||
let index = s.free_object.pop()?;
|
||||
|
||||
s.shadow_oam[index as usize] = Some(ObjectInner { attrs, z: 0 });
|
||||
|
||||
let loan = Loan {
|
||||
index: index as u8,
|
||||
phantom: PhantomData,
|
||||
};
|
||||
|
||||
s.update_z_ordering();
|
||||
|
||||
Some(Object {
|
||||
previous_sprite: sprite.clone(),
|
||||
sprite,
|
||||
loan,
|
||||
attrs,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -435,94 +509,88 @@ impl ObjectController {
|
|||
}
|
||||
}
|
||||
|
||||
impl Drop for Object<'_, '_> {
|
||||
fn drop(&mut self) {
|
||||
self.attrs.a0.set_object_mode(ObjectMode::Disabled);
|
||||
self.commit();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Object<'a, 'b> {
|
||||
#[inline(always)]
|
||||
fn object_inner(&mut self) -> &mut ObjectInner {
|
||||
let s = unsafe { get_object_controller() };
|
||||
unsafe {
|
||||
s.shadow_oam[self.loan.index as usize]
|
||||
.as_mut()
|
||||
.unwrap_unchecked()
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn attrs(&mut self) -> &mut Attributes {
|
||||
&mut self.object_inner().attrs
|
||||
}
|
||||
|
||||
pub fn set_sprite(&'_ mut self, sprite: SpriteBorrow<'a>) {
|
||||
self.attrs.a2.set_tile_index(sprite.sprite_location);
|
||||
self.attrs().a2.set_tile_index(sprite.sprite_location);
|
||||
let shape_size = sprite.id.sprite().size.shape_size();
|
||||
self.attrs.a2.set_palete_bank(sprite.palette_location as u8);
|
||||
self.attrs.a0.set_shape(shape_size.0);
|
||||
self.attrs.a1a.set_size(shape_size.1);
|
||||
self.attrs.a1s.set_size(shape_size.1);
|
||||
self.attrs()
|
||||
.a2
|
||||
.set_palete_bank(sprite.palette_location as u8);
|
||||
self.attrs().a0.set_shape(shape_size.0);
|
||||
self.attrs().a1a.set_size(shape_size.1);
|
||||
self.attrs().a1s.set_size(shape_size.1);
|
||||
self.previous_sprite = self.sprite.clone();
|
||||
self.sprite = sprite;
|
||||
}
|
||||
|
||||
pub fn show(&mut self) -> &mut Self {
|
||||
self.attrs.a0.set_object_mode(ObjectMode::Normal);
|
||||
self.attrs().a0.set_object_mode(ObjectMode::Normal);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_hflip(&mut self, flip: bool) -> &mut Self {
|
||||
self.attrs.a1s.set_horizontal_flip(flip);
|
||||
self.attrs().a1s.set_horizontal_flip(flip);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_vflip(&mut self, flip: bool) -> &mut Self {
|
||||
self.attrs.a1s.set_vertical_flip(flip);
|
||||
self.attrs().a1s.set_vertical_flip(flip);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_x(&mut self, x: u16) -> &mut Self {
|
||||
self.attrs.a1a.set_x(x.rem_euclid(1 << 9) as u16);
|
||||
self.attrs.a1s.set_x(x.rem_euclid(1 << 9) as u16);
|
||||
self.attrs().a1a.set_x(x.rem_euclid(1 << 9) as u16);
|
||||
self.attrs().a1s.set_x(x.rem_euclid(1 << 9) as u16);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_priority(&mut self, priority: Priority) -> &mut Self {
|
||||
self.attrs.a2.set_priority(priority);
|
||||
self.attrs().a2.set_priority(priority);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn hide(&mut self) -> &mut Self {
|
||||
self.attrs.a0.set_object_mode(ObjectMode::Disabled);
|
||||
self.attrs().a0.set_object_mode(ObjectMode::Disabled);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_y(&mut self, y: u16) -> &mut Self {
|
||||
self.attrs.a0.set_y(y as u8);
|
||||
self.attrs().a0.set_y(y as u8);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_z(&mut self, z: i32) -> &mut Self {
|
||||
self.object_inner().z = z;
|
||||
unsafe {
|
||||
get_object_controller().update_z_ordering();
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_position(&mut self, position: Vector2D<i32>) -> &mut Self {
|
||||
self.attrs.a0.set_y(position.y as u8);
|
||||
self.attrs.a1a.set_x(position.x.rem_euclid(1 << 9) as u16);
|
||||
self.attrs.a1s.set_x(position.x.rem_euclid(1 << 9) as u16);
|
||||
self.attrs().a0.set_y(position.y as u8);
|
||||
self.attrs().a1a.set_x(position.x.rem_euclid(1 << 9) as u16);
|
||||
self.attrs().a1s.set_x(position.x.rem_euclid(1 << 9) as u16);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn commit(&mut self) {
|
||||
let mode = self.attrs.a0.object_mode();
|
||||
let attrs: [[u8; 2]; 3] = match mode {
|
||||
ObjectMode::Normal => [
|
||||
self.attrs.a0.into_bytes(),
|
||||
self.attrs.a1s.into_bytes(),
|
||||
self.attrs.a2.into_bytes(),
|
||||
],
|
||||
_ => [
|
||||
self.attrs.a0.into_bytes(),
|
||||
self.attrs.a1a.into_bytes(),
|
||||
self.attrs.a2.into_bytes(),
|
||||
],
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let attrs: [u16; 3] = core::mem::transmute(attrs);
|
||||
let ptr = (OBJECT_ATTRIBUTE_MEMORY as *mut u16).add(self.loan.index as usize * 4);
|
||||
|
||||
ptr.add(0).write_volatile(attrs[0]);
|
||||
ptr.add(1).write_volatile(attrs[1]);
|
||||
ptr.add(2).write_volatile(attrs[2]);
|
||||
};
|
||||
self.previous_sprite = self.sprite.clone();
|
||||
}
|
||||
}
|
||||
|
||||
/// The Sprite Id is a thin wrapper around the pointer to the sprite in
|
||||
|
@ -732,7 +800,7 @@ enum ColourMode {
|
|||
mod attributes {
|
||||
use super::*;
|
||||
#[bitfield]
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub(super) struct ObjectAttribute0 {
|
||||
pub y: B8,
|
||||
pub object_mode: ObjectMode,
|
||||
|
@ -743,7 +811,7 @@ mod attributes {
|
|||
}
|
||||
|
||||
#[bitfield]
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub(super) struct ObjectAttribute1Standard {
|
||||
pub x: B9,
|
||||
#[skip]
|
||||
|
@ -754,7 +822,7 @@ mod attributes {
|
|||
}
|
||||
|
||||
#[bitfield]
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub(super) struct ObjectAttribute1Affine {
|
||||
pub x: B9,
|
||||
pub affine_index: B5,
|
||||
|
@ -762,7 +830,7 @@ mod attributes {
|
|||
}
|
||||
|
||||
#[bitfield]
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub(super) struct ObjectAttribute2 {
|
||||
pub tile_index: B10,
|
||||
pub priority: Priority,
|
||||
|
@ -772,8 +840,6 @@ mod attributes {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::interrupt::add_interrupt_handler;
|
||||
|
||||
use super::*;
|
||||
use core::mem::size_of;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue