1use crate::{Fixed16, Point, Twips};
2use std::ops;
3
4#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
19pub struct Matrix {
20 pub a: Fixed16,
22
23 pub b: Fixed16,
25
26 pub c: Fixed16,
28
29 pub d: Fixed16,
31
32 pub tx: Twips,
34
35 pub ty: Twips,
37}
38
39impl Matrix {
40 pub const IDENTITY: Self = Self {
44 a: Fixed16::ONE,
45 c: Fixed16::ZERO,
46 b: Fixed16::ZERO,
47 d: Fixed16::ONE,
48 ty: Twips::ZERO,
49 tx: Twips::ZERO,
50 };
51
52 #[inline]
54 pub const fn scale(scale_x: Fixed16, scale_y: Fixed16) -> Self {
55 Self {
56 a: scale_x,
57 d: scale_y,
58 ..Self::IDENTITY
59 }
60 }
61
62 #[inline]
64 pub fn rotate(angle: f32) -> Self {
65 Self {
66 a: Fixed16::from_f32(angle.cos()),
67 c: Fixed16::from_f32(-angle.sin()),
68 b: Fixed16::from_f32(angle.sin()),
69 d: Fixed16::from_f32(angle.cos()),
70 ..Default::default()
71 }
72 }
73
74 #[inline]
76 pub const fn translate(x: Twips, y: Twips) -> Self {
77 Self {
78 tx: x,
79 ty: y,
80 ..Self::IDENTITY
81 }
82 }
83
84 #[inline]
88 pub fn invert(&mut self) {
89 let (tx, ty) = (self.tx.get() as f32, self.ty.get() as f32);
91 let a = self.a.to_f32();
92 let b = self.b.to_f32();
93 let c = self.c.to_f32();
94 let d = self.d.to_f32();
95 let det = a * d - b * c;
96 let a = d / det;
97 let b = b / -det;
98 let c = c / -det;
99 let d = a / det;
100 let (out_tx, out_ty) = ((d * tx - c * ty) / -det, (b * tx - a * ty) / det);
101 *self = Matrix {
102 a: Fixed16::from_f32(a),
103 b: Fixed16::from_f32(b),
104 c: Fixed16::from_f32(c),
105 d: Fixed16::from_f32(d),
106 tx: Twips::new(out_tx as i32),
107 ty: Twips::new(out_ty as i32),
108 };
109 }
110}
111
112impl ops::Mul for Matrix {
113 type Output = Self;
114 #[inline]
115 fn mul(self, rhs: Self) -> Self {
116 let (rhs_tx, rhs_ty) = (rhs.tx.get(), rhs.ty.get());
117 let (out_tx, out_ty) = (
118 self.a
119 .wrapping_mul_int(rhs_tx)
120 .wrapping_add(self.c.mul_int(rhs_ty))
121 .wrapping_add(self.tx.get()),
122 self.b
123 .wrapping_mul_int(rhs_tx)
124 .wrapping_add(self.d.mul_int(rhs_ty))
125 .wrapping_add(self.ty.get()),
126 );
127 Matrix {
128 a: self.a * rhs.a + self.c * rhs.b,
129 b: self.b * rhs.a + self.d * rhs.b,
130 c: self.a * rhs.c + self.c * rhs.d,
131 d: self.b * rhs.c + self.d * rhs.d,
132 tx: Twips::new(out_tx),
133 ty: Twips::new(out_ty),
134 }
135 }
136}
137
138impl ops::Mul<Point<Twips>> for Matrix {
139 type Output = Point<Twips>;
140
141 #[inline]
142 fn mul(self, point: Point<Twips>) -> Point<Twips> {
143 let x = point.x.get();
144 let y = point.y.get();
145 let out_x = Twips::new(
146 (self
147 .a
148 .wrapping_mul_int(x)
149 .wrapping_add(self.c.wrapping_mul_int(y)))
150 .wrapping_add(self.tx.get()),
151 );
152 let out_y = Twips::new(
153 (self
154 .b
155 .wrapping_mul_int(x)
156 .wrapping_add(self.d.wrapping_mul_int(y)))
157 .wrapping_add(self.ty.get()),
158 );
159 Point::new(out_x, out_y)
160 }
161}
162
163impl Default for Matrix {
164 #[inline]
165 fn default() -> Matrix {
166 Matrix::IDENTITY
167 }
168}
169
170impl ops::MulAssign for Matrix {
171 #[inline]
172 fn mul_assign(&mut self, rhs: Self) {
173 *self = *self * rhs;
174 }
175}