switch to using new affine matrix

This commit is contained in:
Corwin 2022-10-09 00:42:14 +01:00
parent b80f1e5a79
commit 3497f7a720
4 changed files with 98 additions and 93 deletions

View file

@ -106,11 +106,11 @@ impl AffineMatrix {
pub fn try_to_background(&self) -> Result<AffineMatrixBackground, OverflowError> { pub fn try_to_background(&self) -> Result<AffineMatrixBackground, OverflowError> {
Ok(AffineMatrixBackground { Ok(AffineMatrixBackground {
a: self.a.to_raw().try_into().map_err(|_| OverflowError(()))?, a: self.a.to_raw().try_into().map_err(|_| OverflowError(()))?,
b: self.a.to_raw().try_into().map_err(|_| OverflowError(()))?, b: self.b.to_raw().try_into().map_err(|_| OverflowError(()))?,
c: self.a.to_raw().try_into().map_err(|_| OverflowError(()))?, c: self.c.to_raw().try_into().map_err(|_| OverflowError(()))?,
d: self.a.to_raw().try_into().map_err(|_| OverflowError(()))?, d: self.d.to_raw().try_into().map_err(|_| OverflowError(()))?,
x: self.a.to_raw(), x: self.x.to_raw(),
y: self.a.to_raw(), y: self.y.to_raw(),
}) })
} }
@ -120,11 +120,34 @@ impl AffineMatrix {
pub fn to_background_wrapping(&self) -> AffineMatrixBackground { pub fn to_background_wrapping(&self) -> AffineMatrixBackground {
AffineMatrixBackground { AffineMatrixBackground {
a: self.a.to_raw() as i16, a: self.a.to_raw() as i16,
b: self.a.to_raw() as i16, b: self.b.to_raw() as i16,
c: self.a.to_raw() as i16, c: self.c.to_raw() as i16,
d: self.a.to_raw() as i16, d: self.d.to_raw() as i16,
x: self.a.to_raw(), x: self.x.to_raw(),
y: self.a.to_raw(), y: self.y.to_raw(),
}
}
/// Attempts to convert the matrix to one which can be used in affine
/// objects.
pub fn try_to_object(&self) -> Result<AffineMatrixObject, OverflowError> {
Ok(AffineMatrixObject {
a: self.a.to_raw().try_into().map_err(|_| OverflowError(()))?,
b: self.b.to_raw().try_into().map_err(|_| OverflowError(()))?,
c: self.c.to_raw().try_into().map_err(|_| OverflowError(()))?,
d: self.d.to_raw().try_into().map_err(|_| OverflowError(()))?,
})
}
#[must_use]
/// Converts the matrix to one which can be used in affine objects
/// wrapping any value which is too large to be represented there.
pub fn to_object_wrapping(&self) -> AffineMatrixObject {
AffineMatrixObject {
a: self.a.to_raw() as i16,
b: self.b.to_raw() as i16,
c: self.c.to_raw() as i16,
d: self.d.to_raw() as i16,
} }
} }
} }
@ -143,6 +166,12 @@ pub struct AffineMatrixBackground {
y: i32, y: i32,
} }
impl Default for AffineMatrixBackground {
fn default() -> Self {
AffineMatrix::identity().to_background_wrapping()
}
}
impl TryFrom<AffineMatrix> for AffineMatrixBackground { impl TryFrom<AffineMatrix> for AffineMatrixBackground {
type Error = OverflowError; type Error = OverflowError;
@ -173,9 +202,50 @@ impl From<AffineMatrixBackground> for AffineMatrix {
} }
} }
impl Default for AffineMatrix { #[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(C, packed(4))]
/// An affine matrix that can be used in affine objects
pub struct AffineMatrixObject {
// Internally these can be thought of as Num<i16, 8>
a: i16,
b: i16,
c: i16,
d: i16,
}
impl Default for AffineMatrixObject {
fn default() -> Self { fn default() -> Self {
AffineMatrix::identity() AffineMatrix::identity().to_object_wrapping()
}
}
impl TryFrom<AffineMatrix> for AffineMatrixObject {
type Error = OverflowError;
fn try_from(value: AffineMatrix) -> Result<Self, Self::Error> {
value.try_to_object()
}
}
impl AffineMatrixObject {
#[must_use]
/// Converts to the affine matrix that is usable in performing efficient
/// calculations.
pub fn to_affine_matrix(&self) -> AffineMatrix {
AffineMatrix {
a: Num::from_raw(self.a.into()),
b: Num::from_raw(self.b.into()),
c: Num::from_raw(self.c.into()),
d: Num::from_raw(self.d.into()),
x: 0.into(),
y: 0.into(),
}
}
}
impl From<AffineMatrixObject> for AffineMatrix {
fn from(mat: AffineMatrixObject) -> Self {
mat.to_affine_matrix()
} }
} }

View file

@ -18,7 +18,7 @@ use super::{Priority, DISPLAY_CONTROL};
use crate::agb_alloc::block_allocator::BlockAllocator; use crate::agb_alloc::block_allocator::BlockAllocator;
use crate::agb_alloc::bump_allocator::StartEnd; use crate::agb_alloc::bump_allocator::StartEnd;
use crate::dma; use crate::dma;
use crate::fixnum::{Num, Vector2D}; use crate::fixnum::Vector2D;
use crate::hash_map::HashMap; use crate::hash_map::HashMap;
use attributes::*; use attributes::*;
@ -1193,42 +1193,6 @@ enum ColourMode {
Eight, Eight,
} }
/// The parameters used for the PPU's affine transformation function
/// that can apply to objects and background layers in modes 1 and 2.
/// This can be obtained from X/Y scale and rotation angle with
/// [`agb::syscall::affine_matrix`].
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(C, packed(4))]
pub struct AffineMatrixAttributes {
/// Adjustment made to *X* coordinate when drawing *horizontal* lines.
/// Also known as "dx".
/// Typically computed as `x_scale * cos(angle)`.
pub p_a: Num<i16, 8>,
/// Adjustment made to *X* coordinate along *vertical* lines.
/// Also known as "dmx".
/// Typically computed as `y_scale * sin(angle)`.
pub p_b: Num<i16, 8>,
/// Adjustment made to *Y* coordinate along *horizontal* lines.
/// Also known as "dy".
/// Typically computed as `-x_scale * sin(angle)`.
pub p_c: Num<i16, 8>,
/// Adjustment made to *Y* coordinate along *vertical* lines.
/// Also known as "dmy".
/// Typically computed as `y_scale * cos(angle)`.
pub p_d: Num<i16, 8>,
}
impl Default for AffineMatrixAttributes {
fn default() -> Self {
Self {
p_a: 1.into(),
p_b: Default::default(),
p_c: Default::default(),
p_d: 1.into(),
}
}
}
// this mod is not public, so the internal parts don't need documenting. // this mod is not public, so the internal parts don't need documenting.
#[allow(dead_code)] #[allow(dead_code)]
mod attributes { mod attributes {

View file

@ -2,7 +2,8 @@ use core::cell::RefCell;
use core::ops::{Deref, DerefMut}; use core::ops::{Deref, DerefMut};
use crate::bitarray::Bitarray; use crate::bitarray::Bitarray;
use crate::display::{object::AffineMatrixAttributes, Priority, DISPLAY_CONTROL}; use crate::display::affine::AffineMatrixBackground;
use crate::display::{Priority, DISPLAY_CONTROL};
use crate::dma::dma_copy16; use crate::dma::dma_copy16;
use crate::fixnum::{Num, Vector2D}; use crate::fixnum::{Num, Vector2D};
use crate::memory_mapped::MemoryMapped; use crate::memory_mapped::MemoryMapped;
@ -12,7 +13,6 @@ use super::{
RegularBackgroundSize, Tile, TileFormat, TileIndex, TileSet, TileSetting, VRamManager, RegularBackgroundSize, Tile, TileFormat, TileIndex, TileSet, TileSetting, VRamManager,
}; };
use crate::syscall::BgAffineSetData;
use alloc::{vec, vec::Vec}; use alloc::{vec, vec::Vec};
pub trait TiledMapTypes: private::Sealed { pub trait TiledMapTypes: private::Sealed {
@ -247,7 +247,7 @@ pub struct AffineMap {
scroll: Vector2D<i16>, scroll: Vector2D<i16>,
transform: BgAffineSetData, transform: AffineMatrixBackground,
tiles: Vec<u8>, tiles: Vec<u8>,
tiles_dirty: bool, tiles_dirty: bool,
@ -259,7 +259,7 @@ impl TiledMapTypes for AffineMap {
impl TiledMapPrivate for AffineMap { impl TiledMapPrivate for AffineMap {
type TileType = u8; type TileType = u8;
type AffineMatrix = AffineMatrixAttributes; type AffineMatrix = AffineMatrixBackground;
fn tiles_mut(&mut self) -> &mut [Self::TileType] { fn tiles_mut(&mut self) -> &mut [Self::TileType] {
&mut self.tiles &mut self.tiles
@ -280,10 +280,7 @@ impl TiledMapPrivate for AffineMap {
self.size self.size
} }
fn update_bg_registers(&self) { fn update_bg_registers(&self) {
let register_pos = self.transform.position; self.bg_affine_matrix().set(self.transform);
self.bg_x().set(register_pos.x);
self.bg_y().set(register_pos.y);
self.bg_affine_matrix().set(self.transform.matrix);
} }
fn scroll_pos(&self) -> Vector2D<i16> { fn scroll_pos(&self) -> Vector2D<i16> {
self.scroll self.scroll
@ -359,13 +356,7 @@ impl AffineMap {
crate::syscall::bg_affine_matrix(transform_origin.into(), self.scroll, scale, rotation); crate::syscall::bg_affine_matrix(transform_origin.into(), self.scroll, scale, rotation);
} }
fn bg_x(&self) -> MemoryMapped<Num<i32, 8>> { fn bg_affine_matrix(&self) -> MemoryMapped<AffineMatrixBackground> {
unsafe { MemoryMapped::new(0x0400_0008 + 0x10 * self.background_id()) }
}
fn bg_y(&self) -> MemoryMapped<Num<i32, 8>> {
unsafe { MemoryMapped::new(0x0400_000c + 0x10 * self.background_id()) }
}
fn bg_affine_matrix(&self) -> MemoryMapped<AffineMatrixAttributes> {
unsafe { MemoryMapped::new(0x0400_0000 + 0x10 * self.background_id()) } unsafe { MemoryMapped::new(0x0400_0000 + 0x10 * self.background_id()) }
} }
} }

View file

@ -2,7 +2,7 @@ use agb_fixnum::Vector2D;
use core::arch::asm; use core::arch::asm;
use core::mem::MaybeUninit; use core::mem::MaybeUninit;
use crate::display::object::AffineMatrixAttributes; use crate::display::affine::{AffineMatrixBackground, AffineMatrixObject};
use crate::fixnum::Num; use crate::fixnum::Num;
#[allow(non_snake_case)] #[allow(non_snake_case)]
@ -139,20 +139,6 @@ pub fn arc_tan2(x: i16, y: i32) -> i16 {
result result
} }
#[repr(C, packed(4))]
pub struct BgAffineSetData {
pub matrix: AffineMatrixAttributes,
pub position: Vector2D<Num<i32, 8>>,
}
impl Default for BgAffineSetData {
fn default() -> Self {
Self {
matrix: AffineMatrixAttributes::default(),
position: (0, 0).into(),
}
}
}
/// `rotation` is in revolutions. /// `rotation` is in revolutions.
#[must_use] #[must_use]
pub fn bg_affine_matrix( pub fn bg_affine_matrix(
@ -160,7 +146,7 @@ pub fn bg_affine_matrix(
display_center: Vector2D<i16>, display_center: Vector2D<i16>,
scale: Vector2D<Num<i16, 8>>, scale: Vector2D<Num<i16, 8>>,
rotation: Num<u16, 8>, rotation: Num<u16, 8>,
) -> BgAffineSetData { ) -> AffineMatrixBackground {
#[repr(C, packed(4))] #[repr(C, packed(4))]
struct Input { struct Input {
bg_center: Vector2D<Num<i32, 8>>, bg_center: Vector2D<Num<i32, 8>>,
@ -195,10 +181,7 @@ pub fn bg_affine_matrix(
/// `rotation` is in revolutions. /// `rotation` is in revolutions.
#[must_use] #[must_use]
pub fn obj_affine_matrix( pub fn obj_affine_matrix(scale: Vector2D<Num<i16, 8>>, rotation: Num<u8, 8>) -> AffineMatrixObject {
scale: Vector2D<Num<i16, 8>>,
rotation: Num<u8, 8>,
) -> AffineMatrixAttributes {
#[allow(dead_code)] #[allow(dead_code)]
#[repr(C, packed(4))] #[repr(C, packed(4))]
struct Input { struct Input {
@ -229,6 +212,8 @@ pub fn obj_affine_matrix(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::display::affine::AffineMatrix;
use super::*; use super::*;
#[test_case] #[test_case]
@ -237,10 +222,9 @@ mod tests {
let one: Num<i16, 8> = 1.into(); let one: Num<i16, 8> = 1.into();
let aff = obj_affine_matrix((one, one).into(), Num::default()); let aff = obj_affine_matrix((one, one).into(), Num::default());
let (p_a, p_d) = (aff.p_a, aff.p_d); let matrix = aff.to_affine_matrix();
assert_eq!(p_a, one); assert_eq!(matrix, AffineMatrix::identity());
assert_eq!(p_d, one);
} }
#[test_case] #[test_case]
@ -253,11 +237,7 @@ mod tests {
0.into(), 0.into(),
); );
let matrix = aff.matrix; let matrix = aff.to_affine_matrix();
let (p_a, p_b, p_c, p_d) = (matrix.p_a, matrix.p_b, matrix.p_c, matrix.p_d); assert_eq!(matrix, AffineMatrix::identity());
assert_eq!(p_a, 1.into());
assert_eq!(p_b, 0.into());
assert_eq!(p_c, 0.into());
assert_eq!(p_d, 1.into());
} }
} }