mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 16:21:33 +11:00
affine matricies!
This commit is contained in:
parent
8d23af010f
commit
63088f2907
|
@ -356,6 +356,15 @@ impl AffineMatrixObject {
|
|||
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 {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
mod affine;
|
||||
mod managed;
|
||||
mod sprites;
|
||||
mod unmanaged;
|
||||
|
@ -7,9 +8,12 @@ pub use sprites::{
|
|||
TagMap,
|
||||
};
|
||||
|
||||
pub use affine::AffineMatrix;
|
||||
pub use managed::{OAMManager, Object};
|
||||
pub use unmanaged::{AffineMode, OAMIterator, OAMSlot, UnmanagedOAM, UnmanagedObject};
|
||||
|
||||
pub(crate) use affine::init_affine;
|
||||
|
||||
use super::DISPLAY_CONTROL;
|
||||
|
||||
const OBJECT_ATTRIBUTE_MEMORY: usize = 0x0700_0000;
|
||||
|
|
115
agb/src/display/object/affine.rs
Normal file
115
agb/src/display/object/affine.rs
Normal 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);
|
||||
}
|
||||
}
|
|
@ -1,15 +1,13 @@
|
|||
use core::{
|
||||
cell::{Cell, UnsafeCell},
|
||||
marker::PhantomData,
|
||||
};
|
||||
use core::cell::{Cell, UnsafeCell};
|
||||
|
||||
use agb_fixnum::Vector2D;
|
||||
use alloc::vec::Vec;
|
||||
use slotmap::{new_key_type, SlotMap};
|
||||
|
||||
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; }
|
||||
|
||||
|
@ -416,6 +414,13 @@ impl Object<'_> {
|
|||
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 {
|
||||
// safety: only have one of these, doesn't modify slotmap
|
||||
unsafe { self.object().set_sprite(sprite) };
|
||||
|
|
|
@ -6,7 +6,7 @@ use self::attributes::{
|
|||
ObjectAttribute0, ObjectAttribute1Affine, ObjectAttribute1Standard, ObjectAttribute2,
|
||||
};
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||
pub struct Attributes {
|
||||
a0: ObjectAttribute0,
|
||||
a1s: ObjectAttribute1Standard,
|
||||
|
|
|
@ -4,7 +4,9 @@ use agb_fixnum::Vector2D;
|
|||
use alloc::vec::Vec;
|
||||
|
||||
use crate::display::{
|
||||
object::{sprites::SpriteVram, OBJECT_ATTRIBUTE_MEMORY},
|
||||
object::{
|
||||
affine::AffineMatrixVram, sprites::SpriteVram, AffineMatrix, OBJECT_ATTRIBUTE_MEMORY,
|
||||
},
|
||||
Priority,
|
||||
};
|
||||
|
||||
|
@ -39,10 +41,7 @@ impl OAMSlot<'_> {
|
|||
// 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 sprite = unsafe { &mut *object.sprites.get() };
|
||||
|
||||
frame_data.this_frame_sprites.push(sprite.clone());
|
||||
frame_data.this_frame_sprites.push(object.sprite.clone());
|
||||
|
||||
frame_data.up_to = self.slot as i32;
|
||||
}
|
||||
|
@ -116,10 +115,11 @@ impl UnmanagedOAM<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UnmanagedObject {
|
||||
attributes: Attributes,
|
||||
sprites: UnsafeCell<SpriteVram>,
|
||||
sprite: SpriteVram,
|
||||
affine_matrix: Option<AffineMatrixVram>,
|
||||
}
|
||||
|
||||
impl UnmanagedObject {
|
||||
|
@ -131,7 +131,8 @@ impl UnmanagedObject {
|
|||
|
||||
let mut sprite = Self {
|
||||
attributes: Attributes::default(),
|
||||
sprites: UnsafeCell::new(sprite),
|
||||
sprite,
|
||||
affine_matrix: None,
|
||||
};
|
||||
|
||||
sprite.attributes.set_sprite(sprite_location, shape, size);
|
||||
|
@ -140,6 +141,7 @@ impl UnmanagedObject {
|
|||
sprite
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_visible(&self) -> bool {
|
||||
self.attributes.is_visible()
|
||||
}
|
||||
|
@ -151,6 +153,11 @@ impl UnmanagedObject {
|
|||
}
|
||||
|
||||
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
|
||||
|
@ -199,6 +206,15 @@ impl UnmanagedObject {
|
|||
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 {
|
||||
let size = sprite.size();
|
||||
let (shape, size) = size.shape_size();
|
||||
|
@ -212,9 +228,7 @@ impl UnmanagedObject {
|
|||
pub fn set_sprite(&mut self, sprite: SpriteVram) -> &mut Self {
|
||||
self.set_sprite_attributes(&sprite);
|
||||
|
||||
// SAFETY: This is called here and in OAMSlot set, neither of which call the other.
|
||||
let sprites = unsafe { &mut *self.sprites.get() };
|
||||
*sprites = sprite;
|
||||
self.sprite = sprite;
|
||||
|
||||
self
|
||||
}
|
||||
|
|
|
@ -236,6 +236,7 @@ impl Gba {
|
|||
#[doc(hidden)]
|
||||
#[must_use]
|
||||
pub unsafe fn new_in_entry() -> Self {
|
||||
display::object::init_affine();
|
||||
Self::single_new()
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue