use crate::{Fixed16, Twips};
use std::ops;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Matrix {
pub a: Fixed16,
pub b: Fixed16,
pub c: Fixed16,
pub d: Fixed16,
pub tx: Twips,
pub ty: Twips,
}
impl Matrix {
pub const IDENTITY: Self = Self {
a: Fixed16::ONE,
c: Fixed16::ZERO,
b: Fixed16::ZERO,
d: Fixed16::ONE,
ty: Twips::ZERO,
tx: Twips::ZERO,
};
#[inline]
pub const fn scale(scale_x: Fixed16, scale_y: Fixed16) -> Self {
Self {
a: scale_x,
d: scale_y,
..Self::IDENTITY
}
}
#[inline]
pub fn rotate(angle: f32) -> Self {
Self {
a: Fixed16::from_f32(angle.cos()),
c: Fixed16::from_f32(-angle.sin()),
b: Fixed16::from_f32(angle.sin()),
d: Fixed16::from_f32(angle.cos()),
..Default::default()
}
}
#[inline]
pub const fn translate(x: Twips, y: Twips) -> Self {
Self {
tx: x,
ty: y,
..Self::IDENTITY
}
}
#[inline]
pub fn invert(&mut self) {
let (tx, ty) = (self.tx.get() as f32, self.ty.get() as f32);
let a = self.a.to_f32();
let b = self.b.to_f32();
let c = self.c.to_f32();
let d = self.d.to_f32();
let det = a * d - b * c;
let a = d / det;
let b = b / -det;
let c = c / -det;
let d = a / det;
let (out_tx, out_ty) = ((d * tx - c * ty) / -det, (b * tx - a * ty) / det);
*self = Matrix {
a: Fixed16::from_f32(a),
b: Fixed16::from_f32(b),
c: Fixed16::from_f32(c),
d: Fixed16::from_f32(d),
tx: Twips::new(out_tx as i32),
ty: Twips::new(out_ty as i32),
};
}
}
impl ops::Mul for Matrix {
type Output = Self;
#[inline]
fn mul(self, rhs: Self) -> Self {
let (rhs_tx, rhs_ty) = (rhs.tx.get(), rhs.ty.get());
let (out_tx, out_ty) = (
self.a
.wrapping_mul_int(rhs_tx)
.wrapping_add(self.c.mul_int(rhs_ty))
.wrapping_add(self.tx.get()),
self.b
.wrapping_mul_int(rhs_tx)
.wrapping_add(self.d.mul_int(rhs_ty))
.wrapping_add(self.ty.get()),
);
Matrix {
a: self.a * rhs.a + self.c * rhs.b,
b: self.b * rhs.a + self.d * rhs.b,
c: self.a * rhs.c + self.c * rhs.d,
d: self.b * rhs.c + self.d * rhs.d,
tx: Twips::new(out_tx),
ty: Twips::new(out_ty),
}
}
}
impl ops::Mul<(Twips, Twips)> for Matrix {
type Output = (Twips, Twips);
#[inline]
fn mul(self, (x, y): (Twips, Twips)) -> (Twips, Twips) {
let (x, y) = (x.get(), y.get());
let out_x = (self
.a
.wrapping_mul_int(x)
.wrapping_add(self.c.wrapping_mul_int(y)))
.wrapping_add(self.tx.get());
let out_y = (self
.b
.wrapping_mul_int(x)
.wrapping_add(self.d.wrapping_mul_int(y)))
.wrapping_add(self.ty.get());
(Twips::new(out_x), Twips::new(out_y))
}
}
impl Default for Matrix {
#[inline]
fn default() -> Matrix {
Matrix::IDENTITY
}
}
impl ops::MulAssign for Matrix {
#[inline]
fn mul_assign(&mut self, rhs: Self) {
*self = *self * rhs;
}
}