1use super::{Quaternion, Vec2, Vec3, Vec4, EPSILON};
18use std::ops::{Index, IndexMut, Mul};
19
20#[derive(Debug, Clone, Copy, PartialEq)]
27#[repr(C)]
28pub struct Mat3 {
29 pub cols: [Vec3; 3],
31}
32
33impl Mat3 {
34 pub const IDENTITY: Self = Self {
36 cols: [Vec3::X, Vec3::Y, Vec3::Z],
37 };
38
39 pub const ZERO: Self = Self {
41 cols: [Vec3::ZERO; 3],
42 };
43
44 #[inline]
46 pub fn from_cols(c0: Vec3, c1: Vec3, c2: Vec3) -> Self {
47 Self { cols: [c0, c1, c2] }
48 }
49
50 #[allow(dead_code)]
52 #[inline]
53 fn get_row(&self, index: usize) -> Vec3 {
54 Vec3 {
55 x: self.cols[0].get(index),
56 y: self.cols[1].get(index),
57 z: self.cols[2].get(index),
58 }
59 }
60
61 #[inline]
65 pub fn from_scale_vec2(scale: Vec2) -> Self {
66 Self::from_scale(Vec3::new(scale.x, scale.y, 1.0))
67 }
68
69 #[inline]
71 pub fn from_scale(scale: Vec3) -> Self {
72 Self {
73 cols: [
74 Vec3::new(scale.x, 0.0, 0.0),
75 Vec3::new(0.0, scale.y, 0.0),
76 Vec3::new(0.0, 0.0, scale.z),
77 ],
78 }
79 }
80
81 #[inline]
87 pub fn from_rotation_x(angle_radians: f32) -> Self {
88 let (s, c) = angle_radians.sin_cos();
89 Self {
90 cols: [
91 Vec3::new(1.0, 0.0, 0.0),
92 Vec3::new(0.0, c, s),
93 Vec3::new(0.0, -s, c),
94 ],
95 }
96 }
97
98 #[inline]
104 pub fn from_rotation_y(angle_radians: f32) -> Self {
105 let (s, c) = angle_radians.sin_cos();
106 Self {
107 cols: [
108 Vec3::new(c, 0.0, -s),
109 Vec3::new(0.0, 1.0, 0.0),
110 Vec3::new(s, 0.0, c),
111 ],
112 }
113 }
114
115 #[inline]
121 pub fn from_rotation_z(angle_radians: f32) -> Self {
122 let (s, c) = angle_radians.sin_cos();
123 Self {
124 cols: [
125 Vec3::new(c, s, 0.0),
126 Vec3::new(-s, c, 0.0),
127 Vec3::new(0.0, 0.0, 1.0),
128 ],
129 }
130 }
131
132 #[inline]
139 pub fn from_axis_angle(axis: Vec3, angle_radians: f32) -> Self {
140 let (s, c) = angle_radians.sin_cos();
141 let t = 1.0 - c;
142 let x = axis.x;
143 let y = axis.y;
144 let z = axis.z;
145 Self {
146 cols: [
147 Vec3::new(t * x * x + c, t * x * y + s * z, t * x * z - s * y),
148 Vec3::new(t * y * x - s * z, t * y * y + c, t * y * z + s * x),
149 Vec3::new(t * z * x + s * y, t * z * y - s * x, t * z * z + c),
150 ],
151 }
152 }
153
154 #[inline]
157 pub fn from_quat(q: Quaternion) -> Self {
158 let q = q.normalize();
159 let x = q.x;
160 let y = q.y;
161 let z = q.z;
162 let w = q.w;
163 let x2 = x + x;
164 let y2 = y + y;
165 let z2 = z + z;
166 let xx = x * x2;
167 let xy = x * y2;
168 let xz = x * z2;
169 let yy = y * y2;
170 let yz = y * z2;
171 let zz = z * z2;
172 let wx = w * x2;
173 let wy = w * y2;
174 let wz = w * z2;
175
176 Self::from_cols(
177 Vec3::new(1.0 - (yy + zz), xy + wz, xz - wy),
178 Vec3::new(xy - wz, 1.0 - (xx + zz), yz + wx),
179 Vec3::new(xz + wy, yz - wx, 1.0 - (xx + yy)),
180 )
181 }
182
183 #[inline]
186 pub fn from_mat4(m4: &Mat4) -> Self {
187 Self::from_cols(
188 m4.cols[0].truncate(),
189 m4.cols[1].truncate(),
190 m4.cols[2].truncate(),
191 )
192 }
193
194 #[inline]
199 pub fn determinant(&self) -> f32 {
200 let c0 = self.cols[0];
201 let c1 = self.cols[1];
202 let c2 = self.cols[2];
203 c0.x * (c1.y * c2.z - c2.y * c1.z) - c1.x * (c0.y * c2.z - c2.y * c0.z)
204 + c2.x * (c0.y * c1.z - c1.y * c0.z)
205 }
206
207 #[inline]
209 pub fn transpose(&self) -> Self {
210 Self::from_cols(
211 Vec3::new(self.cols[0].x, self.cols[1].x, self.cols[2].x),
212 Vec3::new(self.cols[0].y, self.cols[1].y, self.cols[2].y),
213 Vec3::new(self.cols[0].z, self.cols[1].z, self.cols[2].z),
214 )
215 }
216
217 pub fn inverse(&self) -> Option<Self> {
222 let c0 = self.cols[0];
223 let c1 = self.cols[1];
224 let c2 = self.cols[2];
225 let m00 = c1.y * c2.z - c2.y * c1.z;
226 let m10 = c2.y * c0.z - c0.y * c2.z;
227 let m20 = c0.y * c1.z - c1.y * c0.z;
228 let det = c0.x * m00 + c1.x * m10 + c2.x * m20;
229
230 if det.abs() < EPSILON {
231 return None;
232 }
233
234 let inv_det = 1.0 / det;
235 let m01 = c2.x * c1.z - c1.x * c2.z;
236 let m11 = c0.x * c2.z - c2.x * c0.z;
237 let m21 = c1.x * c0.z - c0.x * c1.z;
238 let m02 = c1.x * c2.y - c2.x * c1.y;
239 let m12 = c2.x * c0.y - c0.x * c2.y;
240 let m22 = c0.x * c1.y - c1.x * c0.y;
241
242 Some(Self::from_cols(
243 Vec3::new(m00, m10, m20) * inv_det,
244 Vec3::new(m01, m11, m21) * inv_det,
245 Vec3::new(m02, m12, m22) * inv_det,
246 ))
247 }
248
249 #[inline]
252 pub fn to_mat4(&self) -> Mat4 {
253 Mat4::from_cols(
254 Vec4::from_vec3(self.cols[0], 0.0),
255 Vec4::from_vec3(self.cols[1], 0.0),
256 Vec4::from_vec3(self.cols[2], 0.0),
257 Vec4::W,
258 )
259 }
260}
261
262impl Default for Mat3 {
265 #[inline]
267 fn default() -> Self {
268 Self::IDENTITY
269 }
270}
271
272impl Mul<Mat3> for Mat3 {
273 type Output = Self;
274 #[inline]
276 fn mul(self, rhs: Mat3) -> Self::Output {
277 Self::from_cols(self * rhs.cols[0], self * rhs.cols[1], self * rhs.cols[2])
278 }
279}
280
281impl Mul<Vec3> for Mat3 {
282 type Output = Vec3;
283 #[inline]
285 fn mul(self, v: Vec3) -> Self::Output {
286 self.cols[0] * v.x + self.cols[1] * v.y + self.cols[2] * v.z
287 }
288}
289
290impl Index<usize> for Mat3 {
291 type Output = Vec3;
292 #[inline]
294 fn index(&self, index: usize) -> &Self::Output {
295 &self.cols[index]
296 }
297}
298
299impl IndexMut<usize> for Mat3 {
300 #[inline]
302 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
303 &mut self.cols[index]
304 }
305}
306
307#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
316#[repr(C)]
317pub struct Mat4 {
318 pub cols: [Vec4; 4],
320}
321
322impl Mat4 {
323 pub const IDENTITY: Self = Self {
325 cols: [Vec4::X, Vec4::Y, Vec4::Z, Vec4::W],
326 };
327
328 pub const ZERO: Self = Self {
330 cols: [Vec4::ZERO; 4],
331 };
332
333 #[inline]
335 pub fn from_cols(c0: Vec4, c1: Vec4, c2: Vec4, c3: Vec4) -> Self {
336 Self {
337 cols: [c0, c1, c2, c3],
338 }
339 }
340
341 #[inline]
343 pub fn get_row(&self, index: usize) -> Vec4 {
344 Vec4 {
345 x: self.cols[0].get(index),
346 y: self.cols[1].get(index),
347 z: self.cols[2].get(index),
348 w: self.cols[3].get(index),
349 }
350 }
351
352 #[inline]
354 pub const fn to_cols_array_2d(&self) -> [[f32; 4]; 4] {
355 [
356 [
357 self.cols[0].x,
358 self.cols[0].y,
359 self.cols[0].z,
360 self.cols[0].w,
361 ],
362 [
363 self.cols[1].x,
364 self.cols[1].y,
365 self.cols[1].z,
366 self.cols[1].w,
367 ],
368 [
369 self.cols[2].x,
370 self.cols[2].y,
371 self.cols[2].z,
372 self.cols[2].w,
373 ],
374 [
375 self.cols[3].x,
376 self.cols[3].y,
377 self.cols[3].z,
378 self.cols[3].w,
379 ],
380 ]
381 }
382
383 #[inline]
389 pub fn from_translation(v: Vec3) -> Self {
390 Self {
391 cols: [
392 Vec4::new(1.0, 0.0, 0.0, 0.0),
393 Vec4::new(0.0, 1.0, 0.0, 0.0),
394 Vec4::new(0.0, 0.0, 1.0, 0.0),
395 Vec4::new(v.x, v.y, v.z, 1.0),
396 ],
397 }
398 }
399
400 #[inline]
402 pub fn from_scale(scale: Vec3) -> Self {
403 Self {
404 cols: [
405 Vec4::new(scale.x, 0.0, 0.0, 0.0),
406 Vec4::new(0.0, scale.y, 0.0, 0.0),
407 Vec4::new(0.0, 0.0, scale.z, 0.0),
408 Vec4::new(0.0, 0.0, 0.0, 1.0),
409 ],
410 }
411 }
412
413 #[inline]
419 pub fn from_rotation_x(angle: f32) -> Self {
420 let c = angle.cos();
421 let s = angle.sin();
422 Self {
423 cols: [
424 Vec4::new(1.0, 0.0, 0.0, 0.0),
425 Vec4::new(0.0, c, s, 0.0),
426 Vec4::new(0.0, -s, c, 0.0),
427 Vec4::new(0.0, 0.0, 0.0, 1.0),
428 ],
429 }
430 }
431
432 #[inline]
438 pub fn from_rotation_y(angle: f32) -> Self {
439 let c = angle.cos();
440 let s = angle.sin();
441 Self {
442 cols: [
443 Vec4::new(c, 0.0, -s, 0.0),
444 Vec4::new(0.0, 1.0, 0.0, 0.0),
445 Vec4::new(s, 0.0, c, 0.0),
446 Vec4::new(0.0, 0.0, 0.0, 1.0),
447 ],
448 }
449 }
450
451 #[inline]
457 pub fn from_rotation_z(angle: f32) -> Self {
458 let c = angle.cos();
459 let s = angle.sin();
460 Self {
461 cols: [
462 Vec4::new(c, s, 0.0, 0.0),
463 Vec4::new(-s, c, 0.0, 0.0),
464 Vec4::new(0.0, 0.0, 1.0, 0.0),
465 Vec4::new(0.0, 0.0, 0.0, 1.0),
466 ],
467 }
468 }
469
470 #[inline]
477 pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self {
478 let c = angle.cos();
479 let s = angle.sin();
480 let t = 1.0 - c;
481 let x = axis.x;
482 let y = axis.y;
483 let z = axis.z;
484
485 Self {
486 cols: [
487 Vec4::new(t * x * x + c, t * x * y - s * z, t * x * z + s * y, 0.0),
488 Vec4::new(t * y * x + s * z, t * y * y + c, t * y * z - s * x, 0.0),
489 Vec4::new(t * z * x - s * y, t * z * y + s * x, t * z * z + c, 0.0),
490 Vec4::new(0.0, 0.0, 0.0, 1.0),
491 ],
492 }
493 }
494
495 #[inline]
497 pub fn from_quat(q: Quaternion) -> Self {
498 let x = q.x;
499 let y = q.y;
500 let z = q.z;
501 let w = q.w;
502 let x2 = x + x;
503 let y2 = y + y;
504 let z2 = z + z;
505 let xx = x * x2;
506 let xy = x * y2;
507 let xz = x * z2;
508 let yy = y * y2;
509 let yz = y * z2;
510 let zz = z * z2;
511 let wx = w * x2;
512 let wy = w * y2;
513 let wz = w * z2;
514
515 Self::from_cols(
516 Vec4::new(1.0 - (yy + zz), xy + wz, xz - wy, 0.0),
517 Vec4::new(xy - wz, 1.0 - (xx + zz), yz + wx, 0.0),
518 Vec4::new(xz + wy, yz - wx, 1.0 - (xx + yy), 0.0),
519 Vec4::W,
520 )
521 }
522
523 #[inline]
532 pub fn perspective_rh_zo(
533 fov_y_radians: f32,
534 aspect_ratio: f32,
535 z_near: f32,
536 z_far: f32,
537 ) -> Self {
538 assert!(z_near > 0.0 && z_far > z_near);
539 let tan_half_fovy = (fov_y_radians / 2.0).tan();
540 let f = 1.0 / tan_half_fovy;
541 let aa = f / aspect_ratio;
542 let bb = f;
543 let cc = z_far / (z_near - z_far);
544 let dd = (z_near * z_far) / (z_near - z_far);
545
546 Self::from_cols(
547 Vec4::new(aa, 0.0, 0.0, 0.0),
548 Vec4::new(0.0, bb, 0.0, 0.0),
549 Vec4::new(0.0, 0.0, cc, -1.0),
550 Vec4::new(0.0, 0.0, dd, 0.0),
551 )
552 }
553
554 #[inline]
556 pub fn orthographic_rh_zo(
557 left: f32,
558 right: f32,
559 bottom: f32,
560 top: f32,
561 z_near: f32,
562 z_far: f32,
563 ) -> Self {
564 let rml = right - left;
565 let rpl = right + left;
566 let tmb = top - bottom;
567 let tpb = top + bottom;
568 let fmn = z_far - z_near;
569 let aa = 2.0 / rml;
570 let bb = 2.0 / tmb;
571 let cc = -1.0 / fmn;
572 let dd = -rpl / rml;
573 let ee = -tpb / tmb;
574 let ff = -z_near / fmn;
575
576 Self::from_cols(
577 Vec4::new(aa, 0.0, 0.0, 0.0),
578 Vec4::new(0.0, bb, 0.0, 0.0),
579 Vec4::new(0.0, 0.0, cc, 0.0),
580 Vec4::new(dd, ee, ff, 1.0),
581 )
582 }
583
584 #[inline]
597 pub fn look_at_rh(eye: Vec3, target: Vec3, up: Vec3) -> Option<Self> {
598 let forward = target - eye;
599 if forward.length_squared() < crate::math::EPSILON * crate::math::EPSILON {
600 return None;
601 }
602 let f = forward.normalize();
603 let s = f.cross(up);
604 if s.length_squared() < crate::math::EPSILON * crate::math::EPSILON {
605 return None;
606 }
607 let s = s.normalize();
608 let u = s.cross(f);
609
610 Some(Self::from_cols(
611 Vec4::new(s.x, u.x, -f.x, 0.0),
612 Vec4::new(s.y, u.y, -f.y, 0.0),
613 Vec4::new(s.z, u.z, -f.z, 0.0),
614 Vec4::new(-eye.dot(s), -eye.dot(u), eye.dot(f), 1.0),
615 ))
616 }
617
618 #[inline]
620 pub fn transpose(&self) -> Self {
621 Self::from_cols(
622 Vec4::new(
623 self.cols[0].x,
624 self.cols[1].x,
625 self.cols[2].x,
626 self.cols[3].x,
627 ),
628 Vec4::new(
629 self.cols[0].y,
630 self.cols[1].y,
631 self.cols[2].y,
632 self.cols[3].y,
633 ),
634 Vec4::new(
635 self.cols[0].z,
636 self.cols[1].z,
637 self.cols[2].z,
638 self.cols[3].z,
639 ),
640 Vec4::new(
641 self.cols[0].w,
642 self.cols[1].w,
643 self.cols[2].w,
644 self.cols[3].w,
645 ),
646 )
647 }
648
649 pub fn determinant(&self) -> f32 {
651 let c0 = self.cols[0];
652 let c1 = self.cols[1];
653 let c2 = self.cols[2];
654 let c3 = self.cols[3];
655
656 let m00 = c1.y * (c2.z * c3.w - c3.z * c2.w) - c2.y * (c1.z * c3.w - c3.z * c1.w)
657 + c3.y * (c1.z * c2.w - c2.z * c1.w);
658 let m01 = c0.y * (c2.z * c3.w - c3.z * c2.w) - c2.y * (c0.z * c3.w - c3.z * c0.w)
659 + c3.y * (c0.z * c2.w - c2.z * c0.w);
660 let m02 = c0.y * (c1.z * c3.w - c3.z * c1.w) - c1.y * (c0.z * c3.w - c3.z * c0.w)
661 + c3.y * (c0.z * c1.w - c1.z * c0.w);
662 let m03 = c0.y * (c1.z * c2.w - c2.z * c1.w) - c1.y * (c0.z * c2.w - c2.z * c0.w)
663 + c2.y * (c0.z * c1.w - c1.z * c0.w);
664
665 c0.x * m00 - c1.x * m01 + c2.x * m02 - c3.x * m03
666 }
667
668 pub fn inverse(&self) -> Option<Self> {
671 let c0 = self.cols[0];
672 let c1 = self.cols[1];
673 let c2 = self.cols[2];
674 let c3 = self.cols[3];
675
676 let a00 = c1.y * (c2.z * c3.w - c3.z * c2.w) - c2.y * (c1.z * c3.w - c3.z * c1.w)
677 + c3.y * (c1.z * c2.w - c2.z * c1.w);
678 let a01 = -(c1.x * (c2.z * c3.w - c3.z * c2.w) - c2.x * (c1.z * c3.w - c3.z * c1.w)
679 + c3.x * (c1.z * c2.w - c2.z * c1.w));
680 let a02 = c1.x * (c2.y * c3.w - c3.y * c2.w) - c2.x * (c1.y * c3.w - c3.y * c1.w)
681 + c3.x * (c1.y * c2.w - c2.y * c1.w);
682 let a03 = -(c1.x * (c2.y * c3.z - c3.y * c2.z) - c2.x * (c1.y * c3.z - c3.y * c1.z)
683 + c3.x * (c1.y * c2.z - c2.y * c1.z));
684
685 let a10 = -(c0.y * (c2.z * c3.w - c3.z * c2.w) - c2.y * (c0.z * c3.w - c3.z * c0.w)
686 + c3.y * (c0.z * c2.w - c2.z * c0.w));
687 let a11 = c0.x * (c2.z * c3.w - c3.z * c2.w) - c2.x * (c0.z * c3.w - c3.z * c0.w)
688 + c3.x * (c0.z * c2.w - c2.z * c0.w);
689 let a12 = -(c0.x * (c2.y * c3.w - c3.y * c2.w) - c2.x * (c0.y * c3.w - c3.y * c0.w)
690 + c3.x * (c0.y * c2.w - c2.y * c0.w));
691 let a13 = c0.x * (c2.y * c3.z - c3.y * c2.z) - c2.x * (c0.y * c3.z - c3.y * c0.z)
692 + c3.x * (c0.y * c2.z - c2.y * c0.z);
693
694 let a20 = c0.y * (c1.z * c3.w - c3.z * c1.w) - c1.y * (c0.z * c3.w - c3.z * c0.w)
695 + c3.y * (c0.z * c1.w - c1.z * c0.w);
696 let a21 = -(c0.x * (c1.z * c3.w - c3.z * c1.w) - c1.x * (c0.z * c3.w - c3.z * c0.w)
697 + c3.x * (c0.z * c1.w - c1.z * c0.w));
698 let a22 = c0.x * (c1.y * c3.w - c3.y * c1.w) - c1.x * (c0.y * c3.w - c3.y * c0.w)
699 + c3.x * (c0.y * c1.w - c1.y * c0.w);
700 let a23 = -(c0.x * (c1.y * c3.z - c3.y * c1.z) - c1.x * (c0.y * c3.z - c3.y * c0.z)
701 + c3.x * (c0.y * c1.z - c1.y * c0.z));
702
703 let a30 = -(c0.y * (c1.z * c2.w - c2.z * c1.w) - c1.y * (c0.z * c2.w - c2.z * c0.w)
704 + c2.y * (c0.z * c1.w - c1.z * c0.w));
705 let a31 = c0.x * (c1.z * c2.w - c2.z * c1.w) - c1.x * (c0.z * c2.w - c2.z * c0.w)
706 + c2.x * (c0.z * c1.w - c1.z * c0.w);
707 let a32 = -(c0.x * (c1.y * c2.w - c2.y * c1.w) - c1.x * (c0.y * c2.w - c2.y * c0.w)
708 + c2.x * (c0.y * c1.w - c1.y * c0.w));
709 let a33 = c0.x * (c1.y * c2.z - c2.y * c1.z) - c1.x * (c0.y * c2.z - c2.y * c0.z)
710 + c2.x * (c0.y * c1.z - c1.y * c0.z);
711
712 let det = c0.x * a00 + c1.x * a10 + c2.x * a20 + c3.x * a30;
713 if det.abs() < crate::math::EPSILON {
714 return None;
715 }
716 let inv_det = 1.0 / det;
717
718 Some(Self::from_cols(
719 Vec4::new(a00 * inv_det, a10 * inv_det, a20 * inv_det, a30 * inv_det),
720 Vec4::new(a01 * inv_det, a11 * inv_det, a21 * inv_det, a31 * inv_det),
721 Vec4::new(a02 * inv_det, a12 * inv_det, a22 * inv_det, a32 * inv_det),
722 Vec4::new(a03 * inv_det, a13 * inv_det, a23 * inv_det, a33 * inv_det),
723 ))
724 }
725
726 #[inline]
735 pub fn affine_inverse(&self) -> Option<Self> {
736 let c0 = self.cols[0].truncate();
737 let c1 = self.cols[1].truncate();
738 let c2 = self.cols[2].truncate();
739 let translation = self.cols[3].truncate();
740 let det3x3 = c0.x * (c1.y * c2.z - c2.y * c1.z) - c1.x * (c0.y * c2.z - c2.y * c0.z)
741 + c2.x * (c0.y * c1.z - c1.y * c0.z);
742
743 if det3x3.abs() < crate::math::EPSILON {
744 return None;
745 }
746
747 let inv_det3x3 = 1.0 / det3x3;
748 let inv00 = (c1.y * c2.z - c2.y * c1.z) * inv_det3x3;
749 let inv10 = -(c2.y * c0.z - c0.y * c2.z) * inv_det3x3;
750 let inv20 = (c0.y * c1.z - c1.y * c0.z) * inv_det3x3;
751 let inv01 = -(c2.x * c1.z - c1.x * c2.z) * inv_det3x3;
752 let inv11 = (c0.x * c2.z - c2.x * c0.z) * inv_det3x3;
753 let inv21 = -(c1.x * c0.z - c0.x * c1.z) * inv_det3x3;
754 let inv02 = (c1.x * c2.y - c2.x * c1.y) * inv_det3x3;
755 let inv12 = -(c2.x * c0.y - c0.x * c2.y) * inv_det3x3;
756 let inv22 = (c0.x * c1.y - c1.x * c0.y) * inv_det3x3;
757 let inv_tx = -(inv00 * translation.x + inv01 * translation.y + inv02 * translation.z);
758 let inv_ty = -(inv10 * translation.x + inv11 * translation.y + inv12 * translation.z);
759 let inv_tz = -(inv20 * translation.x + inv21 * translation.y + inv22 * translation.z);
760
761 Some(Self::from_cols(
762 Vec4::new(inv00, inv10, inv20, 0.0),
763 Vec4::new(inv01, inv11, inv21, 0.0),
764 Vec4::new(inv02, inv12, inv22, 0.0),
765 Vec4::new(inv_tx, inv_ty, inv_tz, 1.0),
766 ))
767 }
768}
769
770impl Default for Mat4 {
773 #[inline]
775 fn default() -> Self {
776 Self::IDENTITY
777 }
778}
779
780impl Mul<Mat4> for Mat4 {
781 type Output = Self;
782 #[inline]
784 fn mul(self, rhs: Mat4) -> Self::Output {
785 let mut result_cols = [Vec4 {
786 x: 0.0,
787 y: 0.0,
788 z: 0.0,
789 w: 0.0,
790 }; 4];
791 for (c_idx, target_col_ref_mut) in result_cols.iter_mut().enumerate().take(4) {
792 let col_from_rhs = rhs.cols[c_idx];
793 *target_col_ref_mut = Vec4 {
794 x: self.get_row(0).dot(col_from_rhs),
795 y: self.get_row(1).dot(col_from_rhs),
796 z: self.get_row(2).dot(col_from_rhs),
797 w: self.get_row(3).dot(col_from_rhs),
798 };
799 }
800 Mat4 { cols: result_cols }
801 }
802}
803
804impl Mul<Vec4> for Mat4 {
805 type Output = Vec4;
806 #[inline]
808 fn mul(self, rhs: Vec4) -> Self::Output {
809 self.cols[0] * rhs.x + self.cols[1] * rhs.y + self.cols[2] * rhs.z + self.cols[3] * rhs.w
810 }
811}
812
813#[cfg(test)]
816mod tests {
817 use super::*;
818 use crate::math::{approx_eq, matrix::Mat4, quaternion::Quaternion, vector::Vec3, PI};
819
820 fn vec3_approx_eq(a: Vec3, b: Vec3) -> bool {
821 approx_eq(a.x, b.x) && approx_eq(a.y, b.y) && approx_eq(a.z, b.z)
822 }
823
824 fn mat3_approx_eq(a: Mat3, b: Mat3) -> bool {
825 vec3_approx_eq(a.cols[0], b.cols[0])
826 && vec3_approx_eq(a.cols[1], b.cols[1])
827 && vec3_approx_eq(a.cols[2], b.cols[2])
828 }
829
830 fn vec4_approx_eq(a: Vec4, b: Vec4) -> bool {
831 approx_eq(a.x, b.x) && approx_eq(a.y, b.y) && approx_eq(a.z, b.z) && approx_eq(a.w, b.w)
832 }
833
834 fn mat4_approx_eq(a: Mat4, b: Mat4) -> bool {
835 vec4_approx_eq(a.cols[0], b.cols[0])
836 && vec4_approx_eq(a.cols[1], b.cols[1])
837 && vec4_approx_eq(a.cols[2], b.cols[2])
838 && vec4_approx_eq(a.cols[3], b.cols[3])
839 }
840
841 #[test]
844 fn test_mat3_identity_default() {
845 assert_eq!(Mat3::default(), Mat3::IDENTITY);
846
847 let m = Mat3::from_scale(Vec3::new(1.0, 2.0, 3.0));
848 assert!(mat3_approx_eq(m * Mat3::IDENTITY, m));
849 assert!(mat3_approx_eq(Mat3::IDENTITY * m, m));
850 }
851
852 #[test]
853 fn test_mat3_from_scale() {
854 let s = Vec3::new(2.0, -3.0, 0.5);
855 let m = Mat3::from_scale(s);
856 let v = Vec3::new(1.0, 1.0, 1.0);
857 assert!(vec3_approx_eq(m * v, s)); }
859
860 #[test]
861 fn test_mat3_rotations() {
862 let angle = PI / 6.0; let mx = Mat3::from_rotation_x(angle);
864 let my = Mat3::from_rotation_y(angle);
865 let mz = Mat3::from_rotation_z(angle);
866
867 let p = Vec3::Y; let expected_px = Vec3::new(0.0, angle.cos(), angle.sin());
869 assert!(vec3_approx_eq(mx * p, expected_px));
870
871 let p = Vec3::X; let expected_py = Vec3::new(angle.cos(), 0.0, -angle.sin()); assert!(vec3_approx_eq(my * p, expected_py));
874
875 let p = Vec3::X; let expected_pz = Vec3::new(angle.cos(), angle.sin(), 0.0);
877 assert!(vec3_approx_eq(mz * p, expected_pz));
878 }
879
880 #[test]
881 fn test_mat3_from_axis_angle() {
882 let axis = Vec3::new(1.0, 1.0, 1.0).normalize();
883 let angle = 1.2 * PI;
884 let m = Mat3::from_axis_angle(axis, angle);
885
886 let v = Vec3::X;
888 let v_rotated = m * v;
889
890 assert!(approx_eq(v_rotated.length(), v.length()));
892
893 assert!(v_rotated.distance_squared(v) > EPSILON);
895 }
896
897 #[test]
898 fn test_mat3_from_quat() {
899 let axis = Vec3::new(1.0, -2.0, 3.0).normalize();
900 let angle = PI / 7.0;
901 let q = Quaternion::from_axis_angle(axis, angle);
902 let m_from_q = Mat3::from_quat(q);
903
904 let v = Vec3::new(0.5, 1.0, -0.2);
905 let v_rotated_q = q * v;
906 let v_rotated_m = m_from_q * v;
907
908 assert!(vec3_approx_eq(v_rotated_q, v_rotated_m));
909 }
910
911 #[test]
912 fn test_mat3_determinant() {
913 assert!(approx_eq(Mat3::IDENTITY.determinant(), 1.0));
914 assert!(approx_eq(Mat3::ZERO.determinant(), 0.0));
915
916 let m_scale = Mat3::from_scale(Vec3::new(2.0, 3.0, 4.0));
917 assert!(approx_eq(m_scale.determinant(), 24.0));
918
919 let m_rot = Mat3::from_rotation_y(PI / 5.0);
920 assert!(approx_eq(m_rot.determinant(), 1.0)); }
922
923 #[test]
924 fn test_mat3_transpose() {
925 let m = Mat3::from_cols(
926 Vec3::new(1.0, 2.0, 3.0),
927 Vec3::new(4.0, 5.0, 6.0),
928 Vec3::new(7.0, 8.0, 9.0),
929 );
930 let mt = m.transpose();
931 let expected_mt = Mat3::from_cols(
932 Vec3::new(1.0, 4.0, 7.0),
933 Vec3::new(2.0, 5.0, 8.0),
934 Vec3::new(3.0, 6.0, 9.0),
935 );
936
937 assert!(mat3_approx_eq(mt, expected_mt));
938 assert!(mat3_approx_eq(m.transpose().transpose(), m)); }
940
941 #[test]
942 fn test_mat3_inverse() {
943 let m = Mat3::from_rotation_z(PI / 3.0) * Mat3::from_scale(Vec3::new(1.0, 2.0, 0.5));
944 let inv_m = m.inverse().expect("Matrix should be invertible");
945 let identity = m * inv_m;
946 assert!(
947 mat3_approx_eq(identity, Mat3::IDENTITY),
948 "M * inv(M) should be Identity"
949 );
950
951 let singular = Mat3::from_scale(Vec3::new(1.0, 0.0, 1.0));
952 assert!(
953 singular.inverse().is_none(),
954 "Singular matrix inverse should be None"
955 );
956 }
957
958 #[test]
959 fn test_mat3_mul_vec3() {
960 let m = Mat3::from_rotation_z(PI / 2.0); let v = Vec3::X; let expected_v = Vec3::Y; assert!(vec3_approx_eq(m * v, expected_v));
964 }
965
966 #[test]
967 fn test_mat3_mul_mat3() {
968 let rot90z = Mat3::from_rotation_z(PI / 2.0);
969 let rot180z = rot90z * rot90z;
970 let expected_rot180z = Mat3::from_rotation_z(PI);
971 assert!(mat3_approx_eq(rot180z, expected_rot180z));
972 }
973
974 #[test]
975 fn test_mat3_conversions() {
976 let m4 = Mat4::from_translation(Vec3::new(10., 20., 30.)) * Mat4::from_rotation_x(PI / 4.0);
977 let m3 = Mat3::from_mat4(&m4);
978 let m4_again = m3.to_mat4();
979
980 let v = Vec3::Y;
982 let v_rot_m3 = m3 * v;
983 let v_rot_m4 = Mat4::from_rotation_x(PI / 4.0) * Vec4::from_vec3(v, 0.0); assert!(vec3_approx_eq(v_rot_m3, v_rot_m4.truncate()));
985
986 let origin = Vec4::new(0.0, 0.0, 0.0, 1.0);
988 let transformed_origin = m4_again * origin;
989 assert!(approx_eq(transformed_origin.x, 0.0));
990 assert!(approx_eq(transformed_origin.y, 0.0));
991 assert!(approx_eq(transformed_origin.z, 0.0));
992 assert!(approx_eq(transformed_origin.w, 1.0));
993 }
994
995 #[test]
996 fn test_mat3_index() {
997 let mut m = Mat3::from_cols(Vec3::X, Vec3::Y, Vec3::Z);
998 assert_eq!(m[0], Vec3::X);
999 assert_eq!(m[1], Vec3::Y);
1000 assert_eq!(m[2], Vec3::Z);
1001 m[0] = Vec3::ONE;
1002 assert_eq!(m.cols[0], Vec3::ONE);
1003 }
1004
1005 #[test]
1006 #[should_panic]
1007 fn test_mat3_index_out_of_bounds() {
1008 let m = Mat3::IDENTITY;
1009 let _ = m[3]; }
1011
1012 #[test]
1017 fn test_identity() {
1018 assert_eq!(Mat4::default(), Mat4::IDENTITY);
1019 let m = Mat4::from_translation(Vec3::new(1.0, 2.0, 3.0));
1020 assert!(mat4_approx_eq(m * Mat4::IDENTITY, m));
1021 assert!(mat4_approx_eq(Mat4::IDENTITY * m, m));
1022 }
1023
1024 #[test]
1025 fn test_from_quat() {
1026 let axis = Vec3::new(1.0, 2.0, 3.0).normalize();
1027 let angle = PI / 5.0;
1028 let q = Quaternion::from_axis_angle(axis, angle);
1029 let m_from_q = Mat4::from_quat(q);
1030
1031 let v = Vec3::new(5.0, -1.0, 2.0);
1032
1033 let v_rotated_q = q * v; let v4 = Vec4::from_vec3(v, 1.0);
1036 let v_rotated_m4 = m_from_q * v4;
1037 let v_rotated_m = v_rotated_m4.truncate();
1038
1039 assert!(approx_eq(v_rotated_q.x, v_rotated_m.x));
1041 assert!(approx_eq(v_rotated_q.y, v_rotated_m.y));
1042 assert!(approx_eq(v_rotated_q.z, v_rotated_m.z));
1043 }
1044
1045 #[test]
1046 fn test_translation() {
1047 let t = Vec3::new(1.0, 2.0, 3.0);
1048 let m = Mat4::from_translation(t);
1049 let p = Vec4::new(1.0, 1.0, 1.0, 1.0);
1050 let expected_p = Vec4::new(2.0, 3.0, 4.0, 1.0);
1051
1052 assert!(vec4_approx_eq(m * p, expected_p));
1053 }
1054
1055 #[test]
1056 fn test_scale() {
1057 let s = Vec3::new(2.0, 3.0, 4.0);
1058 let m = Mat4::from_scale(s);
1059 let p = Vec4::new(1.0, 1.0, 1.0, 1.0);
1060 let expected_p = Vec4::new(2.0, 3.0, 4.0, 1.0);
1061 assert!(vec4_approx_eq(m * p, expected_p));
1062 }
1063
1064 #[test]
1065 fn test_rotation_x() {
1066 let angle = PI / 2.0; let m = Mat4::from_rotation_x(angle);
1068 let p = Vec4::new(0.0, 1.0, 0.0, 1.0); let expected_p = Vec4::new(0.0, 0.0, 1.0, 1.0); assert!(vec4_approx_eq(m * p, expected_p));
1071 }
1072
1073 #[test]
1074 fn test_rotation_y() {
1075 let angle = PI / 2.0; let m = Mat4::from_rotation_y(angle);
1077 let p = Vec4::new(1.0, 0.0, 0.0, 1.0); let expected_p = Vec4::new(0.0, 0.0, -1.0, 1.0); assert!(vec4_approx_eq(m * p, expected_p));
1081 }
1082
1083 #[test]
1084 fn test_rotation_z() {
1085 let angle = PI / 2.0; let m = Mat4::from_rotation_z(angle);
1087 let p = Vec4::new(1.0, 0.0, 0.0, 1.0); let expected_p = Vec4::new(0.0, 1.0, 0.0, 1.0); assert!(vec4_approx_eq(m * p, expected_p));
1090 }
1091
1092 #[test]
1093 fn test_transpose() {
1094 let m = Mat4::from_cols(
1095 Vec4::new(1., 2., 3., 4.),
1096 Vec4::new(5., 6., 7., 8.),
1097 Vec4::new(9., 10., 11., 12.),
1098 Vec4::new(13., 14., 15., 16.),
1099 );
1100 let mt = m.transpose();
1101 let expected_mt = Mat4::from_cols(
1102 Vec4::new(1., 5., 9., 13.),
1103 Vec4::new(2., 6., 10., 14.),
1104 Vec4::new(3., 7., 11., 15.),
1105 Vec4::new(4., 8., 12., 16.),
1106 );
1107 assert_eq!(mt.cols[0], expected_mt.cols[0]); assert_eq!(mt.cols[1], expected_mt.cols[1]);
1109 assert_eq!(mt.cols[2], expected_mt.cols[2]);
1110 assert_eq!(mt.cols[3], expected_mt.cols[3]);
1111
1112 assert!(mat4_approx_eq(m.transpose().transpose(), m));
1114 }
1115
1116 #[test]
1117 fn test_mul_mat4() {
1118 let t = Mat4::from_translation(Vec3::new(1.0, 0.0, 0.0));
1119 let r = Mat4::from_rotation_z(PI / 2.0);
1120
1121 let tr = r * t;
1123 let p = Vec4::new(1.0, 0.0, 0.0, 1.0); let expected_tr = Vec4::new(0.0, 2.0, 0.0, 1.0);
1127 assert!(vec4_approx_eq(tr * p, expected_tr));
1128
1129 let rt = t * r;
1131 let expected_rt = Vec4::new(1.0, 1.0, 0.0, 1.0);
1134 assert!(vec4_approx_eq(rt * p, expected_rt));
1135 }
1136
1137 #[test]
1138 fn test_inverse() {
1139 let m = Mat4::from_translation(Vec3::new(1., 2., 3.))
1140 * Mat4::from_rotation_y(PI / 4.0)
1141 * Mat4::from_scale(Vec3::new(1., 2., 1.));
1142
1143 let inv_m = m.inverse().expect("Matrix should be invertible");
1144 let identity = m * inv_m;
1145
1146 assert!(
1148 mat4_approx_eq(identity, Mat4::IDENTITY),
1149 "M * inv(M) should be Identity"
1150 );
1151
1152 let singular = Mat4::from_scale(Vec3::new(1.0, 0.0, 1.0));
1154 assert!(
1155 singular.inverse().is_none(),
1156 "Singular matrix inverse should be None"
1157 );
1158 }
1159
1160 #[test]
1161 fn test_affine_inverse() {
1162 let t = Mat4::from_translation(Vec3::new(1., 2., 3.));
1163 let r = Mat4::from_rotation_y(PI / 3.0);
1164 let s = Mat4::from_scale(Vec3::new(1., 2., 0.5));
1165 let m = t * r * s; let inv_m = m.inverse().expect("Matrix should be invertible");
1168 let affine_inv_m = m
1169 .affine_inverse()
1170 .expect("Matrix should be affine invertible");
1171
1172 assert!(
1174 mat4_approx_eq(inv_m, affine_inv_m),
1175 "Affine inverse should match general inverse"
1176 );
1177
1178 let identity = m * affine_inv_m;
1180 assert!(
1181 mat4_approx_eq(identity, Mat4::IDENTITY),
1182 "M * affine_inv(M) should be Identity"
1183 );
1184
1185 let singular_s = Mat4::from_scale(Vec3::new(1.0, 0.0, 1.0));
1187 let singular_m = t * singular_s;
1188 assert!(
1189 singular_m.affine_inverse().is_none(),
1190 "Singular affine matrix inverse should be None"
1191 );
1192 }
1193
1194 #[test]
1195 fn test_perspective_rh_zo() {
1196 let fov = PI / 4.0; let aspect = 16.0 / 9.0;
1198 let near = 0.1;
1199 let far = 100.0;
1200
1201 let m = Mat4::perspective_rh_zo(fov, aspect, near, far);
1202 assert!(approx_eq(m.cols[0].x, 1.0 / (aspect * (fov / 2.0).tan())));
1203 assert!(approx_eq(m.cols[1].y, 1.0 / ((fov / 2.0).tan())));
1204 assert!(approx_eq(m.cols[2].z, -far / (far - near)));
1205 assert!(approx_eq(m.cols[3].z, -(far * near) / (far - near)));
1206 }
1207
1208 #[test]
1209 fn test_orthographic_rh_zo() {
1210 let left = -1.0;
1211 let right = 1.0;
1212 let bottom = -1.0;
1213 let top = 1.0;
1214 let near = 0.1;
1215 let far = 100.0;
1216 let m = Mat4::orthographic_rh_zo(left, right, bottom, top, near, far);
1217
1218 assert!(approx_eq(m.cols[0].x, 2.0 / (right - left)));
1220 assert!(approx_eq(m.cols[1].y, 2.0 / (top - bottom)));
1221 assert!(approx_eq(m.cols[2].z, -1.0 / (far - near)));
1222
1223 assert!(approx_eq(m.cols[3].x, -(right + left) / (right - left)));
1225 assert!(approx_eq(m.cols[3].y, -(top + bottom) / (top - bottom)));
1226 assert!(approx_eq(m.cols[3].z, -near / (far - near))); }
1228
1229 #[test]
1230 fn test_look_at_rh() {
1231 let eye = Vec3::new(0.0, 0.0, 5.0);
1232 let target = Vec3::new(0.0, 0.0, 0.0);
1233 let up = Vec3::new(0.0, 1.0, 0.0);
1234
1235 let m = Mat4::look_at_rh(eye, target, up).expect("look_at_rh should return Some(Mat4)");
1236
1237 assert!(approx_eq(m.cols[2].z, 1.0));
1239
1240 assert!(approx_eq(m.cols[3].z, -5.0));
1242 }
1243
1244 #[test]
1245 fn test_look_at_rh_invalid() {
1246 let eye = Vec3::new(0.0, 0.0, 5.0);
1247 let target = Vec3::new(0.0, 0.0, 5.0); let up = Vec3::new(0.0, 1.0, 0.0);
1249
1250 assert!(Mat4::look_at_rh(eye, target, up).is_none());
1252 }
1253
1254 }