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> {
Ok(AffineMatrixBackground {
a: self.a.to_raw().try_into().map_err(|_| OverflowError(()))?,
b: self.a.to_raw().try_into().map_err(|_| OverflowError(()))?,
c: self.a.to_raw().try_into().map_err(|_| OverflowError(()))?,
d: self.a.to_raw().try_into().map_err(|_| OverflowError(()))?,
x: self.a.to_raw(),
y: self.a.to_raw(),
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(()))?,
x: self.x.to_raw(),
y: self.y.to_raw(),
})
}
@ -120,11 +120,34 @@ impl AffineMatrix {
pub fn to_background_wrapping(&self) -> AffineMatrixBackground {
AffineMatrixBackground {
a: self.a.to_raw() as i16,
b: self.a.to_raw() as i16,
c: self.a.to_raw() as i16,
d: self.a.to_raw() as i16,
x: self.a.to_raw(),
y: self.a.to_raw(),
b: self.b.to_raw() as i16,
c: self.c.to_raw() as i16,
d: self.d.to_raw() as i16,
x: self.x.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,
}
impl Default for AffineMatrixBackground {
fn default() -> Self {
AffineMatrix::identity().to_background_wrapping()
}
}
impl TryFrom<AffineMatrix> for AffineMatrixBackground {
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 {
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::bump_allocator::StartEnd;
use crate::dma;
use crate::fixnum::{Num, Vector2D};
use crate::fixnum::Vector2D;
use crate::hash_map::HashMap;
use attributes::*;
@ -1193,42 +1193,6 @@ enum ColourMode {
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.
#[allow(dead_code)]
mod attributes {

View file

@ -2,7 +2,8 @@ use core::cell::RefCell;
use core::ops::{Deref, DerefMut};
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::fixnum::{Num, Vector2D};
use crate::memory_mapped::MemoryMapped;
@ -12,7 +13,6 @@ use super::{
RegularBackgroundSize, Tile, TileFormat, TileIndex, TileSet, TileSetting, VRamManager,
};
use crate::syscall::BgAffineSetData;
use alloc::{vec, vec::Vec};
pub trait TiledMapTypes: private::Sealed {
@ -247,7 +247,7 @@ pub struct AffineMap {
scroll: Vector2D<i16>,
transform: BgAffineSetData,
transform: AffineMatrixBackground,
tiles: Vec<u8>,
tiles_dirty: bool,
@ -259,7 +259,7 @@ impl TiledMapTypes for AffineMap {
impl TiledMapPrivate for AffineMap {
type TileType = u8;
type AffineMatrix = AffineMatrixAttributes;
type AffineMatrix = AffineMatrixBackground;
fn tiles_mut(&mut self) -> &mut [Self::TileType] {
&mut self.tiles
@ -280,10 +280,7 @@ impl TiledMapPrivate for AffineMap {
self.size
}
fn update_bg_registers(&self) {
let register_pos = self.transform.position;
self.bg_x().set(register_pos.x);
self.bg_y().set(register_pos.y);
self.bg_affine_matrix().set(self.transform.matrix);
self.bg_affine_matrix().set(self.transform);
}
fn scroll_pos(&self) -> Vector2D<i16> {
self.scroll
@ -359,13 +356,7 @@ impl AffineMap {
crate::syscall::bg_affine_matrix(transform_origin.into(), self.scroll, scale, rotation);
}
fn bg_x(&self) -> MemoryMapped<Num<i32, 8>> {
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> {
fn bg_affine_matrix(&self) -> MemoryMapped<AffineMatrixBackground> {
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::mem::MaybeUninit;
use crate::display::object::AffineMatrixAttributes;
use crate::display::affine::{AffineMatrixBackground, AffineMatrixObject};
use crate::fixnum::Num;
#[allow(non_snake_case)]
@ -139,20 +139,6 @@ pub fn arc_tan2(x: i16, y: i32) -> i16 {
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.
#[must_use]
pub fn bg_affine_matrix(
@ -160,7 +146,7 @@ pub fn bg_affine_matrix(
display_center: Vector2D<i16>,
scale: Vector2D<Num<i16, 8>>,
rotation: Num<u16, 8>,
) -> BgAffineSetData {
) -> AffineMatrixBackground {
#[repr(C, packed(4))]
struct Input {
bg_center: Vector2D<Num<i32, 8>>,
@ -195,10 +181,7 @@ pub fn bg_affine_matrix(
/// `rotation` is in revolutions.
#[must_use]
pub fn obj_affine_matrix(
scale: Vector2D<Num<i16, 8>>,
rotation: Num<u8, 8>,
) -> AffineMatrixAttributes {
pub fn obj_affine_matrix(scale: Vector2D<Num<i16, 8>>, rotation: Num<u8, 8>) -> AffineMatrixObject {
#[allow(dead_code)]
#[repr(C, packed(4))]
struct Input {
@ -229,6 +212,8 @@ pub fn obj_affine_matrix(
#[cfg(test)]
mod tests {
use crate::display::affine::AffineMatrix;
use super::*;
#[test_case]
@ -237,10 +222,9 @@ mod tests {
let one: Num<i16, 8> = 1.into();
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!(p_d, one);
assert_eq!(matrix, AffineMatrix::identity());
}
#[test_case]
@ -253,11 +237,7 @@ mod tests {
0.into(),
);
let matrix = aff.matrix;
let (p_a, p_b, p_c, p_d) = (matrix.p_a, matrix.p_b, matrix.p_c, matrix.p_d);
assert_eq!(p_a, 1.into());
assert_eq!(p_b, 0.into());
assert_eq!(p_c, 0.into());
assert_eq!(p_d, 1.into());
let matrix = aff.to_affine_matrix();
assert_eq!(matrix, AffineMatrix::identity());
}
}