1use crate::{Degrees, Radians, Scalar};
2use crate::vector::*;
3use crate::quaternion::Quaternion;
4use super::Matrix3x3;
5
6#[repr(C)]
8#[derive(Debug, Default, Copy, Clone, PartialEq)]
9pub struct Matrix4x4 {
10 pub c00: Scalar, pub c10: Scalar, pub c20: Scalar, pub c30: Scalar,
11 pub c01: Scalar, pub c11: Scalar, pub c21: Scalar, pub c31: Scalar,
12 pub c02: Scalar, pub c12: Scalar, pub c22: Scalar, pub c32: Scalar,
13 pub c03: Scalar, pub c13: Scalar, pub c23: Scalar, pub c33: Scalar,
14}
15impl_add_self!(Matrix4x4, c00, c10, c20, c30, c01, c11, c21, c31, c02, c12, c22, c32, c03, c13, c23, c33);
16impl_sub_self!(Matrix4x4, c00, c10, c20, c30, c01, c11, c21, c31, c02, c12, c22, c32, c03, c13, c23, c33);
17impl_mul_scalar!(Matrix4x4, c00, c10, c20, c30, c01, c11, c21, c31, c02, c12, c22, c32, c03, c13, c23, c33);
18impl_approx!(Matrix4x4, c00, c10, c20, c30, c01, c11, c21, c31, c02, c12, c22, c32, c03, c13, c23, c33);
19
20impl Matrix4x4 {
21 pub const fn identity() -> Self {
22 Self {
23 c00: 1.0, c10: 0.0, c20: 0.0, c30: 0.0,
24 c01: 0.0, c11: 1.0, c21: 0.0, c31: 0.0,
25 c02: 0.0, c12: 0.0, c22: 1.0, c32: 0.0,
26 c03: 0.0, c13: 0.0, c23: 0.0, c33: 1.0,
27 }
28 }
29
30 pub fn new_perspective_projection(fov: Degrees, aspect_ratio: Scalar, near_plane: Scalar, far_plane: Scalar) -> Self {
39 assert!(aspect_ratio != 0.0);
40 assert!(near_plane - far_plane != 0.0);
41 let mut result = Self::default();
42 let x_scale = 2.0 / Radians::from(fov).0.tan();
43 result.c00 = x_scale;
44 result.c11 = x_scale / aspect_ratio;
45 result.c22 = far_plane / (far_plane - near_plane);
46 result.c32 = 1.0;
47 result.c33 = near_plane * far_plane / (near_plane - far_plane);
48 result
49 }
50
51 pub fn new_orthographic_projection(top: Scalar, bottom: Scalar, left: Scalar, right: Scalar, near_plane: Scalar, far_plane: Scalar) -> Self {
75 assert!(top - bottom != 0.0);
76 assert!(left - right != 0.0);
77 assert!(near_plane - far_plane != 0.0);
78 let mut result = Self::default();
79 result.c00 = 2.0 / (right - left);
80 result.c11 = 2.0 / (top - bottom);
81 result.c22 = 1.0 / (far_plane - near_plane);
82 result.c23 = -near_plane / (far_plane - near_plane);
83 result.c33 = 1.0;
84 result
85 }
86
87 pub const fn from_translation(translation: &Vector3) -> Self {
89 Self {
90 c00: 1.0, c10: 0.0, c20: 0.0, c30: 0.0,
91 c01: 0.0, c11: 1.0, c21: 0.0, c31: 0.0,
92 c02: 0.0, c12: 0.0, c22: 1.0, c32: 0.0,
93 c03: translation.x, c13: translation.y, c23: translation.z, c33: 1.0,
94 }
95 }
96
97 pub const fn from_nonuniform_scale(scale: &Vector3) -> Self {
99 Self {
100 c00: scale.x, c10: 0.0, c20: 0.0, c30: 0.0,
101 c01: 0.0, c11: scale.y, c21: 0.0, c31: 0.0,
102 c02: 0.0, c12: 0.0, c22: scale.z, c32: 0.0,
103 c03: 0.0, c13: 0.0, c23: 0.0, c33: 1.0,
104 }
105 }
106
107 pub const fn from_scale(scale: Scalar) -> Self {
109 Self {
110 c00: scale, c10: 0.0, c20: 0.0, c30: 0.0,
111 c01: 0.0, c11: scale, c21: 0.0, c31: 0.0,
112 c02: 0.0, c12: 0.0, c22: scale, c32: 0.0,
113 c03: 0.0, c13: 0.0, c23: 0.0, c33: 1.0,
114 }
115 }
116
117 pub fn matrix_of_minors(&self) -> Matrix4x4 {
119 let c00 = Matrix3x3 {
120 c00: self.c11, c10: self.c21, c20: self.c31,
121 c01: self.c12, c11: self.c22, c21: self.c32,
122 c02: self.c13, c12: self.c23, c22: self.c33,
123 }.determinant();
124 let c10 = Matrix3x3 {
125 c00: self.c01, c10: self.c21, c20: self.c31,
126 c01: self.c02, c11: self.c22, c21: self.c32,
127 c02: self.c03, c12: self.c23, c22: self.c33,
128 }.determinant();
129 let c20 = Matrix3x3 {
130 c00: self.c01, c10: self.c11, c20: self.c31,
131 c01: self.c02, c11: self.c12, c21: self.c32,
132 c02: self.c03, c12: self.c13, c22: self.c33,
133 }.determinant();
134 let c30 = Matrix3x3 {
135 c00: self.c01, c10: self.c11, c20: self.c21,
136 c01: self.c02, c11: self.c12, c21: self.c22,
137 c02: self.c03, c12: self.c13, c22: self.c23,
138 }.determinant();
139
140 let c01 = Matrix3x3 {
141 c00: self.c10, c10: self.c20, c20: self.c30,
142 c01: self.c12, c11: self.c22, c21: self.c32,
143 c02: self.c13, c12: self.c23, c22: self.c33,
144 }.determinant();
145 let c11 = Matrix3x3 {
146 c00: self.c00, c10: self.c20, c20: self.c30,
147 c01: self.c02, c11: self.c22, c21: self.c32,
148 c02: self.c03, c12: self.c23, c22: self.c33,
149 }.determinant();
150 let c21 = Matrix3x3 {
151 c00: self.c00, c10: self.c10, c20: self.c30,
152 c01: self.c02, c11: self.c12, c21: self.c32,
153 c02: self.c03, c12: self.c13, c22: self.c33,
154 }.determinant();
155 let c31 = Matrix3x3 {
156 c00: self.c00, c10: self.c10, c20: self.c20,
157 c01: self.c02, c11: self.c12, c21: self.c22,
158 c02: self.c03, c12: self.c13, c22: self.c23,
159 }.determinant();
160
161 let c02 = Matrix3x3 {
162 c00: self.c10, c10: self.c20, c20: self.c30,
163 c01: self.c11, c11: self.c21, c21: self.c31,
164 c02: self.c13, c12: self.c23, c22: self.c33,
165 }.determinant();
166 let c12 = Matrix3x3 {
167 c00: self.c00, c10: self.c20, c20: self.c30,
168 c01: self.c01, c11: self.c21, c21: self.c31,
169 c02: self.c03, c12: self.c23, c22: self.c33,
170 }.determinant();
171 let c22 = Matrix3x3 {
172 c00: self.c00, c10: self.c10, c20: self.c30,
173 c01: self.c01, c11: self.c11, c21: self.c31,
174 c02: self.c03, c12: self.c13, c22: self.c33,
175 }.determinant();
176 let c32 = Matrix3x3 {
177 c00: self.c00, c10: self.c10, c20: self.c20,
178 c01: self.c01, c11: self.c11, c21: self.c21,
179 c02: self.c03, c12: self.c13, c22: self.c23,
180 }.determinant();
181
182 let c03 = Matrix3x3 {
183 c00: self.c10, c10: self.c20, c20: self.c30,
184 c01: self.c11, c11: self.c21, c21: self.c31,
185 c02: self.c12, c12: self.c22, c22: self.c32,
186 }.determinant();
187 let c13 = Matrix3x3 {
188 c00: self.c00, c10: self.c20, c20: self.c30,
189 c01: self.c01, c11: self.c21, c21: self.c31,
190 c02: self.c02, c12: self.c22, c22: self.c32,
191 }.determinant();
192 let c23 = Matrix3x3 {
193 c00: self.c00, c10: self.c10, c20: self.c30,
194 c01: self.c01, c11: self.c11, c21: self.c31,
195 c02: self.c02, c12: self.c12, c22: self.c32,
196 }.determinant();
197 let c33 = Matrix3x3 {
198 c00: self.c00, c10: self.c10, c20: self.c20,
199 c01: self.c01, c11: self.c11, c21: self.c21,
200 c02: self.c02, c12: self.c12, c22: self.c22,
201 }.determinant();
202
203 Matrix4x4 {
204 c00, c10, c20, c30,
205 c01, c11, c21, c31,
206 c02, c12, c22, c32,
207 c03, c13, c23, c33,
208 }
209 }
210
211 pub fn matrix_of_cofactors(&self) -> Matrix4x4 {
213 Matrix4x4 {
214 c00: self.c00, c10: -self.c10, c20: self.c20, c30: -self.c30,
215 c01: -self.c01, c11: self.c11, c21: -self.c21, c31: self.c31,
216 c02: self.c02, c12: -self.c12, c22: self.c22, c32: -self.c32,
217 c03: -self.c03, c13: self.c13, c23: -self.c23, c33: self.c33,
218 }
219 }
220
221 pub fn transpose(&self) -> Matrix4x4 {
223 Matrix4x4 {
224 c00: self.c00, c10: self.c01, c20: self.c02, c30: self.c03,
225 c01: self.c10, c11: self.c11, c21: self.c12, c31: self.c13,
226 c02: self.c20, c12: self.c21, c22: self.c22, c32: self.c23,
227 c03: self.c30, c13: self.c31, c23: self.c32, c33: self.c33,
228 }
229 }
230
231 pub fn determinant(&self) -> f32 {
233 let minors = self.matrix_of_minors();
234 let cofactors = minors.matrix_of_cofactors();
235 self.c00 * cofactors.c00 + self.c10 * cofactors.c10 + self.c20 * cofactors.c20 + self.c30 * cofactors.c30
236 }
237
238 pub fn inverse(&self) -> Matrix4x4 {
240 let minors = self.matrix_of_minors();
241 let cofactors = minors.matrix_of_cofactors();
242 let adjugate = cofactors.transpose();
243 let determinant = self.determinant();
244 adjugate * (1.0 / determinant)
245 }
246}
247
248impl std::ops::Mul for Matrix4x4 {
249 type Output = Matrix4x4;
250
251 fn mul(self, rhs: Matrix4x4) -> Matrix4x4 {
252 Matrix4x4 {
253 c00: self.c00 * rhs.c00 + self.c10 * rhs.c01 + self.c20 * rhs.c02 + self.c30 * rhs.c03,
254 c10: self.c00 * rhs.c10 + self.c10 * rhs.c11 + self.c20 * rhs.c12 + self.c30 * rhs.c13,
255 c20: self.c00 * rhs.c20 + self.c10 * rhs.c21 + self.c20 * rhs.c22 + self.c30 * rhs.c23,
256 c30: self.c00 * rhs.c30 + self.c10 * rhs.c31 + self.c20 * rhs.c32 + self.c30 * rhs.c33,
257
258 c01: self.c01 * rhs.c00 + self.c11 * rhs.c01 + self.c21 * rhs.c02 + self.c31 * rhs.c03,
259 c11: self.c01 * rhs.c10 + self.c11 * rhs.c11 + self.c21 * rhs.c12 + self.c31 * rhs.c13,
260 c21: self.c01 * rhs.c20 + self.c11 * rhs.c21 + self.c21 * rhs.c22 + self.c31 * rhs.c23,
261 c31: self.c01 * rhs.c30 + self.c11 * rhs.c31 + self.c21 * rhs.c32 + self.c31 * rhs.c33,
262
263 c02: self.c02 * rhs.c00 + self.c12 * rhs.c01 + self.c22 * rhs.c02 + self.c32 * rhs.c03,
264 c12: self.c02 * rhs.c10 + self.c12 * rhs.c11 + self.c22 * rhs.c12 + self.c32 * rhs.c13,
265 c22: self.c02 * rhs.c20 + self.c12 * rhs.c21 + self.c22 * rhs.c22 + self.c32 * rhs.c23,
266 c32: self.c02 * rhs.c30 + self.c12 * rhs.c31 + self.c22 * rhs.c32 + self.c32 * rhs.c33,
267
268 c03: self.c03 * rhs.c00 + self.c13 * rhs.c01 + self.c23 * rhs.c02 + self.c33 * rhs.c03,
269 c13: self.c03 * rhs.c10 + self.c13 * rhs.c11 + self.c23 * rhs.c12 + self.c33 * rhs.c13,
270 c23: self.c03 * rhs.c20 + self.c13 * rhs.c21 + self.c23 * rhs.c22 + self.c33 * rhs.c23,
271 c33: self.c03 * rhs.c30 + self.c13 * rhs.c31 + self.c23 * rhs.c32 + self.c33 * rhs.c33,
272 }
273 }
274}
275
276impl std::ops::MulAssign for Matrix4x4 {
277 fn mul_assign(&mut self, rhs: Matrix4x4) {
278 let c00 = self.c00 * rhs.c00 + self.c10 * rhs.c01 + self.c20 * rhs.c02 + self.c30 * rhs.c03;
279 let c10 = self.c00 * rhs.c10 + self.c10 * rhs.c11 + self.c20 * rhs.c12 + self.c30 * rhs.c13;
280 let c20 = self.c00 * rhs.c20 + self.c10 * rhs.c21 + self.c20 * rhs.c22 + self.c30 * rhs.c23;
281 let c30 = self.c00 * rhs.c30 + self.c10 * rhs.c31 + self.c20 * rhs.c32 + self.c30 * rhs.c33;
282
283 let c01 = self.c01 * rhs.c00 + self.c11 * rhs.c01 + self.c21 * rhs.c02 + self.c31 * rhs.c03;
284 let c11 = self.c01 * rhs.c10 + self.c11 * rhs.c11 + self.c21 * rhs.c12 + self.c31 * rhs.c13;
285 let c21 = self.c01 * rhs.c20 + self.c11 * rhs.c21 + self.c21 * rhs.c22 + self.c31 * rhs.c23;
286 let c31 = self.c01 * rhs.c30 + self.c11 * rhs.c31 + self.c21 * rhs.c32 + self.c31 * rhs.c33;
287
288 let c02 = self.c02 * rhs.c00 + self.c12 * rhs.c01 + self.c22 * rhs.c02 + self.c32 * rhs.c03;
289 let c12 = self.c02 * rhs.c10 + self.c12 * rhs.c11 + self.c22 * rhs.c12 + self.c32 * rhs.c13;
290 let c22 = self.c02 * rhs.c20 + self.c12 * rhs.c21 + self.c22 * rhs.c22 + self.c32 * rhs.c23;
291 let c32 = self.c02 * rhs.c30 + self.c12 * rhs.c31 + self.c22 * rhs.c32 + self.c32 * rhs.c33;
292
293 let c03 = self.c03 * rhs.c00 + self.c13 * rhs.c01 + self.c23 * rhs.c02 + self.c33 * rhs.c03;
294 let c13 = self.c03 * rhs.c10 + self.c13 * rhs.c11 + self.c23 * rhs.c12 + self.c33 * rhs.c13;
295 let c23 = self.c03 * rhs.c20 + self.c13 * rhs.c21 + self.c23 * rhs.c22 + self.c33 * rhs.c23;
296 let c33 = self.c03 * rhs.c30 + self.c13 * rhs.c31 + self.c23 * rhs.c32 + self.c33 * rhs.c33;
297
298 self.c00 = c00; self.c10 = c10; self.c20 = c20; self.c30 = c30;
299 self.c01 = c01; self.c11 = c11; self.c21 = c21; self.c31 = c31;
300 self.c02 = c02; self.c12 = c12; self.c22 = c22; self.c32 = c32;
301 self.c03 = c03; self.c13 = c13; self.c23 = c23; self.c33 = c33;
302 }
303}
304
305impl std::ops::Mul<Quaternion> for Matrix4x4 {
306 type Output = Matrix4x4;
307
308 fn mul(self, rhs: Quaternion) -> Self::Output {
309 self * Matrix4x4::from(rhs)
310 }
311}
312
313impl std::ops::MulAssign<Quaternion> for Matrix4x4 {
314 fn mul_assign(&mut self, rhs: Quaternion) {
315 *self *= Matrix4x4::from(rhs);
316 }
317}
318
319impl From<Quaternion> for Matrix4x4 {
320 fn from(rotation: Quaternion) -> Self {
321 let x = rotation.x * 2.0;
322 let y = rotation.y * 2.0;
323 let z = rotation.z * 2.0;
324 let xx = rotation.x * x;
325 let yy = rotation.y * y;
326 let zz = rotation.z * z;
327 let xy = rotation.x * y;
328 let xz = rotation.x * z;
329 let yz = rotation.y * z;
330 let wx = rotation.w * x;
331 let wy = rotation.w * y;
332 let wz = rotation.w * z;
333
334 Self {
335 c00: 1.0 - (yy + zz), c10: xy - wz, c20: xz + wy, c30: 0.0,
336 c01: xy + wz, c11: 1.0 - (xx + zz), c21: yz - wx, c31: 0.0,
337 c02: xz - wy, c12: yz + wx, c22: 1.0 - (xx + yy), c32: 0.0,
338 c03: 0.0, c13: 0.0, c23: 0.0, c33: 1.0,
339 }
340 }
341}