1use super::*;
6
7#[derive(Copy, Clone, Default, PartialEq)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18#[repr(C)]
19pub struct Mat4<T> {
20 pub a11: T, pub a12: T, pub a13: T, pub a14: T,
21 pub a21: T, pub a22: T, pub a23: T, pub a24: T,
22 pub a31: T, pub a32: T, pub a33: T, pub a34: T,
23 pub a41: T, pub a42: T, pub a43: T, pub a44: T,
24}
25
26#[allow(non_snake_case)]
28#[inline]
29pub const fn Mat4<T>(
30 a11: T, a12: T, a13: T, a14: T,
31 a21: T, a22: T, a23: T, a24: T,
32 a31: T, a32: T, a33: T, a34: T,
33 a41: T, a42: T, a43: T, a44: T,
34) -> Mat4<T> {
35 Mat4 { a11, a12, a13, a14, a21, a22, a23, a24, a31, a32, a33, a34, a41, a42, a43, a44 }
36}
37
38#[cfg(feature = "dataview")]
39unsafe impl<T: dataview::Pod> dataview::Pod for Mat4<T> {}
40
41impl<T> Mat4<T> {
45 #[inline]
47 pub const fn new(
48 a11: T, a12: T, a13: T, a14: T,
49 a21: T, a22: T, a23: T, a24: T,
50 a31: T, a32: T, a33: T, a34: T,
51 a41: T, a42: T, a43: T, a44: T,
52 ) -> Mat4<T> {
53 Mat4 {
54 a11, a12, a13, a14,
55 a21, a22, a23, a24,
56 a31, a32, a33, a34,
57 a41, a42, a43, a44,
58 }
59 }
60}
61
62impl<T: Zero> Mat4<T> {
63 pub const ZERO: Mat4<T> = Mat4 {
65 a11: T::ZERO, a12: T::ZERO, a13: T::ZERO, a14: T::ZERO,
66 a21: T::ZERO, a22: T::ZERO, a23: T::ZERO, a24: T::ZERO,
67 a31: T::ZERO, a32: T::ZERO, a33: T::ZERO, a34: T::ZERO,
68 a41: T::ZERO, a42: T::ZERO, a43: T::ZERO, a44: T::ZERO,
69 };
70}
71
72impl<T: Zero + One> Mat4<T> {
73 pub const IDENTITY: Mat4<T> = Mat4 {
75 a11: T::ONE, a12: T::ZERO, a13: T::ZERO, a14: T::ZERO,
76 a21: T::ZERO, a22: T::ONE, a23: T::ZERO, a24: T::ZERO,
77 a31: T::ZERO, a32: T::ZERO, a33: T::ONE, a34: T::ZERO,
78 a41: T::ZERO, a42: T::ZERO, a43: T::ZERO, a44: T::ONE,
79 };
80}
81
82impl<T: Zero + One> From<Mat3<T>> for Mat4<T> {
83 #[inline]
84 fn from(mat: Mat3<T>) -> Mat4<T> {
85 Mat4 {
86 a11: mat.a11, a12: mat.a12, a13: mat.a13,
87 a21: mat.a21, a22: mat.a22, a23: mat.a23,
88 a31: mat.a31, a32: mat.a32, a33: mat.a33,
89 ..Mat4::IDENTITY
90 }
91 }
92}
93
94impl<T: Zero + One> From<Transform3<T>> for Mat4<T> {
95 #[inline]
96 fn from(mat: Transform3<T>) -> Mat4<T> {
97 Mat4 {
98 a11: mat.a11, a12: mat.a12, a13: mat.a13, a14: mat.a14,
99 a21: mat.a21, a22: mat.a22, a23: mat.a23, a24: mat.a24,
100 a31: mat.a31, a32: mat.a32, a33: mat.a33, a34: mat.a34,
101 ..Mat4::IDENTITY
102 }
103 }
104}
105
106impl<T: Float> Mat4<T> {
109 #[inline]
111 pub fn look_at(position: Vec3<T>, target: Vec3<T>, ref_up: Vec3<T>, hand: Hand) -> Mat4<T> {
112 Transform3::look_at(position, target, ref_up, hand).into()
113 }
114
115 #[inline]
119 pub fn ortho(left: T, right: T, bottom: T, top: T, near: T, far: T, (hand, clip): (Hand, Clip)) -> Mat4<T> {
120 let mins = Vec3(left, bottom, near);
121 let maxs = Vec3(right, top, far);
122 Transform3::ortho(Bounds3 { mins, maxs }, (hand, clip)).into()
123 }
124
125 #[inline]
140 pub fn ortho_perspective(focus_depth: T, fov_y: Angle<T>, aspect_ratio: T, near: T, far: T, flags: (Hand, Clip)) -> Mat4<T> {
141 debug_assert!(fov_y > Angle::ZERO && fov_y < Angle::HALF, "fov_y must be in (0, 180)");
142 debug_assert!(aspect_ratio > T::ZERO, "aspect_ratio must be strictly positive");
143 debug_assert!(T::ZERO < near && near < far);
144
145 let half_height = (fov_y / T::TWO).tan() * focus_depth;
146 let half_width = half_height * aspect_ratio;
147 Mat4::ortho(-half_width, half_width, -half_height, half_height, near, far, flags)
148 }
149
150 #[inline]
152 pub fn frustum(left: T, right: T, bottom: T, top: T, near: T, far: T, (hand, clip): (Hand, Clip)) -> Mat4<T> {
153 debug_assert!(T::ZERO < near && near < far);
154
155 let nf = far - near;
156 let np = near + near;
157
158 let a11 = np / (right - left);
159 let a13 = (right + left) / (right - left);
160 let a22 = np / (top - bottom);
161 let a23 = (top + bottom) / (top - bottom);
162
163 let a33 = match clip {
164 Clip::ZO => far / nf,
165 Clip::NO => (far + near) / nf,
166 };
167 let a33 = match hand {
168 Hand::LH => a33,
169 Hand::RH => -a33,
170 };
171
172 let a34 = -far * near / nf;
173 let a34 = match clip {
174 Clip::ZO => a34,
175 Clip::NO => a34 + a34,
176 };
177
178 let a43 = match hand {
179 Hand::LH => T::ONE,
180 Hand::RH => -T::ONE,
181 };
182
183 Mat4 { a11, a13, a22, a23, a33, a34, a43, ..Mat4::ZERO }
184 }
185
186 #[inline]
194 pub fn perspective(fov_y: Angle<T>, aspect_ratio: T, near: T, far: T, flags: (Hand, Clip)) -> Mat4<T> {
195 debug_assert!(fov_y > Angle::ZERO && fov_y < Angle::HALF, "fov_y must be in (0, 180)");
196 debug_assert!(aspect_ratio > T::ZERO, "aspect_ratio must be strictly positive");
197 debug_assert!(T::ZERO < near && near < far);
198
199 let half_fov_y = fov_y / T::TWO;
200 let half_height = near * half_fov_y.tan();
201 let half_width = aspect_ratio * half_height;
202
203 let left = -half_width;
204 let right = half_width;
205 let bottom = -half_height;
206 let top = half_height;
207
208 Mat4::frustum(left, right, bottom, top, near, far, flags)
209 }
210
211 pub fn blend_ortho_perspective(blend: T, focus_depth: T, fov_y: Angle<T>, aspect_ratio: T, near: T, far: T, flags: (Hand, Clip)) -> Mat4<T> {
221 debug_assert!(fov_y > Angle::ZERO && fov_y < Angle::HALF, "fov_y must be in (0, 180)");
222 debug_assert!(aspect_ratio > T::ZERO, "aspect_ratio must be strictly positive");
223 debug_assert!(T::ZERO < near && near < far);
224 debug_assert!(blend >= T::ZERO && blend <= T::ONE, "fraction must be in [0, 1]");
225
226 let blend = blend.clamp(T::ZERO, T::ONE);
227 let blend = blend * blend;
228 let blend = blend * blend;
229
230 let half_height = (fov_y / T::TWO).tan() * focus_depth;
231 if blend <= T::EPSILON {
232 let half_width = half_height * aspect_ratio;
233 return Mat4::ortho(-half_width, half_width, -half_height, half_height, near, far, flags);
234 }
235
236 let dz = (T::ONE - blend) / blend;
237 let adjusted_fov_y = Angle::atan(half_height / (focus_depth + dz)) * T::TWO;
238
239 let projection = Mat4::perspective(adjusted_fov_y, aspect_ratio, near + dz, far + dz, flags);
240 let trans = Vec3(T::ZERO, T::ZERO, match flags.0 { Hand::LH => dz, Hand::RH => -dz });
241 let view_shift = Transform3::translation(trans);
242
243 projection * view_shift
244 }
245}
246
247impl<T> Mat4<T> {
251 #[inline]
253 pub fn mat3(self) -> Mat3<T> {
254 Mat3 {
255 a11: self.a11, a12: self.a12, a13: self.a13,
256 a21: self.a21, a22: self.a22, a23: self.a23,
257 a31: self.a31, a32: self.a32, a33: self.a33,
258 }
259 }
260}
261
262impl<T> Mat4<T> {
263 #[inline]
264 fn as_array(&self) -> &[T; 16] {
265 unsafe { mem::transmute(self)}
266 }
267 #[inline]
269 pub fn from_row_major(mat: [[T; 4]; 4]) -> Mat4<T> {
270 let [[a11, a12, a13, a14], [a21, a22, a23, a24], [a31, a32, a33, a34], [a41, a42, a43, a44]] = mat;
271 Mat4 {
272 a11, a12, a13, a14,
273 a21, a22, a23, a24,
274 a31, a32, a33, a34,
275 a41, a42, a43, a44,
276 }
277 }
278 #[inline]
280 pub fn from_column_major(mat: [[T; 4]; 4]) -> Mat4<T> {
281 let [[a11, a21, a31, a41], [a12, a22, a32, a42], [a13, a23, a33, a43], [a14, a24, a34, a44]] = mat;
282 Mat4 {
283 a11, a12, a13, a14,
284 a21, a22, a23, a24,
285 a31, a32, a33, a34,
286 a41, a42, a43, a44,
287 }
288 }
289 #[inline]
291 pub fn into_row_major(self) -> [[T; 4]; 4] {
292 [
293 [self.a11, self.a12, self.a13, self.a14],
294 [self.a21, self.a22, self.a23, self.a24],
295 [self.a31, self.a32, self.a33, self.a34],
296 [self.a41, self.a42, self.a43, self.a44],
297 ]
298 }
299 #[inline]
301 pub fn into_column_major(self) -> [[T; 4]; 4] {
302 [
303 [self.a11, self.a21, self.a31, self.a41],
304 [self.a12, self.a22, self.a32, self.a42],
305 [self.a13, self.a23, self.a33, self.a43],
306 [self.a14, self.a24, self.a34, self.a44],
307 ]
308 }
309}
310
311impl<T> Mat4<T> {
315 #[inline]
317 pub fn compose(x: Vec4<T>, y: Vec4<T>, z: Vec4<T>, w: Vec4<T>) -> Mat4<T> {
318 Mat4 {
319 a11: x.x, a12: y.x, a13: z.x, a14: w.x,
320 a21: x.y, a22: y.y, a23: z.y, a24: w.y,
321 a31: x.z, a32: y.z, a33: z.z, a34: w.z,
322 a41: x.w, a42: y.w, a43: z.w, a44: w.w,
323 }
324 }
325 #[inline]
327 pub fn x(self) -> Vec4<T> {
328 Vec4 { x: self.a11, y: self.a21, z: self.a31, w: self.a41 }
329 }
330 #[inline]
332 pub fn y(self) -> Vec4<T> {
333 Vec4 { x: self.a12, y: self.a22, z: self.a32, w: self.a42 }
334 }
335 #[inline]
337 pub fn z(self) -> Vec4<T> {
338 Vec4 { x: self.a13, y: self.a23, z: self.a33, w: self.a43 }
339 }
340 #[inline]
342 pub fn w(self) -> Vec4<T> {
343 Vec4 { x: self.a14, y: self.a24, z: self.a34, w: self.a44 }
344 }
345}
346
347impl<T: Scalar> Mat4<T> {
351 #[inline]
353 pub fn det(self) -> T {
354 let s0 = self.a33 * self.a44 - self.a34 * self.a43;
356 let s1 = self.a32 * self.a44 - self.a34 * self.a42;
357 let s2 = self.a32 * self.a43 - self.a33 * self.a42;
358 let s3 = self.a31 * self.a44 - self.a34 * self.a41;
359 let s4 = self.a31 * self.a43 - self.a33 * self.a41;
360 let s5 = self.a31 * self.a42 - self.a32 * self.a41;
361
362 let c0 = self.a22 * s0 - self.a23 * s1 + self.a24 * s2;
364 let c1 = self.a21 * s0 - self.a23 * s3 + self.a24 * s4;
365 let c2 = self.a21 * s1 - self.a22 * s3 + self.a24 * s5;
366 let c3 = self.a21 * s2 - self.a22 * s4 + self.a23 * s5;
367
368 self.a11 * c0 - self.a12 * c1 + self.a13 * c2 - self.a14 * c3
370 }
371 #[inline]
373 pub fn trace(self) -> T {
374 self.a11 + self.a22 + self.a33 + self.a44
375 }
376 #[inline]
382 pub fn flat_norm_sqr(self) -> T {
383 self.a11 * self.a11 + self.a12 * self.a12 + self.a13 * self.a13 + self.a14 * self.a14 +
384 self.a21 * self.a21 + self.a22 * self.a22 + self.a23 * self.a23 + self.a24 * self.a24 +
385 self.a31 * self.a31 + self.a32 * self.a32 + self.a33 * self.a33 + self.a34 * self.a34 +
386 self.a41 * self.a41 + self.a42 * self.a42 + self.a43 * self.a43 + self.a44 * self.a44
387 }
388 #[inline]
389 pub fn try_invert(self) -> Option<Mat4<T>> where T: Float {
390 glu_invert(&self)
391 }
392 #[inline]
396 pub fn inverse(self) -> Mat4<T> where T: Float {
397 glu_invert(&self).unwrap_or(Mat4::ZERO)
398 }
399 #[inline]
401 pub fn transpose(self) -> Mat4<T> {
402 Mat4 {
403 a11: self.a11, a12: self.a21, a13: self.a31, a14: self.a41,
404 a21: self.a12, a22: self.a22, a23: self.a32, a24: self.a42,
405 a31: self.a13, a32: self.a23, a33: self.a33, a34: self.a43,
406 a41: self.a14, a42: self.a24, a43: self.a34, a44: self.a44,
407 }
408 }
409 #[inline]
411 pub fn lerp(self, rhs: Mat4<T>, t: T) -> Mat4<T> where T: Float {
412 Mat4 {
413 a11: self.a11 + (rhs.a11 - self.a11) * t,
414 a12: self.a12 + (rhs.a12 - self.a12) * t,
415 a13: self.a13 + (rhs.a13 - self.a13) * t,
416 a14: self.a14 + (rhs.a14 - self.a14) * t,
417
418 a21: self.a21 + (rhs.a21 - self.a21) * t,
419 a22: self.a22 + (rhs.a22 - self.a22) * t,
420 a23: self.a23 + (rhs.a23 - self.a23) * t,
421 a24: self.a24 + (rhs.a24 - self.a24) * t,
422
423 a31: self.a31 + (rhs.a31 - self.a31) * t,
424 a32: self.a32 + (rhs.a32 - self.a32) * t,
425 a33: self.a33 + (rhs.a33 - self.a33) * t,
426 a34: self.a34 + (rhs.a34 - self.a34) * t,
427
428 a41: self.a41 + (rhs.a41 - self.a41) * t,
429 a42: self.a42 + (rhs.a42 - self.a42) * t,
430 a43: self.a43 + (rhs.a43 - self.a43) * t,
431 a44: self.a44 + (rhs.a44 - self.a44) * t,
432 }
433 }
434}
435
436impl<T: ops::Neg<Output = T>> ops::Neg for Mat4<T> {
440 type Output = Mat4<T>;
441 #[inline]
442 fn neg(self) -> Mat4<T> {
443 Mat4 {
444 a11: -self.a11, a12: -self.a12, a13: -self.a13, a14: -self.a14,
445 a21: -self.a21, a22: -self.a22, a23: -self.a23, a24: -self.a24,
446 a31: -self.a31, a32: -self.a32, a33: -self.a33, a34: -self.a34,
447 a41: -self.a41, a42: -self.a42, a43: -self.a43, a44: -self.a44,
448 }
449 }
450}
451
452impl<T: Copy + ops::Add<Output = T>> ops::Add<Mat4<T>> for Mat4<T> {
453 type Output = Mat4<T>;
454 #[inline]
455 fn add(self, rhs: Mat4<T>) -> Mat4<T> {
456 Mat4 {
457 a11: self.a11 + rhs.a11, a12: self.a12 + rhs.a12, a13: self.a13 + rhs.a13, a14: self.a14 + rhs.a14,
458 a21: self.a21 + rhs.a21, a22: self.a22 + rhs.a22, a23: self.a23 + rhs.a23, a24: self.a24 + rhs.a24,
459 a31: self.a31 + rhs.a31, a32: self.a32 + rhs.a32, a33: self.a33 + rhs.a33, a34: self.a34 + rhs.a34,
460 a41: self.a41 + rhs.a41, a42: self.a42 + rhs.a42, a43: self.a43 + rhs.a43, a44: self.a44 + rhs.a44,
461 }
462 }
463}
464impl<T: Copy + ops::AddAssign> ops::AddAssign<Mat4<T>> for Mat4<T> {
465 #[inline]
466 fn add_assign(&mut self, rhs: Mat4<T>) {
467 self.a11 += rhs.a11; self.a12 += rhs.a12; self.a13 += rhs.a13; self.a14 += rhs.a14;
468 self.a21 += rhs.a21; self.a22 += rhs.a22; self.a23 += rhs.a23; self.a24 += rhs.a24;
469 self.a31 += rhs.a31; self.a32 += rhs.a32; self.a33 += rhs.a33; self.a34 += rhs.a34;
470 self.a41 += rhs.a41; self.a42 += rhs.a42; self.a43 += rhs.a43; self.a44 += rhs.a44;
471 }
472}
473impl<T: Copy + ops::Sub<Output = T>> ops::Sub<Mat4<T>> for Mat4<T> {
474 type Output = Mat4<T>;
475 #[inline]
476 fn sub(self, rhs: Mat4<T>) -> Mat4<T> {
477 Mat4 {
478 a11: self.a11 - rhs.a11, a12: self.a12 - rhs.a12, a13: self.a13 - rhs.a13, a14: self.a14 - rhs.a14,
479 a21: self.a21 - rhs.a21, a22: self.a22 - rhs.a22, a23: self.a23 - rhs.a23, a24: self.a24 - rhs.a24,
480 a31: self.a31 - rhs.a31, a32: self.a32 - rhs.a32, a33: self.a33 - rhs.a33, a34: self.a34 - rhs.a34,
481 a41: self.a41 - rhs.a41, a42: self.a42 - rhs.a42, a43: self.a43 - rhs.a43, a44: self.a44 - rhs.a44,
482 }
483 }
484}
485impl<T: Copy + ops::SubAssign> ops::SubAssign<Mat4<T>> for Mat4<T> {
486 #[inline]
487 fn sub_assign(&mut self, rhs: Mat4<T>) {
488 self.a11 -= rhs.a11; self.a12 -= rhs.a12; self.a13 -= rhs.a13; self.a14 -= rhs.a14;
489 self.a21 -= rhs.a21; self.a22 -= rhs.a22; self.a23 -= rhs.a23; self.a24 -= rhs.a24;
490 self.a31 -= rhs.a31; self.a32 -= rhs.a32; self.a33 -= rhs.a33; self.a34 -= rhs.a34;
491 self.a41 -= rhs.a41; self.a42 -= rhs.a42; self.a43 -= rhs.a43; self.a44 -= rhs.a44;
492 }
493}
494
495impl<T: Copy + ops::Mul<Output = T>> ops::Mul<T> for Mat4<T> {
496 type Output = Mat4<T>;
497 #[inline]
498 fn mul(self, rhs: T) -> Mat4<T> {
499 Mat4 {
500 a11: self.a11 * rhs, a12: self.a12 * rhs, a13: self.a13 * rhs, a14: self.a14 * rhs,
501 a21: self.a21 * rhs, a22: self.a22 * rhs, a23: self.a23 * rhs, a24: self.a24 * rhs,
502 a31: self.a31 * rhs, a32: self.a32 * rhs, a33: self.a33 * rhs, a34: self.a34 * rhs,
503 a41: self.a41 * rhs, a42: self.a42 * rhs, a43: self.a43 * rhs, a44: self.a44 * rhs,
504 }
505 }
506}
507impl<T: Copy + ops::MulAssign> ops::MulAssign<T> for Mat4<T> {
508 #[inline]
509 fn mul_assign(&mut self, rhs: T) {
510 self.a11 *= rhs; self.a12 *= rhs; self.a13 *= rhs; self.a14 *= rhs;
511 self.a21 *= rhs; self.a22 *= rhs; self.a23 *= rhs; self.a24 *= rhs;
512 self.a31 *= rhs; self.a32 *= rhs; self.a33 *= rhs; self.a34 *= rhs;
513 self.a41 *= rhs; self.a42 *= rhs; self.a43 *= rhs; self.a44 *= rhs;
514 }
515}
516
517impl<T: Copy + ops::Add<Output = T> + ops::Mul<Output = T>> ops::Mul<Vec4<T>> for Mat4<T> {
518 type Output = Vec4<T>;
519 #[inline]
520 fn mul(self, rhs: Vec4<T>) -> Vec4<T> {
521 Vec4 {
522 x: self.a11 * rhs.x + self.a12 * rhs.y + self.a13 * rhs.z + self.a14 * rhs.w,
523 y: self.a21 * rhs.x + self.a22 * rhs.y + self.a23 * rhs.z + self.a24 * rhs.w,
524 z: self.a31 * rhs.x + self.a32 * rhs.y + self.a33 * rhs.z + self.a34 * rhs.w,
525 w: self.a41 * rhs.x + self.a42 * rhs.y + self.a43 * rhs.z + self.a44 * rhs.w,
526 }
527 }
528}
529
530impl<T: Copy + ops::Add<Output = T> + ops::Mul<Output = T>> ops::Mul<Mat4<T>> for Mat4<T> {
531 type Output = Mat4<T>;
532 #[inline]
533 fn mul(self, rhs: Mat4<T>) -> Mat4<T> {
534 Mat4 {
535 a11: self.a11 * rhs.a11 + self.a12 * rhs.a21 + self.a13 * rhs.a31 + self.a14 * rhs.a41,
536 a12: self.a11 * rhs.a12 + self.a12 * rhs.a22 + self.a13 * rhs.a32 + self.a14 * rhs.a42,
537 a13: self.a11 * rhs.a13 + self.a12 * rhs.a23 + self.a13 * rhs.a33 + self.a14 * rhs.a43,
538 a14: self.a11 * rhs.a14 + self.a12 * rhs.a24 + self.a13 * rhs.a34 + self.a14 * rhs.a44,
539
540 a21: self.a21 * rhs.a11 + self.a22 * rhs.a21 + self.a23 * rhs.a31 + self.a24 * rhs.a41,
541 a22: self.a21 * rhs.a12 + self.a22 * rhs.a22 + self.a23 * rhs.a32 + self.a24 * rhs.a42,
542 a23: self.a21 * rhs.a13 + self.a22 * rhs.a23 + self.a23 * rhs.a33 + self.a24 * rhs.a43,
543 a24: self.a21 * rhs.a14 + self.a22 * rhs.a24 + self.a23 * rhs.a34 + self.a24 * rhs.a44,
544
545 a31: self.a31 * rhs.a11 + self.a32 * rhs.a21 + self.a33 * rhs.a31 + self.a34 * rhs.a41,
546 a32: self.a31 * rhs.a12 + self.a32 * rhs.a22 + self.a33 * rhs.a32 + self.a34 * rhs.a42,
547 a33: self.a31 * rhs.a13 + self.a32 * rhs.a23 + self.a33 * rhs.a33 + self.a34 * rhs.a43,
548 a34: self.a31 * rhs.a14 + self.a32 * rhs.a24 + self.a33 * rhs.a34 + self.a34 * rhs.a44,
549
550 a41: self.a41 * rhs.a11 + self.a42 * rhs.a21 + self.a43 * rhs.a31 + self.a44 * rhs.a41,
551 a42: self.a41 * rhs.a12 + self.a42 * rhs.a22 + self.a43 * rhs.a32 + self.a44 * rhs.a42,
552 a43: self.a41 * rhs.a13 + self.a42 * rhs.a23 + self.a43 * rhs.a33 + self.a44 * rhs.a43,
553 a44: self.a41 * rhs.a14 + self.a42 * rhs.a24 + self.a43 * rhs.a34 + self.a44 * rhs.a44,
554 }
555 }
556}
557impl<T: Copy + ops::Add<Output = T> + ops::Mul<Output = T>> ops::MulAssign<Mat4<T>> for Mat4<T> {
558 #[inline]
559 fn mul_assign(&mut self, rhs: Mat4<T>) {
560 *self = *self * rhs;
561 }
562}
563
564impl<T: Copy + ops::Add<Output = T> + ops::Mul<Output = T>> ops::Mul<Transform3<T>> for Mat4<T> {
565 type Output = Mat4<T>;
566 #[inline]
567 fn mul(self, rhs: Transform3<T>) -> Mat4<T> {
568 Mat4 {
569 a11: self.a11 * rhs.a11 + self.a12 * rhs.a21 + self.a13 * rhs.a31,
570 a12: self.a11 * rhs.a12 + self.a12 * rhs.a22 + self.a13 * rhs.a32,
571 a13: self.a11 * rhs.a13 + self.a12 * rhs.a23 + self.a13 * rhs.a33,
572 a14: self.a11 * rhs.a14 + self.a12 * rhs.a24 + self.a13 * rhs.a34 + self.a14,
573
574 a21: self.a21 * rhs.a11 + self.a22 * rhs.a21 + self.a23 * rhs.a31,
575 a22: self.a21 * rhs.a12 + self.a22 * rhs.a22 + self.a23 * rhs.a32,
576 a23: self.a21 * rhs.a13 + self.a22 * rhs.a23 + self.a23 * rhs.a33,
577 a24: self.a21 * rhs.a14 + self.a22 * rhs.a24 + self.a23 * rhs.a34 + self.a24,
578
579 a31: self.a31 * rhs.a11 + self.a32 * rhs.a21 + self.a33 * rhs.a31,
580 a32: self.a31 * rhs.a12 + self.a32 * rhs.a22 + self.a33 * rhs.a32,
581 a33: self.a31 * rhs.a13 + self.a32 * rhs.a23 + self.a33 * rhs.a33,
582 a34: self.a31 * rhs.a14 + self.a32 * rhs.a24 + self.a33 * rhs.a34 + self.a34,
583
584 a41: self.a41 * rhs.a11 + self.a42 * rhs.a21 + self.a43 * rhs.a31,
585 a42: self.a41 * rhs.a12 + self.a42 * rhs.a22 + self.a43 * rhs.a32,
586 a43: self.a41 * rhs.a13 + self.a42 * rhs.a23 + self.a43 * rhs.a33,
587 a44: self.a41 * rhs.a14 + self.a42 * rhs.a24 + self.a43 * rhs.a34 + self.a44,
588 }
589 }
590}
591impl<T: Copy + ops::Add<Output = T> + ops::Mul<Output = T>> ops::MulAssign<Transform3<T>> for Mat4<T> {
592 #[inline]
593 fn mul_assign(&mut self, rhs: Transform3<T>) {
594 *self = *self * rhs;
595 }
596}
597
598#[inline(always)]
601fn glu_invert<T: Float>(this: &Mat4<T>) -> Option<Mat4<T>> {
602 let m = [
603 this.a11, this.a12, this.a13, this.a14,
604 this.a21, this.a22, this.a23, this.a24,
605 this.a31, this.a32, this.a33, this.a34,
606 this.a41, this.a42, this.a43, this.a44,
607 ];
608
609 let mut inv = [T::ZERO; 16];
610
611 inv[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15]
612 + m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10];
613
614 inv[4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15]
615 - m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10];
616
617 inv[8] = m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15]
618 + m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[9];
619
620 inv[12] = -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14]
621 - m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[9];
622
623 inv[1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15]
624 - m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10];
625
626 inv[5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15]
627 + m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10];
628
629 inv[9] = -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15]
630 - m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[9];
631
632 inv[13] = m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14]
633 + m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[9];
634
635 inv[2] = m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - m[5] * m[2] * m[15]
636 + m[5] * m[3] * m[14] + m[13] * m[2] * m[7] - m[13] * m[3] * m[6];
637
638 inv[6] = -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] + m[4] * m[2] * m[15]
639 - m[4] * m[3] * m[14] - m[12] * m[2] * m[7] + m[12] * m[3] * m[6];
640
641 inv[10] = m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - m[4] * m[1] * m[15]
642 + m[4] * m[3] * m[13] + m[12] * m[1] * m[7] - m[12] * m[3] * m[5];
643
644 inv[14] = -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] + m[4] * m[1] * m[14]
645 - m[4] * m[2] * m[13] - m[12] * m[1] * m[6] + m[12] * m[2] * m[5];
646
647 inv[3] = -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] + m[5] * m[2] * m[11]
648 - m[5] * m[3] * m[10] - m[9] * m[2] * m[7] + m[9] * m[3] * m[6];
649
650 inv[7] = m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - m[4] * m[2] * m[11]
651 + m[4] * m[3] * m[10] + m[8] * m[2] * m[7] - m[8] * m[3] * m[6];
652
653 inv[11] = -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] + m[4] * m[1] * m[11]
654 - m[4] * m[3] * m[9] - m[8] * m[1] * m[7] + m[8] * m[3] * m[5];
655
656 inv[15] = m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - m[4] * m[1] * m[10]
657 + m[4] * m[2] * m[9] + m[8] * m[1] * m[6] - m[8] * m[2] * m[5];
658
659 let det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
660 if det == T::ZERO {
661 return None; }
663
664 let inv_det = T::ONE / det;
665
666 Some(Mat4 {
667 a11: inv[0] * inv_det, a12: inv[1] * inv_det, a13: inv[2] * inv_det, a14: inv[3] * inv_det,
668 a21: inv[4] * inv_det, a22: inv[5] * inv_det, a23: inv[6] * inv_det, a24: inv[7] * inv_det,
669 a31: inv[8] * inv_det, a32: inv[9] * inv_det, a33: inv[10] * inv_det, a34: inv[11] * inv_det,
670 a41: inv[12] * inv_det, a42: inv[13] * inv_det, a43: inv[14] * inv_det, a44: inv[15] * inv_det,
671 })
672}
673
674impl_mat_neg!(Mat4);
675impl_mat_add_mat!(Mat4);
676impl_mat_sub_mat!(Mat4);
677impl_mat_mul_scalar!(Mat4);
678impl_mat_mul_vec!(Mat4, Vec4);
679impl_mat_mul_mat!(Mat4);
680
681impl<T: fmt::Display> fmt::Display for Mat4<T> {
685 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
686 f.write_str("Mat4(")?;
687 print::print(&move |i| &self.as_array()[i], 0x44, f)?;
688 f.write_str(")")
689 }
690}
691impl<T: fmt::Debug> fmt::Debug for Mat4<T> {
692 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
693 f.write_str("Mat4(")?;
694 print::print(&move |i| print::Debug(&self.as_array()[i]), 0x44, f)?;
695 f.write_str(")")
696 }
697}
698
699#[test]
703fn test_inverse() {
704 let mut rng = urandom::seeded(42);
705
706 for _ in 0..1000 {
707 let fov_y = Angle::deg(rng.range(1.0..179.0));
708
709 let aspect = rng.range(0.5..4.0);
710
711 let near = rng.range(0.1..10.0);
712 let far = near + rng.range(10.0..100.0);
713
714 let hand = if rng.coin_flip() { Hand::RH } else { Hand::LH };
715 let clip = if rng.coin_flip() { Clip::NO } else { Clip::ZO };
716
717 let mat = Mat4::perspective(fov_y, aspect, near, far, (hand, clip));
718 let inv = mat.inverse();
719
720 let p = Vec4(
721 rng.range(-10.0..10.0),
722 rng.range(-10.0..10.0),
723 rng.range(near..far),
724 rng.range(0.1..10.0),
725 );
726
727 let projected = mat * p;
728 let unprojected = inv * projected;
729 let _identity = mat * inv;
730
731 let error = (unprojected - p).len();
732 assert!(error < 1e-6, "Failed for fov_y: {fov_y}, aspect: {aspect}, near: {near}, far: {far}, hand: {hand:?}, clip: {clip:?}, p: {p:?}, error: {error}");
733 }
734}
735
736#[test]
737fn test_ortho_inverse() {
738 let near = 10.0;
739 let far = 2000.0;
740 let half_width = 400.0;
741 let half_height = 300.0;
742 let projection = Mat4f::ortho(
743 -half_width, half_width,
744 -half_height, half_height,
745 near, far,
746 (Hand::LH, Clip::NO)
747 );
748
749 dbg!(projection.det());
750
751 let inv_proj = projection.inverse();
752 let identity = projection * inv_proj;
753
754 dbg!(identity);
755
756 let error = (identity.flat_norm_sqr() - 4.0).abs();
757 assert!(error.abs() < 1e-6, "Inverse projection matrix does not yield identity: error = {error}");
758}
759
760#[test]
761fn test_add() {
762 let lhs = Mat4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
763 let rhs = Mat4(10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160);
764 let expected = Mat4(11, 22, 33, 44, 55, 66, 77, 88, 99, 110, 121, 132, 143, 154, 165, 176);
765
766 assert_eq!(lhs + rhs, expected);
767 assert_eq!(lhs + &rhs, expected);
768 assert_eq!(&lhs + rhs, expected);
769 assert_eq!(&lhs + &rhs, expected);
770
771 let mut value = lhs;
772 value += rhs;
773 assert_eq!(value, expected);
774
775 let mut value = lhs;
776 value += &rhs;
777 assert_eq!(value, expected);
778}
779
780#[test]
781fn test_sub() {
782 let lhs = Mat4(11, 22, 33, 44, 55, 66, 77, 88, 99, 110, 121, 132, 143, 154, 165, 176);
783 let rhs = Mat4(10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160);
784 let expected = Mat4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
785
786 assert_eq!(lhs - rhs, expected);
787 assert_eq!(lhs - &rhs, expected);
788 assert_eq!(&lhs - rhs, expected);
789 assert_eq!(&lhs - &rhs, expected);
790
791 let mut value = lhs;
792 value -= rhs;
793 assert_eq!(value, expected);
794
795 let mut value = lhs;
796 value -= &rhs;
797 assert_eq!(value, expected);
798}
799
800#[test]
801fn test_neg() {
802 let value = Mat4(1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12, 13, -14, 15, -16);
803 let expected = Mat4(-1, 2, -3, 4, -5, 6, -7, 8, -9, 10, -11, 12, -13, 14, -15, 16);
804 assert_eq!(-value, expected);
805 assert_eq!(-&value, expected);
806}