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(),
|
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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
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::{
|
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) };
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue