mirror of
https://github.com/italicsjenga/agb.git
synced 2025-01-10 00:51:34 +11:00
switch to using new affine matrix
This commit is contained in:
parent
b80f1e5a79
commit
3497f7a720
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue