diff --git a/agb/src/number.rs b/agb/src/number.rs index d129b153..8be2b96a 100644 --- a/agb/src/number.rs +++ b/agb/src/number.rs @@ -1,12 +1,83 @@ use core::{ + cmp::{Eq, Ord, PartialEq, PartialOrd}, fmt::{Debug, Display}, - ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign}, + ops::{ + Add, AddAssign, BitAnd, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, Shr, + Sub, SubAssign, + }, }; -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct Num(i32); +pub trait FixedWidthUnsignedInteger: + Sized + + Copy + + PartialOrd + + Ord + + PartialEq + + Eq + + Shl + + Shr + + Add + + Sub + + Not + + BitAnd + + Rem + + Div + + Mul + + From + + Debug + + Display +{ + fn zero() -> Self; + fn one() -> Self; + fn ten() -> Self; +} -pub fn change_base(num: Num) -> Num { +pub trait FixedWidthSignedInteger: FixedWidthUnsignedInteger + Neg { + fn fixed_abs(self) -> Self; +} + +macro_rules! fixed_width_unsigned_integer_impl { + ($T: ty) => { + impl FixedWidthUnsignedInteger for $T { + fn zero() -> Self { + 0 + } + fn one() -> Self { + 1 + } + fn ten() -> Self { + 10 + } + } + }; +} + +macro_rules! fixed_width_signed_integer_impl { + ($T: ty) => { + impl FixedWidthSignedInteger for $T { + fn fixed_abs(self) -> Self { + self.abs() + } + } + }; +} + +fixed_width_unsigned_integer_impl!(i16); +fixed_width_unsigned_integer_impl!(u16); +fixed_width_unsigned_integer_impl!(i32); +fixed_width_unsigned_integer_impl!(u32); + +fixed_width_signed_integer_impl!(i16); +fixed_width_signed_integer_impl!(i32); + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct Num(I); + +pub type Number = Num; + +pub fn change_base( + num: Num, +) -> Num { if N < M { Num(num.0 << (M - N)) } else { @@ -14,15 +85,16 @@ pub fn change_base(num: Num) -> Num { } } -impl From for Num { - fn from(value: i32) -> Self { +impl From for Num { + fn from(value: I) -> Self { Num(value << N) } } -impl Add for Num +impl Add for Num where - T: Into>, + I: FixedWidthUnsignedInteger, + T: Into>, { type Output = Self; fn add(self, rhs: T) -> Self::Output { @@ -30,18 +102,20 @@ where } } -impl AddAssign for Num +impl AddAssign for Num where - T: Into>, + I: FixedWidthUnsignedInteger, + T: Into>, { fn add_assign(&mut self, rhs: T) { self.0 = (*self + rhs.into()).0 } } -impl Sub for Num +impl Sub for Num where - T: Into>, + I: FixedWidthUnsignedInteger, + T: Into>, { type Output = Self; fn sub(self, rhs: T) -> Self::Output { @@ -49,18 +123,20 @@ where } } -impl SubAssign for Num +impl SubAssign for Num where - T: Into>, + I: FixedWidthUnsignedInteger, + T: Into>, { fn sub_assign(&mut self, rhs: T) { self.0 = (*self - rhs.into()).0 } } -impl Mul for Num +impl Mul for Num where - T: Into>, + I: FixedWidthUnsignedInteger, + T: Into>, { type Output = Self; fn mul(self, rhs: T) -> Self::Output { @@ -68,18 +144,20 @@ where } } -impl MulAssign for Num +impl MulAssign for Num where - T: Into>, + I: FixedWidthUnsignedInteger, + T: Into>, { fn mul_assign(&mut self, rhs: T) { self.0 = (*self * rhs.into()).0 } } -impl Div for Num +impl Div for Num where - T: Into>, + I: FixedWidthUnsignedInteger, + T: Into>, { type Output = Self; fn div(self, rhs: T) -> Self::Output { @@ -87,18 +165,20 @@ where } } -impl DivAssign for Num +impl DivAssign for Num where - T: Into>, + I: FixedWidthUnsignedInteger, + T: Into>, { fn div_assign(&mut self, rhs: T) { self.0 = (*self / rhs.into()).0 } } -impl Rem for Num +impl Rem for Num where - T: Into>, + I: FixedWidthUnsignedInteger, + T: Into>, { type Output = Self; fn rem(self, modulus: T) -> Self::Output { @@ -106,45 +186,38 @@ where } } -impl RemAssign for Num +impl RemAssign for Num where - T: Into>, + I: FixedWidthUnsignedInteger, + T: Into>, { fn rem_assign(&mut self, modulus: T) { self.0 = (*self % modulus).0 } } -impl Neg for Num { +impl Neg for Num { type Output = Self; fn neg(self) -> Self::Output { Num(-self.0) } } -impl Num { - pub const fn max() -> Self { - Num(i32::MAX) - } - - pub const fn min() -> Self { - Num(i32::MIN) - } - - pub const fn from_raw(n: i32) -> Self { +impl Num { + pub fn from_raw(n: I) -> Self { Num(n) } - pub const fn to_raw(&self) -> i32 { + pub fn to_raw(self) -> I { self.0 } - pub const fn trunc(&self) -> i32 { - let fractional_part = self.0 & ((1 << N) - 1); + pub fn trunc(&self) -> I { + let fractional_part = self.0 & ((I::one() << N) - I::one()); let self_as_int = self.0 >> N; - if self_as_int < 0 && fractional_part != 0 { - self_as_int + 1 + if self_as_int < I::zero() && fractional_part != I::zero() { + self_as_int + I::one() } else { self_as_int } @@ -152,8 +225,8 @@ impl Num { pub fn rem_euclid(&self, rhs: Self) -> Self { let r = *self % rhs; - if r < 0.into() { - if rhs < 0.into() { + if r < I::zero().into() { + if rhs < I::zero().into() { r - rhs } else { r + rhs @@ -163,48 +236,57 @@ impl Num { } } - pub const fn floor(&self) -> i32 { + pub fn floor(&self) -> I { self.0 >> N } - pub const fn abs(self) -> Self { - Num(self.0.abs()) + pub fn new(integral: I) -> Self { + Self(integral << N) + } +} + +impl Num { + pub fn abs(self) -> Self { + Num(self.0.fixed_abs()) } /// domain of [0, 1]. /// see https://github.com/tarcieri/micromath/blob/24584465b48ff4e87cffb709c7848664db896b4f/src/float/cos.rs#L226 pub fn cos(self) -> Self { - let one: Self = 1.into(); + let one: Self = I::one().into(); let mut x = self; - x -= one / 4 + (x + one / 4).floor(); - x *= (x.abs() - one / 2) * 16; - x += x * (x.abs() - 1) * 9 / 40; + let four: I = 4.into(); + let two: I = 2.into(); + let sixteen: I = 16.into(); + let nine: I = 9.into(); + let forty: I = 40.into(); + + x -= one / four + (x + one / four).floor(); + x *= (x.abs() - one / two) * sixteen; + x += x * (x.abs() - one) * (nine / forty); x } pub fn sin(self) -> Self { - let one: Self = 1.into(); - (self - one / 4).cos() - } - - pub const fn new(integral: i32) -> Self { - Self(integral << N) + let one: Self = I::one().into(); + let four: I = 4.into(); + (self - one / four).cos() } } #[test_case] fn test_numbers(_gba: &mut super::Gba) { // test addition - let n: Num<8> = 1.into(); + let n: Num = 1.into(); assert_eq!(n + 2, 3.into(), "testing that 1 + 2 == 3"); // test multiplication - let n: Num<8> = 5.into(); + let n: Num = 5.into(); assert_eq!(n * 3, 15.into(), "testing that 5 * 3 == 15"); // test division - let n: Num<8> = 30.into(); - let p: Num<8> = 3.into(); + let n: Num = 30.into(); + let p: Num = 3.into(); assert_eq!(n / 20, p / 2, "testing that 30 / 20 == 3 / 2"); assert_ne!(n, p, "testing that 30 != 3"); @@ -212,20 +294,20 @@ fn test_numbers(_gba: &mut super::Gba) { #[test_case] fn test_division_by_one(_gba: &mut super::Gba) { - let one: Num<8> = 1.into(); + let one: Num = 1.into(); for i in -40..40 { - let n: Num<8> = i.into(); + let n: Num = i.into(); assert_eq!(n / one, n); } } #[test_case] fn test_division_and_multiplication_by_16(_gba: &mut super::Gba) { - let sixteen: Num<8> = 16.into(); + let sixteen: Num = 16.into(); for i in -40..40 { - let n: Num<8> = i.into(); + let n: Num = i.into(); let m = n / sixteen; assert_eq!(m * sixteen, n); @@ -234,12 +316,12 @@ fn test_division_and_multiplication_by_16(_gba: &mut super::Gba) { #[test_case] fn test_division_by_2_and_15(_gba: &mut super::Gba) { - let two: Num<8> = 2.into(); - let fifteen: Num<8> = 15.into(); - let thirty: Num<8> = 30.into(); + let two: Num = 2.into(); + let fifteen: Num = 15.into(); + let thirty: Num = 30.into(); for i in -128..128 { - let n: Num<8> = i.into(); + let n: Num = i.into(); assert_eq!(n / two / fifteen, n / thirty); assert_eq!(n / fifteen / two, n / thirty); @@ -248,8 +330,8 @@ fn test_division_by_2_and_15(_gba: &mut super::Gba) { #[test_case] fn test_change_base(_gba: &mut super::Gba) { - let two: Num<9> = 2.into(); - let three: Num<4> = 3.into(); + let two: Num = 2.into(); + let three: Num = 3.into(); assert_eq!(two + change_base(three), 5.into()); assert_eq!(three + change_base(two), 5.into()); @@ -264,7 +346,7 @@ fn test_rem_returns_sensible_values_for_integers(_gba: &mut super::Gba) { } let i_rem_j_normally = i % j; - let i_fixnum: Num<8> = i.into(); + let i_fixnum: Num = i.into(); assert_eq!(i_fixnum % j, i_rem_j_normally.into()); } @@ -273,7 +355,7 @@ fn test_rem_returns_sensible_values_for_integers(_gba: &mut super::Gba) { #[test_case] fn test_rem_returns_sensible_values_for_non_integers(_gba: &mut super::Gba) { - let one: Num<8> = 1.into(); + let one: Num = 1.into(); let third = one / 3; for i in -50..50 { @@ -283,10 +365,10 @@ fn test_rem_returns_sensible_values_for_non_integers(_gba: &mut super::Gba) { } // full calculation in the normal way - let x: Num<8> = third + i; - let y: Num<8> = j.into(); + let x: Num = third + i; + let y: Num = j.into(); - let truncated_division: Num<8> = (x / y).trunc().into(); + let truncated_division: Num = (x / y).trunc().into(); let remainder = x - truncated_division * y; @@ -297,7 +379,7 @@ fn test_rem_returns_sensible_values_for_non_integers(_gba: &mut super::Gba) { #[test_case] fn test_rem_euclid_is_always_positive_and_sensible(_gba: &mut super::Gba) { - let one: Num<8> = 1.into(); + let one: Num = 1.into(); let third = one / 3; for i in -50..50 { @@ -306,13 +388,8 @@ fn test_rem_euclid_is_always_positive_and_sensible(_gba: &mut super::Gba) { continue; } - // full calculation in the normal way - let x: Num<8> = third + i; - let y: Num<8> = j.into(); - - let truncated_division: Num<8> = (x / y).trunc().into(); - - let remainder = x - truncated_division * y; + let x: Num = third + i; + let y: Num = j.into(); let rem_euclid = x.rem_euclid(y); assert!(rem_euclid > 0.into()); @@ -320,29 +397,32 @@ fn test_rem_euclid_is_always_positive_and_sensible(_gba: &mut super::Gba) { } } -impl Display for Num { +impl Display for Num { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let integral = self.0 >> N; - let mask: u32 = (1 << N) - 1; + let mask: I = (I::one() << N) - I::one(); write!(f, "{}", integral)?; - let mut fractional = self.0 as u32 & mask; - if fractional & mask != 0 { + let mut fractional = self.0 & mask; + if fractional & mask != I::zero() { write!(f, ".")?; } - while fractional & mask != 0 { - fractional *= 10; + + while fractional & mask != I::zero() { + fractional = fractional * I::ten(); write!(f, "{}", (fractional & !mask) >> N)?; - fractional &= mask; + fractional = fractional & mask; } Ok(()) } } -impl Debug for Num { +impl Debug for Num { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "Num<{}>({})", N, self) + use core::any::type_name; + + write!(f, "Num<{}, {}>({})", type_name::(), N, self) } } diff --git a/agb/src/syscall.rs b/agb/src/syscall.rs index b30cb6a4..49e1fc53 100644 --- a/agb/src/syscall.rs +++ b/agb/src/syscall.rs @@ -106,7 +106,11 @@ pub fn arc_tan2(x: i16, y: i32) -> i16 { result } -pub fn affine_matrix(x_scale: Num<8>, y_scale: Num<8>, rotation: u8) -> AffineMatrixAttributes { +pub fn affine_matrix( + x_scale: Num, + y_scale: Num, + rotation: u8, +) -> AffineMatrixAttributes { let mut result = AffineMatrixAttributes { p_a: 0, p_b: 0, @@ -125,8 +129,8 @@ pub fn affine_matrix(x_scale: Num<8>, y_scale: Num<8>, rotation: u8) -> AffineMa let rotation_for_input = (rotation as u16) << 8; let input = Input { - y_scale: x_scale.to_raw() as i16, - x_scale: y_scale.to_raw() as i16, + y_scale: x_scale.to_raw(), + x_scale: y_scale.to_raw(), rotation: rotation_for_input, }; @@ -145,9 +149,9 @@ pub fn affine_matrix(x_scale: Num<8>, y_scale: Num<8>, rotation: u8) -> AffineMa #[test_case] fn affine(_gba: &mut crate::Gba) { // expect identity matrix - let one: Num<8> = 1.into(); + let one: Num = 1.into(); let aff = affine_matrix(one, one, 0); - assert_eq!(aff.p_a, one.to_raw() as i16); - assert_eq!(aff.p_d, one.to_raw() as i16); + assert_eq!(aff.p_a, one.to_raw()); + assert_eq!(aff.p_d, one.to_raw()); }