affine matricies!

This commit is contained in:
Corwin 2023-04-03 20:14:05 +01:00
parent 8d23af010f
commit 63088f2907
No known key found for this signature in database
7 changed files with 166 additions and 18 deletions

View file

@ -356,6 +356,15 @@ impl AffineMatrixObject {
y: 0.into(), y: 0.into(),
} }
} }
pub(crate) fn components(self) -> [u16; 4] {
[
self.a.to_raw() as u16,
self.b.to_raw() as u16,
self.c.to_raw() as u16,
self.d.to_raw() as u16,
]
}
} }
impl From<AffineMatrixObject> for AffineMatrix { impl From<AffineMatrixObject> for AffineMatrix {

View file

@ -1,3 +1,4 @@
mod affine;
mod managed; mod managed;
mod sprites; mod sprites;
mod unmanaged; mod unmanaged;
@ -7,9 +8,12 @@ pub use sprites::{
TagMap, TagMap,
}; };
pub use affine::AffineMatrix;
pub use managed::{OAMManager, Object}; pub use managed::{OAMManager, Object};
pub use unmanaged::{AffineMode, OAMIterator, OAMSlot, UnmanagedOAM, UnmanagedObject}; pub use unmanaged::{AffineMode, OAMIterator, OAMSlot, UnmanagedOAM, UnmanagedObject};
pub(crate) use affine::init_affine;
use super::DISPLAY_CONTROL; use super::DISPLAY_CONTROL;
const OBJECT_ATTRIBUTE_MEMORY: usize = 0x0700_0000; const OBJECT_ATTRIBUTE_MEMORY: usize = 0x0700_0000;

View file

@ -0,0 +1,115 @@
use alloc::rc::Rc;
use crate::{display::affine::AffineMatrixObject, sync::Static};
use super::OBJECT_ATTRIBUTE_MEMORY;
#[derive(Debug)]
struct AffineMatrixLocation {
location: u16,
}
#[derive(Debug, Clone)]
pub(crate) struct AffineMatrixVram(Rc<AffineMatrixLocation>);
#[derive(Debug)]
pub struct AffineMatrix {
location: AffineMatrixVram,
}
impl AffineMatrix {
pub fn new(affine_matrix: AffineMatrixObject) -> Option<AffineMatrix> {
let mut matrix = AFFINE_MATRIX_DISTRIBUTOR.get_matrix()?;
matrix.write(affine_matrix);
Some(matrix)
}
pub(crate) fn vram(self) -> AffineMatrixVram {
self.location
}
fn write(&mut self, affine_matrix: AffineMatrixObject) {
let components = affine_matrix.components();
let location = self.location.0.location as usize;
for (idx, component) in components.iter().enumerate() {
unsafe {
(OBJECT_ATTRIBUTE_MEMORY as *mut u16)
.add(location * 4 * idx + 3)
.write_volatile(*component);
}
}
}
}
impl AffineMatrixVram {
pub fn location(&self) -> u16 {
self.0.location
}
}
impl Drop for AffineMatrixLocation {
fn drop(&mut self) {
// safety: obtained via affine matrix distributor
unsafe { AFFINE_MATRIX_DISTRIBUTOR.return_matrix(self.location) }
}
}
struct AffineMatrixDistributor {
tip: Static<u16>,
}
static AFFINE_MATRIX_DISTRIBUTOR: AffineMatrixDistributor = AffineMatrixDistributor::new();
pub(crate) unsafe fn init_affine() {
AFFINE_MATRIX_DISTRIBUTOR.initialise_affine_matricies();
}
impl AffineMatrixDistributor {
const fn new() -> Self {
AffineMatrixDistributor {
tip: Static::new(u16::MAX),
}
}
unsafe fn initialise_affine_matricies(&self) {
for i in 0..32 {
let ptr = (OBJECT_ATTRIBUTE_MEMORY as *mut u16).add(i * 16 + 3);
if i == 31 {
// none
ptr.write_volatile(u16::MAX);
} else {
ptr.write_volatile(i as u16 + 1);
}
}
self.tip.write(0);
}
fn location_of(affine_matrix_location: u16) -> *mut u16 {
unsafe {
(OBJECT_ATTRIBUTE_MEMORY as *mut u16).add(affine_matrix_location as usize * 16 + 3)
}
}
fn get_matrix(&self) -> Option<AffineMatrix> {
let location = self.tip.read();
if location == u16::MAX {
return None;
}
let next_tip = unsafe { Self::location_of(location).read_volatile() };
self.tip.write(next_tip);
Some(AffineMatrix {
location: AffineMatrixVram(Rc::new(AffineMatrixLocation { location })),
})
}
unsafe fn return_matrix(&self, mat_id: u16) {
Self::location_of(mat_id).write_volatile(mat_id);
self.tip.write(mat_id);
}
}

View file

@ -1,15 +1,13 @@
use core::{ use core::cell::{Cell, UnsafeCell};
cell::{Cell, UnsafeCell},
marker::PhantomData,
};
use agb_fixnum::Vector2D; use agb_fixnum::Vector2D;
use alloc::vec::Vec;
use slotmap::{new_key_type, SlotMap}; use slotmap::{new_key_type, SlotMap};
use crate::display::Priority; use crate::display::Priority;
use super::{AffineMode, Sprite, SpriteVram, StaticSpriteLoader, UnmanagedOAM, UnmanagedObject}; use super::{
AffineMatrix, AffineMode, Sprite, SpriteVram, StaticSpriteLoader, UnmanagedOAM, UnmanagedObject,
};
new_key_type! {struct ObjectKey; } new_key_type! {struct ObjectKey; }
@ -416,6 +414,13 @@ impl Object<'_> {
self self
} }
pub fn set_affine_matrix(&mut self, affine_matrix: AffineMatrix) -> &mut Self {
// safety: only have one of these, doesn't modify slotmap
unsafe { self.object().set_affine_matrix(affine_matrix) };
self
}
pub fn set_sprite(&mut self, sprite: SpriteVram) -> &mut Self { pub fn set_sprite(&mut self, sprite: SpriteVram) -> &mut Self {
// safety: only have one of these, doesn't modify slotmap // safety: only have one of these, doesn't modify slotmap
unsafe { self.object().set_sprite(sprite) }; unsafe { self.object().set_sprite(sprite) };

View file

@ -6,7 +6,7 @@ use self::attributes::{
ObjectAttribute0, ObjectAttribute1Affine, ObjectAttribute1Standard, ObjectAttribute2, ObjectAttribute0, ObjectAttribute1Affine, ObjectAttribute1Standard, ObjectAttribute2,
}; };
#[derive(PartialEq, Eq, Debug)] #[derive(PartialEq, Eq, Debug, Clone)]
pub struct Attributes { pub struct Attributes {
a0: ObjectAttribute0, a0: ObjectAttribute0,
a1s: ObjectAttribute1Standard, a1s: ObjectAttribute1Standard,

View file

@ -4,7 +4,9 @@ use agb_fixnum::Vector2D;
use alloc::vec::Vec; use alloc::vec::Vec;
use crate::display::{ use crate::display::{
object::{sprites::SpriteVram, OBJECT_ATTRIBUTE_MEMORY}, object::{
affine::AffineMatrixVram, sprites::SpriteVram, AffineMatrix, OBJECT_ATTRIBUTE_MEMORY,
},
Priority, Priority,
}; };
@ -39,10 +41,7 @@ impl OAMSlot<'_> {
// SAFETY: This function is not reentrant and we currently hold a mutable borrow of the [UnmanagedOAM]. // 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() }; let frame_data = unsafe { &mut *self.frame_data.get() };
// SAFETY: This is called here and in set_sprite, neither of which call the other. frame_data.this_frame_sprites.push(object.sprite.clone());
let sprite = unsafe { &mut *object.sprites.get() };
frame_data.this_frame_sprites.push(sprite.clone());
frame_data.up_to = self.slot as i32; frame_data.up_to = self.slot as i32;
} }
@ -116,10 +115,11 @@ impl UnmanagedOAM<'_> {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct UnmanagedObject { pub struct UnmanagedObject {
attributes: Attributes, attributes: Attributes,
sprites: UnsafeCell<SpriteVram>, sprite: SpriteVram,
affine_matrix: Option<AffineMatrixVram>,
} }
impl UnmanagedObject { impl UnmanagedObject {
@ -131,7 +131,8 @@ impl UnmanagedObject {
let mut sprite = Self { let mut sprite = Self {
attributes: Attributes::default(), attributes: Attributes::default(),
sprites: UnsafeCell::new(sprite), sprite,
affine_matrix: None,
}; };
sprite.attributes.set_sprite(sprite_location, shape, size); sprite.attributes.set_sprite(sprite_location, shape, size);
@ -140,6 +141,7 @@ impl UnmanagedObject {
sprite sprite
} }
#[must_use]
pub fn is_visible(&self) -> bool { pub fn is_visible(&self) -> bool {
self.attributes.is_visible() self.attributes.is_visible()
} }
@ -151,6 +153,11 @@ impl UnmanagedObject {
} }
pub fn show_affine(&mut self, affine_mode: AffineMode) -> &mut Self { pub fn show_affine(&mut self, affine_mode: AffineMode) -> &mut Self {
assert!(
self.affine_matrix.is_some(),
"affine matrix must be set before enabling affine matrix!"
);
self.attributes.show_affine(affine_mode); self.attributes.show_affine(affine_mode);
self self
@ -199,6 +206,15 @@ impl UnmanagedObject {
self self
} }
pub fn set_affine_matrix(&mut self, affine_matrix: AffineMatrix) -> &mut Self {
let vram = affine_matrix.vram();
let location = vram.location();
self.affine_matrix = Some(vram);
self.attributes.set_affine_matrix(location);
self
}
fn set_sprite_attributes(&mut self, sprite: &SpriteVram) -> &mut Self { fn set_sprite_attributes(&mut self, sprite: &SpriteVram) -> &mut Self {
let size = sprite.size(); let size = sprite.size();
let (shape, size) = size.shape_size(); let (shape, size) = size.shape_size();
@ -212,9 +228,7 @@ impl UnmanagedObject {
pub fn set_sprite(&mut self, sprite: SpriteVram) -> &mut Self { pub fn set_sprite(&mut self, sprite: SpriteVram) -> &mut Self {
self.set_sprite_attributes(&sprite); self.set_sprite_attributes(&sprite);
// SAFETY: This is called here and in OAMSlot set, neither of which call the other. self.sprite = sprite;
let sprites = unsafe { &mut *self.sprites.get() };
*sprites = sprite;
self self
} }

View file

@ -236,6 +236,7 @@ impl Gba {
#[doc(hidden)] #[doc(hidden)]
#[must_use] #[must_use]
pub unsafe fn new_in_entry() -> Self { pub unsafe fn new_in_entry() -> Self {
display::object::init_affine();
Self::single_new() Self::single_new()
} }