glam_matrix_extras/symmetric/
symmetric_mat4.rs

1use core::iter::Sum;
2use core::ops::*;
3#[cfg(feature = "f64")]
4use glam::{DMat4, DVec4};
5use glam::{Mat4, Vec4};
6
7#[cfg(feature = "bevy_reflect")]
8use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize, std_traits::ReflectDefault};
9
10use crate::{MatConversionError, SquareMatExt, ops::FloatAbs};
11
12/// An extension trait for 4x4 matrices.
13pub trait Mat4Ext {
14    /// The type of the symmetric 4x4 matrix.
15    type SymmetricMat4;
16
17    /// Multiplies `self` by a symmetric 4x4 matrix.
18    fn mul_symmetric_mat4(&self, rhs: &Self::SymmetricMat4) -> Self;
19
20    /// Adds a symmetric 4x4 matrix to `self`.
21    fn add_symmetric_mat4(&self, rhs: &Self::SymmetricMat4) -> Self;
22
23    /// Subtracts a symmetric 4x4 matrix from `self`.
24    fn sub_symmetric_mat4(&self, rhs: &Self::SymmetricMat4) -> Self;
25}
26
27#[cfg(feature = "f32")]
28impl Mat4Ext for Mat4 {
29    type SymmetricMat4 = SymmetricMat4;
30
31    #[inline]
32    fn mul_symmetric_mat4(&self, rhs: &SymmetricMat4) -> Mat4 {
33        self.mul(rhs)
34    }
35
36    #[inline]
37    fn add_symmetric_mat4(&self, rhs: &SymmetricMat4) -> Mat4 {
38        self.add(rhs)
39    }
40
41    #[inline]
42    fn sub_symmetric_mat4(&self, rhs: &SymmetricMat4) -> Mat4 {
43        self.sub(rhs)
44    }
45}
46
47#[cfg(feature = "f64")]
48impl Mat4Ext for DMat4 {
49    type SymmetricMat4 = SymmetricDMat4;
50
51    #[inline]
52    fn mul_symmetric_mat4(&self, rhs: &SymmetricDMat4) -> DMat4 {
53        self.mul(rhs)
54    }
55
56    #[inline]
57    fn add_symmetric_mat4(&self, rhs: &SymmetricDMat4) -> DMat4 {
58        self.add(rhs)
59    }
60
61    #[inline]
62    fn sub_symmetric_mat4(&self, rhs: &SymmetricDMat4) -> DMat4 {
63        self.sub(rhs)
64    }
65}
66
67macro_rules! symmetric_mat4s {
68    ($($n:ident => $nonsymmetricn:ident, $vt:ident, $t:ident),+) => {
69        $(
70        /// The bottom left triangle (including the diagonal) of a symmetric 4x4 column-major matrix.
71        ///
72        /// This is useful for storing a symmetric 4x4 matrix in a more compact form and performing some
73        /// matrix operations more efficiently.
74        ///
75        /// Some defining properties of symmetric matrices include:
76        ///
77        /// - The matrix is equal to its transpose.
78        /// - The matrix has real eigenvalues.
79        /// - The eigenvectors corresponding to the eigenvalues are orthogonal.
80        /// - The matrix is always diagonalizable.
81        ///
82        /// The sum and difference of two symmetric matrices is always symmetric.
83        /// However, the product of two symmetric matrices is *only* symmetric
84        /// if the matrices are commutable, meaning that `AB = BA`.
85        #[derive(Clone, Copy, PartialEq)]
86        #[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
87        #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
88        #[cfg_attr(
89            all(feature = "bevy_reflect", feature = "serde"),
90            reflect(Debug, Default, PartialEq, Serialize, Deserialize)
91        )]
92        pub struct $n {
93            /// The first element of the first column.
94            pub m00: $t,
95            /// The second element of the first column.
96            pub m01: $t,
97            /// The third element of the first column.
98            pub m02: $t,
99            /// The fourth element of the first column.
100            pub m03: $t,
101            /// The second element of the second column.
102            pub m11: $t,
103            /// The third element of the second column.
104            pub m12: $t,
105            /// The fourth element of the second column.
106            pub m13: $t,
107            /// The third element of the third column.
108            pub m22: $t,
109            /// The fourth element of the third column.
110            pub m23: $t,
111            /// The fourth element of the fourth column.
112            pub m33: $t,
113        }
114
115        impl $n {
116            /// A symmetric 4x4 matrix with all elements set to `0.0`.
117            pub const ZERO: Self = Self::new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
118
119            /// A symmetric 4x4 identity matrix, where all diagonal elements are `1.0`,
120            /// and all off-diagonal elements are `0.0`.
121            pub const IDENTITY: Self = Self::new(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0);
122
123            /// All NaNs.
124            pub const NAN: Self = Self::new(
125                $t::NAN,
126                $t::NAN,
127                $t::NAN,
128                $t::NAN,
129                $t::NAN,
130                $t::NAN,
131                $t::NAN,
132                $t::NAN,
133                $t::NAN,
134                $t::NAN,
135            );
136
137            /// Creates a new symmetric 4x4 matrix from its bottom left triangle, including diagonal elements.
138            ///
139            /// The elements are in column-major order `mCR`, where `C` is the column index
140            /// and `R` is the row index.
141            #[inline(always)]
142            #[must_use]
143            #[expect(clippy::too_many_arguments, reason = "It's important to have a raw constructor for this.")]
144            pub const fn new(
145                m00: $t,
146                m01: $t,
147                m02: $t,
148                m03: $t,
149                m11: $t,
150                m12: $t,
151                m13: $t,
152                m22: $t,
153                m23: $t,
154                m33: $t,
155            ) -> Self {
156                Self {
157                    m00,
158                    m01,
159                    m02,
160                    m03,
161                    m11,
162                    m12,
163                    m13,
164                    m22,
165                    m23,
166                    m33,
167                }
168            }
169
170            /// Creates a symmetric 4x4 matrix from four column vectors.
171            ///
172            /// Only the lower left triangle of the matrix is used. No check is performed to ensure
173            /// that the given columns truly produce a symmetric matrix.
174            #[inline(always)]
175            #[must_use]
176            pub fn from_cols_unchecked(x_axis: $vt, y_axis: $vt, z_axis: $vt, w_axis: $vt) -> Self {
177                Self {
178                    m00: x_axis.x,
179                    m01: x_axis.y,
180                    m02: x_axis.z,
181                    m03: w_axis.x,
182                    m11: y_axis.y,
183                    m12: y_axis.z,
184                    m13: w_axis.y,
185                    m22: z_axis.z,
186                    m23: w_axis.z,
187                    m33: w_axis.w,
188                }
189            }
190
191            /// Creates a symmetric 4x4 matrix from an array stored in column major order.
192            ///
193            /// Only the lower left triangle of the matrix is used. No check is performed to ensure
194            /// that the given columns truly produce a symmetric matrix.
195            #[inline]
196            #[must_use]
197            pub const fn from_cols_array_unchecked(m: &[$t; 16]) -> Self {
198                Self::new(m[0], m[1], m[2], m[3], m[5], m[6], m[7], m[10], m[11], m[15])
199            }
200
201            /// Creates an array storing data in column major order.
202            #[inline]
203            #[must_use]
204            pub const fn to_cols_array(&self) -> [$t; 16] {
205                [
206                    self.m00, self.m01, self.m02, self.m03,
207                    self.m01, self.m11, self.m12, self.m13,
208                    self.m02, self.m12, self.m22, self.m23,
209                    self.m03, self.m13, self.m23, self.m33,
210                ]
211            }
212
213            /// Creates a symmetric 4x4 matrix from a 2D array stored in column major order.
214            ///
215            /// Only the lower left triangle of the matrix is used. No check is performed to ensure
216            /// that the given columns truly produce a symmetric matrix.
217            #[inline]
218            #[must_use]
219            pub fn from_cols_array_2d_unchecked(m: &[[$t; 4]; 4]) -> Self {
220                Self::from_cols_unchecked(
221                    $vt::from_array(m[0]),
222                    $vt::from_array(m[1]),
223                    $vt::from_array(m[2]),
224                    $vt::from_array(m[3]),
225                )
226            }
227
228            /// Creates a 2D array storing data in column major order.
229            #[inline]
230            #[must_use]
231            pub const fn to_cols_array_2d(&self) -> [[$t; 4]; 4] {
232                [
233                    [self.m00, self.m01, self.m02, self.m03],
234                    [self.m01, self.m11, self.m12, self.m13],
235                    [self.m02, self.m12, self.m22, self.m23],
236                    [self.m03, self.m13, self.m23, self.m33],
237                ]
238            }
239
240            /// Creates a 4x4 matrix from the first 16 values in `slice`.
241            ///
242            /// Only the lower left triangle of the matrix is used. No check is performed to ensure
243            /// that the given columns truly produce a symmetric matrix.
244            ///
245            /// # Panics
246            ///
247            /// Panics if `slice` is less than 16 elements long.
248            #[inline]
249            #[must_use]
250            pub const fn from_cols_slice(slice: &[$t]) -> Self {
251                Self::new(
252                    slice[0],
253                    slice[1],
254                    slice[2],
255                    slice[3],
256                    slice[5],
257                    slice[6],
258                    slice[7],
259                    slice[10],
260                    slice[11],
261                    slice[15],
262                )
263            }
264
265            /// Creates a symmetric 4x4 matrix with its diagonal set to `diagonal` and all other entries set to `0.0`.
266            #[inline]
267            #[must_use]
268            #[doc(alias = "scale")]
269            pub fn from_diagonal(diagonal: $vt) -> Self {
270                Self::new(
271                    diagonal.x,
272                    0.0,
273                    0.0,
274                    0.0,
275                    diagonal.y,
276                    0.0,
277                    0.0,
278                    diagonal.z,
279                    0.0,
280                    diagonal.w,
281                )
282            }
283
284            /// Tries to create a symmetric 4x4 matrix from a 4x4 matrix.
285            ///
286            /// # Errors
287            ///
288            /// Returns a [`MatConversionError`] if the given matrix is not symmetric.
289            #[inline]
290            pub fn try_from_mat4(mat: $nonsymmetricn) -> Result<Self, MatConversionError> {
291                if mat.is_symmetric() {
292                    Ok(Self::from_mat4_unchecked(mat))
293                } else {
294                    Err(MatConversionError::Asymmetric)
295                }
296            }
297
298            /// Creates a symmetric 4x4 matrix from a 4x4 matrix.
299            ///
300            /// Only the lower left triangle of the matrix is used. No check is performed to ensure
301            /// that the given matrix is truly symmetric.
302            #[inline]
303            #[must_use]
304            pub fn from_mat4_unchecked(mat: $nonsymmetricn) -> Self {
305                Self::new(
306                    mat.x_axis.x,
307                    mat.x_axis.y,
308                    mat.x_axis.z,
309                    mat.x_axis.w,
310                    mat.y_axis.y,
311                    mat.y_axis.z,
312                    mat.y_axis.w,
313                    mat.z_axis.z,
314                    mat.z_axis.w,
315                    mat.w_axis.w,
316                )
317            }
318
319            /// Creates a 4x4 matrix from the symmetric 4x4 matrix in `self`.
320            #[inline]
321            #[must_use]
322            pub const fn to_mat4(&self) -> $nonsymmetricn {
323                $nonsymmetricn::from_cols_array(&self.to_cols_array())
324            }
325
326            /// Creates a new symmetric 4x4 matrix from the outer product `v * v^T`.
327            #[inline(always)]
328            #[must_use]
329            pub fn from_outer_product(v: $vt) -> Self {
330                Self::new(
331                    v.x * v.x,
332                    v.x * v.y,
333                    v.x * v.z,
334                    v.x * v.w,
335                    v.y * v.y,
336                    v.y * v.z,
337                    v.y * v.w,
338                    v.z * v.z,
339                    v.z * v.w,
340                    v.w * v.w,
341                )
342            }
343
344            /// Returns the matrix column for the given `index`.
345            ///
346            /// # Panics
347            ///
348            /// Panics if `index` is greater than 3.
349            #[inline]
350            #[must_use]
351            pub const fn col(&self, index: usize) -> $vt {
352                match index {
353                    0 => $vt::new(self.m00, self.m01, self.m02, self.m03),
354                    1 => $vt::new(self.m01, self.m11, self.m12, self.m13),
355                    2 => $vt::new(self.m02, self.m12, self.m22, self.m23),
356                    3 => $vt::new(self.m03, self.m13, self.m23, self.m33),
357                    _ => panic!("index out of bounds"),
358                }
359            }
360
361            /// Returns the matrix row for the given `index`.
362            ///
363            /// # Panics
364            ///
365            /// Panics if `index` is greater than 3.
366            #[inline]
367            #[must_use]
368            pub const fn row(&self, index: usize) -> $vt {
369                match index {
370                    0 => $vt::new(self.m00, self.m01, self.m02, self.m03),
371                    1 => $vt::new(self.m01, self.m11, self.m12, self.m13),
372                    2 => $vt::new(self.m02, self.m12, self.m22, self.m23),
373                    3 => $vt::new(self.m03, self.m13, self.m23, self.m33),
374                    _ => panic!("index out of bounds"),
375                }
376            }
377
378            /// Returns the diagonal of the matrix.
379            #[inline]
380            #[must_use]
381            pub fn diagonal(&self) -> $vt {
382                $vt::new(self.m00, self.m11, self.m22, self.m33)
383            }
384
385            /// Returns `true` if, and only if, all elements are finite.
386            /// If any element is either `NaN` or positive or negative infinity, this will return `false`.
387            #[inline]
388            #[must_use]
389            pub fn is_finite(&self) -> bool {
390                self.m00.is_finite()
391                    && self.m01.is_finite()
392                    && self.m02.is_finite()
393                    && self.m03.is_finite()
394                    && self.m11.is_finite()
395                    && self.m12.is_finite()
396                    && self.m13.is_finite()
397                    && self.m22.is_finite()
398                    && self.m23.is_finite()
399                    && self.m33.is_finite()
400            }
401
402            /// Returns `true` if any elements are `NaN`.
403            #[inline]
404            #[must_use]
405            pub fn is_nan(&self) -> bool {
406                self.m00.is_nan()
407                    || self.m01.is_nan()
408                    || self.m02.is_nan()
409                    || self.m03.is_nan()
410                    || self.m11.is_nan()
411                    || self.m12.is_nan()
412                    || self.m13.is_nan()
413                    || self.m22.is_nan()
414                    || self.m23.is_nan()
415                    || self.m33.is_nan()
416            }
417
418            /// Returns the determinant of `self`.
419            #[inline]
420            #[must_use]
421            pub fn determinant(&self) -> $t {
422                // Reference: Symmetric4x4Wide in Bepu
423                // https://github.com/bepu/bepuphysics2/blob/1d1aead82c493c22793bc02a233a6dcd08b57bd6/BepuUtilities/Symmetric4x4Wide.cs#L62
424
425                // TODO: This probably isn't as optimized as it could be.
426                let s0 = self.m00 * self.m11 - self.m01 * self.m01;
427                let s1 = self.m00 * self.m12 - self.m01 * self.m02;
428                let s2 = self.m00 * self.m13 - self.m01 * self.m03;
429                let s3 = self.m01 * self.m12 - self.m11 * self.m02;
430                let s4 = self.m01 * self.m13 - self.m11 * self.m03;
431                let s5 = self.m02 * self.m13 - self.m12 * self.m03;
432                let c5 = self.m22 * self.m33 - self.m23 * self.m23;
433                let c4 = self.m12 * self.m33 - self.m13 * self.m23;
434                let c3 = self.m12 * self.m23 - self.m13 * self.m22;
435                let c2 = self.m02 * self.m33 - self.m03 * self.m23;
436                let c1 = self.m02 * self.m23 - self.m03 * self.m22;
437                // let c0 = s5;
438
439                s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * s5
440            }
441
442            /// Returns the inverse of `self`.
443            ///
444            /// If the matrix is not invertible the returned matrix will be invalid.
445            #[inline]
446            #[must_use]
447            pub fn inverse(&self) -> Self {
448                // Reference: Symmetric4x4Wide in Bepu
449                // https://github.com/bepu/bepuphysics2/blob/1d1aead82c493c22793bc02a233a6dcd08b57bd6/BepuUtilities/Symmetric4x4Wide.cs#L62
450
451                let s0 = self.m00 * self.m11 - self.m01 * self.m01;
452                let s1 = self.m00 * self.m12 - self.m01 * self.m02;
453                let s2 = self.m00 * self.m13 - self.m01 * self.m03;
454                let s3 = self.m01 * self.m12 - self.m11 * self.m02;
455                let s4 = self.m01 * self.m13 - self.m11 * self.m03;
456                let s5 = self.m02 * self.m13 - self.m12 * self.m03;
457                let c5 = self.m22 * self.m33 - self.m23 * self.m23;
458                let c4 = self.m12 * self.m33 - self.m13 * self.m23;
459                let c3 = self.m12 * self.m23 - self.m13 * self.m22;
460                let c2 = self.m02 * self.m33 - self.m03 * self.m23;
461                let c1 = self.m02 * self.m23 - self.m03 * self.m22;
462                // let c0 = s5;
463
464                let inverse_determinant = 1.0 / (s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * s5);
465
466                let m00 = self.m11 * c5 - self.m12 * c4 + self.m13 * c3;
467                let m01 = -self.m01 * c5 + self.m12 * c2 - self.m13 * c1;
468                let m02 = self.m01 * c4 - self.m11 * c2 + self.m13 * s5;
469                let m03 = -self.m01 * c3 + self.m11 * c1 - self.m12 * s5;
470                let m11 = self.m00 * c5 - self.m02 * c2 + self.m03 * c1;
471                let m12 = -self.m00 * c4 + self.m01 * c2 - self.m03 * s5;
472                let m13 = self.m00 * c3 - self.m01 * c1 + self.m02 * s5;
473                let m22 = self.m03 * s4 - self.m13 * s2 + self.m33 * s0;
474                let m23 = -self.m03 * s3 + self.m13 * s1 - self.m23 * s0;
475                let m33 = self.m02 * s3 - self.m12 * s1 + self.m22 * s0;
476
477                Self {
478                    m00: m00 * inverse_determinant,
479                    m01: m01 * inverse_determinant,
480                    m02: m02 * inverse_determinant,
481                    m03: m03 * inverse_determinant,
482                    m11: m11 * inverse_determinant,
483                    m12: m12 * inverse_determinant,
484                    m13: m13 * inverse_determinant,
485                    m22: m22 * inverse_determinant,
486                    m23: m23 * inverse_determinant,
487                    m33: m33 * inverse_determinant,
488                }
489            }
490
491            /// Returns the inverse of `self`, or a zero matrix if the matrix is not invertible.
492            #[inline]
493            #[must_use]
494            pub fn inverse_or_zero(&self) -> Self {
495                // Reference: Symmetric4x4Wide in Bepu
496                // https://github.com/bepu/bepuphysics2/blob/1d1aead82c493c22793bc02a233a6dcd08b57bd6/BepuUtilities/Symmetric4x4Wide.cs#L62
497
498                let s0 = self.m00 * self.m11 - self.m01 * self.m01;
499                let s1 = self.m00 * self.m12 - self.m01 * self.m02;
500                let s2 = self.m00 * self.m13 - self.m01 * self.m03;
501                let s3 = self.m01 * self.m12 - self.m11 * self.m02;
502                let s4 = self.m01 * self.m13 - self.m11 * self.m03;
503                let s5 = self.m02 * self.m13 - self.m12 * self.m03;
504                let c5 = self.m22 * self.m33 - self.m23 * self.m23;
505                let c4 = self.m12 * self.m33 - self.m13 * self.m23;
506                let c3 = self.m12 * self.m23 - self.m13 * self.m22;
507                let c2 = self.m02 * self.m33 - self.m03 * self.m23;
508                let c1 = self.m02 * self.m23 - self.m03 * self.m22;
509                // let c0 = s5;
510
511                let determinant = s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * s5;
512
513                if determinant == 0.0 {
514                    return Self::ZERO;
515                }
516
517                let inverse_determinant = 1.0 / determinant;
518
519                let m00 = self.m11 * c5 - self.m12 * c4 + self.m13 * c3;
520                let m01 = -self.m01 * c5 + self.m12 * c2 - self.m13 * c1;
521                let m02 = self.m01 * c4 - self.m11 * c2 + self.m13 * s5;
522                let m03 = -self.m01 * c3 + self.m11 * c1 - self.m12 * s5;
523                let m11 = self.m00 * c5 - self.m02 * c2 + self.m03 * c1;
524                let m12 = -self.m00 * c4 + self.m01 * c2 - self.m03 * s5;
525                let m13 = self.m00 * c3 - self.m01 * c1 + self.m02 * s5;
526                let m22 = self.m03 * s4 - self.m13 * s2 + self.m33 * s0;
527                let m23 = -self.m03 * s3 + self.m13 * s1 - self.m23 * s0;
528                let m33 = self.m02 * s3 - self.m12 * s1 + self.m22 * s0;
529
530                Self {
531                    m00: m00 * inverse_determinant,
532                    m01: m01 * inverse_determinant,
533                    m02: m02 * inverse_determinant,
534                    m03: m03 * inverse_determinant,
535                    m11: m11 * inverse_determinant,
536                    m12: m12 * inverse_determinant,
537                    m13: m13 * inverse_determinant,
538                    m22: m22 * inverse_determinant,
539                    m23: m23 * inverse_determinant,
540                    m33: m33 * inverse_determinant,
541                }
542            }
543
544            /// Takes the absolute value of each element in `self`.
545            #[inline]
546            #[must_use]
547            pub fn abs(&self) -> Self {
548                Self::new(
549                    FloatAbs::abs(self.m00),
550                    FloatAbs::abs(self.m01),
551                    FloatAbs::abs(self.m02),
552                    FloatAbs::abs(self.m03),
553                    FloatAbs::abs(self.m11),
554                    FloatAbs::abs(self.m12),
555                    FloatAbs::abs(self.m13),
556                    FloatAbs::abs(self.m22),
557                    FloatAbs::abs(self.m23),
558                    FloatAbs::abs(self.m33),
559                )
560            }
561
562            /// Transforms a 4D vector.
563            #[inline]
564            #[must_use]
565            pub fn mul_vec4(&self, rhs: $vt) -> $vt {
566                let mut res = self.col(0).mul(rhs.x);
567                res = res.add(self.col(1).mul(rhs.y));
568                res = res.add(self.col(2).mul(rhs.z));
569                res = res.add(self.col(3).mul(rhs.w));
570                res
571            }
572
573            /// Multiplies two 4x4 matrices.
574            #[inline]
575            #[must_use]
576            pub fn mul_mat4(&self, rhs: &$nonsymmetricn) -> $nonsymmetricn {
577                self.mul(rhs)
578            }
579
580            /// Adds two 4x4 matrices.
581            #[inline]
582            #[must_use]
583            pub fn add_mat4(&self, rhs: &$nonsymmetricn) -> $nonsymmetricn {
584                self.add(rhs)
585            }
586
587            /// Subtracts two 4x4 matrices.
588            #[inline]
589            #[must_use]
590            pub fn sub_mat4(&self, rhs: &$nonsymmetricn) -> $nonsymmetricn {
591                self.sub(rhs)
592            }
593
594            /// Multiplies two symmetric 4x4 matrices.
595            #[inline]
596            #[must_use]
597            pub fn mul_symmetric_mat4(&self, rhs: &Self) -> $nonsymmetricn {
598                self.mul(rhs)
599            }
600
601            /// Adds two symmetric 4x4 matrices.
602            #[inline]
603            #[must_use]
604            pub fn add_symmetric_mat4(&self, rhs: &Self) -> Self {
605                self.add(rhs)
606            }
607
608            /// Subtracts two symmetric 4x4 matrices.
609            #[inline]
610            #[must_use]
611            pub fn sub_symmetric_mat4(&self, rhs: &Self) -> Self {
612                self.sub(rhs)
613            }
614
615            /// Multiplies a 4x4 matrix by a scalar.
616            #[inline]
617            #[must_use]
618            pub fn mul_scalar(&self, rhs: $t) -> Self {
619                Self::new(
620                    self.m00 * rhs,
621                    self.m01 * rhs,
622                    self.m02 * rhs,
623                    self.m03 * rhs,
624                    self.m11 * rhs,
625                    self.m12 * rhs,
626                    self.m13 * rhs,
627                    self.m22 * rhs,
628                    self.m23 * rhs,
629                    self.m33 * rhs,
630                )
631            }
632
633            /// Divides a 4x4 matrix by a scalar.
634            #[inline]
635            #[must_use]
636            pub fn div_scalar(&self, rhs: $t) -> Self {
637                Self::new(
638                    self.m00 / rhs,
639                    self.m01 / rhs,
640                    self.m02 / rhs,
641                    self.m03 / rhs,
642                    self.m11 / rhs,
643                    self.m12 / rhs,
644                    self.m13 / rhs,
645                    self.m22 / rhs,
646                    self.m23 / rhs,
647                    self.m33 / rhs,
648                )
649            }
650        }
651
652        impl Default for $n {
653            #[inline(always)]
654            fn default() -> Self {
655                Self::IDENTITY
656            }
657        }
658
659        impl TryFrom<$nonsymmetricn> for $n {
660            type Error = MatConversionError;
661
662            #[inline]
663            fn try_from(mat: $nonsymmetricn) -> Result<Self, Self::Error> {
664                Self::try_from_mat4(mat)
665            }
666        }
667
668        impl Add for $n {
669            type Output = Self;
670            #[inline]
671            fn add(self, rhs: Self) -> Self::Output {
672                Self::new(
673                    self.m00 + rhs.m00,
674                    self.m01 + rhs.m01,
675                    self.m02 + rhs.m02,
676                    self.m03 + rhs.m03,
677                    self.m11 + rhs.m11,
678                    self.m12 + rhs.m12,
679                    self.m13 + rhs.m13,
680                    self.m22 + rhs.m22,
681                    self.m23 + rhs.m23,
682                    self.m33 + rhs.m33,
683                )
684            }
685        }
686
687        impl Add<&Self> for $n {
688            type Output = Self;
689            #[inline]
690            fn add(self, rhs: &Self) -> Self::Output {
691                self.add(*rhs)
692            }
693        }
694
695        impl Add<Self> for &$n {
696            type Output = $n;
697            #[inline]
698            fn add(self, rhs: Self) -> Self::Output {
699                (*self).add(rhs)
700            }
701        }
702
703        impl Add<&Self> for &$n {
704            type Output = $n;
705            #[inline]
706            fn add(self, rhs: &Self) -> Self::Output {
707                (*self).add(*rhs)
708            }
709        }
710
711        impl AddAssign for $n {
712            #[inline]
713            fn add_assign(&mut self, rhs: Self) {
714                *self = self.add(rhs);
715            }
716        }
717
718        impl AddAssign<&Self> for $n {
719            #[inline]
720            fn add_assign(&mut self, rhs: &Self) {
721                self.add_assign(*rhs);
722            }
723        }
724
725        impl Add<$nonsymmetricn> for $n {
726            type Output = $nonsymmetricn;
727            #[inline]
728            fn add(self, rhs: $nonsymmetricn) -> Self::Output {
729                $nonsymmetricn::from_cols(
730                    self.col(0).add(rhs.x_axis),
731                    self.col(1).add(rhs.y_axis),
732                    self.col(2).add(rhs.z_axis),
733                    self.col(3).add(rhs.w_axis),
734                )
735            }
736        }
737
738        impl Add<&$nonsymmetricn> for $n {
739            type Output = $nonsymmetricn;
740            #[inline]
741            fn add(self, rhs: &$nonsymmetricn) -> Self::Output {
742                self.add(*rhs)
743            }
744        }
745
746        impl Add<$nonsymmetricn> for &$n {
747            type Output = $nonsymmetricn;
748            #[inline]
749            fn add(self, rhs: $nonsymmetricn) -> Self::Output {
750                (*self).add(rhs)
751            }
752        }
753
754        impl Add<&$nonsymmetricn> for &$n {
755            type Output = $nonsymmetricn;
756            #[inline]
757            fn add(self, rhs: &$nonsymmetricn) -> Self::Output {
758                (*self).add(*rhs)
759            }
760        }
761
762        impl Add<$n> for $nonsymmetricn {
763            type Output = $nonsymmetricn;
764            #[inline]
765            fn add(self, rhs: $n) -> Self::Output {
766                rhs.add(&self)
767            }
768        }
769
770        impl Add<&$n> for $nonsymmetricn {
771            type Output = $nonsymmetricn;
772            #[inline]
773            fn add(self, rhs: &$n) -> Self::Output {
774                self.add(*rhs)
775            }
776        }
777
778        impl Add<&$n> for &$nonsymmetricn {
779            type Output = $nonsymmetricn;
780            #[inline]
781            fn add(self, rhs: &$n) -> Self::Output {
782                (*self).add(*rhs)
783            }
784        }
785
786        impl AddAssign<$n> for $nonsymmetricn {
787            #[inline]
788            fn add_assign(&mut self, rhs: $n) {
789                *self = self.add(rhs);
790            }
791        }
792
793        impl AddAssign<&$n> for $nonsymmetricn {
794            #[inline]
795            fn add_assign(&mut self, rhs: &$n) {
796                *self = self.add(*rhs);
797            }
798        }
799
800        impl Sub for $n {
801            type Output = Self;
802            #[inline]
803            fn sub(self, rhs: Self) -> Self::Output {
804                Self::new(
805                    self.m00 - rhs.m00,
806                    self.m01 - rhs.m01,
807                    self.m02 - rhs.m02,
808                    self.m03 - rhs.m03,
809                    self.m11 - rhs.m11,
810                    self.m12 - rhs.m12,
811                    self.m13 - rhs.m13,
812                    self.m22 - rhs.m22,
813                    self.m23 - rhs.m23,
814                    self.m33 - rhs.m33,
815                )
816            }
817        }
818
819        impl Sub<&Self> for $n {
820            type Output = Self;
821            #[inline]
822            fn sub(self, rhs: &Self) -> Self::Output {
823                self.sub(*rhs)
824            }
825        }
826
827        impl Sub<Self> for &$n {
828            type Output = $n;
829            #[inline]
830            fn sub(self, rhs: Self) -> Self::Output {
831                (*self).sub(rhs)
832            }
833        }
834
835        impl Sub<&Self> for &$n {
836            type Output = $n;
837            #[inline]
838            fn sub(self, rhs: &Self) -> Self::Output {
839                (*self).sub(*rhs)
840            }
841        }
842
843        impl SubAssign for $n {
844            #[inline]
845            fn sub_assign(&mut self, rhs: Self) {
846                *self = self.sub(rhs);
847            }
848        }
849
850        impl SubAssign<&Self> for $n {
851            #[inline]
852            fn sub_assign(&mut self, rhs: &Self) {
853                self.sub_assign(*rhs);
854            }
855        }
856
857        impl Sub<$nonsymmetricn> for $n {
858            type Output = $nonsymmetricn;
859            #[inline]
860            fn sub(self, rhs: $nonsymmetricn) -> Self::Output {
861                $nonsymmetricn::from_cols(
862                    self.col(0).sub(rhs.x_axis),
863                    self.col(1).sub(rhs.y_axis),
864                    self.col(2).sub(rhs.z_axis),
865                    self.col(3).sub(rhs.w_axis),
866                )
867            }
868        }
869
870        impl Sub<&$nonsymmetricn> for $n {
871            type Output = $nonsymmetricn;
872            #[inline]
873            fn sub(self, rhs: &$nonsymmetricn) -> Self::Output {
874                self.sub(*rhs)
875            }
876        }
877
878        impl Sub<$nonsymmetricn> for &$n {
879            type Output = $nonsymmetricn;
880            #[inline]
881            fn sub(self, rhs: $nonsymmetricn) -> Self::Output {
882                (*self).sub(rhs)
883            }
884        }
885
886        impl Sub<&$nonsymmetricn> for &$n {
887            type Output = $nonsymmetricn;
888            #[inline]
889            fn sub(self, rhs: &$nonsymmetricn) -> Self::Output {
890                (*self).sub(*rhs)
891            }
892        }
893
894        impl Sub<$n> for $nonsymmetricn {
895            type Output = $nonsymmetricn;
896            #[inline]
897            fn sub(self, rhs: $n) -> Self::Output {
898                rhs.sub(&self)
899            }
900        }
901
902        impl Sub<&$n> for $nonsymmetricn {
903            type Output = $nonsymmetricn;
904            #[inline]
905            fn sub(self, rhs: &$n) -> Self::Output {
906                self.sub(*rhs)
907            }
908        }
909
910        impl Sub<&$n> for &$nonsymmetricn {
911            type Output = $nonsymmetricn;
912            #[inline]
913            fn sub(self, rhs: &$n) -> Self::Output {
914                (*self).sub(*rhs)
915            }
916        }
917
918        impl SubAssign<$n> for $nonsymmetricn {
919            #[inline]
920            fn sub_assign(&mut self, rhs: $n) {
921                *self = self.sub(rhs);
922            }
923        }
924
925        impl SubAssign<&$n> for $nonsymmetricn {
926            #[inline]
927            fn sub_assign(&mut self, rhs: &$n) {
928                *self = self.sub(*rhs);
929            }
930        }
931
932        impl Neg for $n {
933            type Output = Self;
934            #[inline]
935            fn neg(self) -> Self::Output {
936                Self::new(
937                    -self.m00,
938                    -self.m01,
939                    -self.m02,
940                    -self.m03,
941                    -self.m11,
942                    -self.m12,
943                    -self.m13,
944                    -self.m22,
945                    -self.m23,
946                    -self.m33,
947                )
948            }
949        }
950
951        impl Neg for &$n {
952            type Output = $n;
953            #[inline]
954            fn neg(self) -> Self::Output {
955                (*self).neg()
956            }
957        }
958
959        impl Mul for $n {
960            type Output = $nonsymmetricn;
961            #[inline]
962            fn mul(self, rhs: Self) -> Self::Output {
963                $nonsymmetricn::from_cols(
964                    self.mul(rhs.col(0)),
965                    self.mul(rhs.col(1)),
966                    self.mul(rhs.col(2)),
967                    self.mul(rhs.col(3)),
968                )
969            }
970        }
971
972        impl Mul<&Self> for $n {
973            type Output = $nonsymmetricn;
974            #[inline]
975            fn mul(self, rhs: &Self) -> Self::Output {
976                self.mul(*rhs)
977            }
978        }
979
980        impl Mul<Self> for &$n {
981            type Output = $nonsymmetricn;
982            #[inline]
983            fn mul(self, rhs: Self) -> Self::Output {
984                (*self).mul(rhs)
985            }
986        }
987
988        impl Mul<&Self> for &$n {
989            type Output = $nonsymmetricn;
990            #[inline]
991            fn mul(self, rhs: &Self) -> Self::Output {
992                (*self).mul(*rhs)
993            }
994        }
995
996        impl Mul<$n> for $nonsymmetricn {
997            type Output = Self;
998            #[inline]
999            fn mul(self, rhs: $n) -> Self::Output {
1000                Self::from_cols_array_2d(&[
1001                    [
1002                        self.x_axis.x * rhs.m00 + self.y_axis.x * rhs.m01 + self.z_axis.x * rhs.m02 + self.w_axis.x * rhs.m03,
1003                        self.x_axis.y * rhs.m00 + self.y_axis.y * rhs.m01 + self.z_axis.y * rhs.m02 + self.w_axis.y * rhs.m03,
1004                        self.x_axis.z * rhs.m00 + self.y_axis.z * rhs.m01 + self.z_axis.z * rhs.m02 + self.w_axis.z * rhs.m03,
1005                        self.x_axis.w * rhs.m00 + self.y_axis.w * rhs.m01 + self.z_axis.w * rhs.m02 + self.w_axis.w * rhs.m03,
1006                    ],
1007                    [
1008                        self.x_axis.x * rhs.m01 + self.y_axis.x * rhs.m11 + self.z_axis.x * rhs.m12 + self.w_axis.x * rhs.m13,
1009                        self.x_axis.y * rhs.m01 + self.y_axis.y * rhs.m11 + self.z_axis.y * rhs.m12 + self.w_axis.y * rhs.m13,
1010                        self.x_axis.z * rhs.m01 + self.y_axis.z * rhs.m11 + self.z_axis.z * rhs.m12 + self.w_axis.z * rhs.m13,
1011                        self.x_axis.w * rhs.m01 + self.y_axis.w * rhs.m11 + self.z_axis.w * rhs.m12 + self.w_axis.w * rhs.m13,
1012                    ],
1013                    [
1014                        self.x_axis.x * rhs.m02 + self.y_axis.x * rhs.m12 + self.z_axis.x * rhs.m22 + self.w_axis.x * rhs.m23,
1015                        self.x_axis.y * rhs.m02 + self.y_axis.y * rhs.m12 + self.z_axis.y * rhs.m22 + self.w_axis.y * rhs.m23,
1016                        self.x_axis.z * rhs.m02 + self.y_axis.z * rhs.m12 + self.z_axis.z * rhs.m22 + self.w_axis.z * rhs.m23,
1017                        self.x_axis.w * rhs.m02 + self.y_axis.w * rhs.m12 + self.z_axis.w * rhs.m22 + self.w_axis.w * rhs.m23,
1018                    ],
1019                    [
1020                        self.x_axis.x * rhs.m03 + self.y_axis.x * rhs.m13 + self.z_axis.x * rhs.m23 + self.w_axis.x * rhs.m33,
1021                        self.x_axis.y * rhs.m03 + self.y_axis.y * rhs.m13 + self.z_axis.y * rhs.m23 + self.w_axis.y * rhs.m33,
1022                        self.x_axis.z * rhs.m03 + self.y_axis.z * rhs.m13 + self.z_axis.z * rhs.m23 + self.w_axis.z * rhs.m33,
1023                        self.x_axis.w * rhs.m03 + self.y_axis.w * rhs.m13 + self.z_axis.w * rhs.m23 + self.w_axis.w * rhs.m33,
1024                    ],
1025                ])
1026            }
1027        }
1028
1029        impl Mul<&$n> for $nonsymmetricn {
1030            type Output = Self;
1031            #[inline]
1032            fn mul(self, rhs: &$n) -> Self::Output {
1033                self.mul(*rhs)
1034            }
1035        }
1036
1037        impl Mul<$n> for &$nonsymmetricn {
1038            type Output = $nonsymmetricn;
1039            #[inline]
1040            fn mul(self, rhs: $n) -> Self::Output {
1041                (*self).mul(rhs)
1042            }
1043        }
1044
1045        impl Mul<&$n> for &$nonsymmetricn {
1046            type Output = $nonsymmetricn;
1047            #[inline]
1048            fn mul(self, rhs: &$n) -> Self::Output {
1049                (*self).mul(*rhs)
1050            }
1051        }
1052
1053        impl MulAssign<$n> for $nonsymmetricn {
1054            #[inline]
1055            fn mul_assign(&mut self, rhs: $n) {
1056                *self = self.mul(rhs);
1057            }
1058        }
1059
1060        impl MulAssign<&$n> for $nonsymmetricn {
1061            #[inline]
1062            fn mul_assign(&mut self, rhs: &$n) {
1063                *self = self.mul(*rhs);
1064            }
1065        }
1066
1067        impl Mul<$nonsymmetricn> for $n {
1068            type Output = $nonsymmetricn;
1069            #[inline]
1070            fn mul(self, rhs: $nonsymmetricn) -> Self::Output {
1071                $nonsymmetricn::from_cols(
1072                    self.mul(rhs.x_axis),
1073                    self.mul(rhs.y_axis),
1074                    self.mul(rhs.z_axis),
1075                    self.mul(rhs.w_axis),
1076                )
1077            }
1078        }
1079
1080        impl Mul<&$nonsymmetricn> for $n {
1081            type Output = $nonsymmetricn;
1082            #[inline]
1083            fn mul(self, rhs: &$nonsymmetricn) -> Self::Output {
1084                self.mul(*rhs)
1085            }
1086        }
1087
1088        impl Mul<$nonsymmetricn> for &$n {
1089            type Output = $nonsymmetricn;
1090            #[inline]
1091            fn mul(self, rhs: $nonsymmetricn) -> Self::Output {
1092                (*self).mul(rhs)
1093            }
1094        }
1095
1096        impl Mul<&$nonsymmetricn> for &$n {
1097            type Output = $nonsymmetricn;
1098            #[inline]
1099            fn mul(self, rhs: &$nonsymmetricn) -> Self::Output {
1100                (*self).mul(*rhs)
1101            }
1102        }
1103
1104        impl Mul<$vt> for $n {
1105            type Output = $vt;
1106            #[inline]
1107            fn mul(self, rhs: $vt) -> Self::Output {
1108                self.mul_vec4(rhs)
1109            }
1110        }
1111
1112        impl Mul<&$vt> for $n {
1113            type Output = $vt;
1114            #[inline]
1115            fn mul(self, rhs: &$vt) -> Self::Output {
1116                self.mul(*rhs)
1117            }
1118        }
1119
1120        impl Mul<$vt> for &$n {
1121            type Output = $vt;
1122            #[inline]
1123            fn mul(self, rhs: $vt) -> Self::Output {
1124                (*self).mul(rhs)
1125            }
1126        }
1127
1128        impl Mul<&$vt> for &$n {
1129            type Output = $vt;
1130            #[inline]
1131            fn mul(self, rhs: &$vt) -> Self::Output {
1132                (*self).mul(*rhs)
1133            }
1134        }
1135
1136        impl Mul<$n> for $t {
1137            type Output = $n;
1138            #[inline]
1139            fn mul(self, rhs: $n) -> Self::Output {
1140                rhs.mul_scalar(self)
1141            }
1142        }
1143
1144        impl Mul<&$n> for $t {
1145            type Output = $n;
1146            #[inline]
1147            fn mul(self, rhs: &$n) -> Self::Output {
1148                self.mul(*rhs)
1149            }
1150        }
1151
1152        impl Mul<$n> for &$t {
1153            type Output = $n;
1154            #[inline]
1155            fn mul(self, rhs: $n) -> Self::Output {
1156                (*self).mul(rhs)
1157            }
1158        }
1159
1160        impl Mul<&$n> for &$t {
1161            type Output = $n;
1162            #[inline]
1163            fn mul(self, rhs: &$n) -> Self::Output {
1164                (*self).mul(*rhs)
1165            }
1166        }
1167
1168        impl Mul<$t> for $n {
1169            type Output = Self;
1170            #[inline]
1171            fn mul(self, rhs: $t) -> Self::Output {
1172                self.mul_scalar(rhs)
1173            }
1174        }
1175
1176        impl Mul<&$t> for $n {
1177            type Output = Self;
1178            #[inline]
1179            fn mul(self, rhs: &$t) -> Self::Output {
1180                self.mul(*rhs)
1181            }
1182        }
1183
1184        impl Mul<$t> for &$n {
1185            type Output = $n;
1186            #[inline]
1187            fn mul(self, rhs: $t) -> Self::Output {
1188                (*self).mul(rhs)
1189            }
1190        }
1191
1192        impl Mul<&$t> for &$n {
1193            type Output = $n;
1194            #[inline]
1195            fn mul(self, rhs: &$t) -> Self::Output {
1196                (*self).mul(*rhs)
1197            }
1198        }
1199
1200        impl MulAssign<$t> for $n {
1201            #[inline]
1202            fn mul_assign(&mut self, rhs: $t) {
1203                *self = self.mul(rhs);
1204            }
1205        }
1206
1207        impl MulAssign<&$t> for $n {
1208            #[inline]
1209            fn mul_assign(&mut self, rhs: &$t) {
1210                self.mul_assign(*rhs);
1211            }
1212        }
1213
1214        impl Div<$n> for $t {
1215            type Output = $n;
1216            #[inline]
1217            fn div(self, rhs: $n) -> Self::Output {
1218                rhs.div_scalar(self)
1219            }
1220        }
1221
1222        impl Div<&$n> for $t {
1223            type Output = $n;
1224            #[inline]
1225            fn div(self, rhs: &$n) -> Self::Output {
1226                self.div(*rhs)
1227            }
1228        }
1229
1230        impl Div<$n> for &$t {
1231            type Output = $n;
1232            #[inline]
1233            fn div(self, rhs: $n) -> Self::Output {
1234                (*self).div(rhs)
1235            }
1236        }
1237
1238        impl Div<&$n> for &$t {
1239            type Output = $n;
1240            #[inline]
1241            fn div(self, rhs: &$n) -> Self::Output {
1242                (*self).div(*rhs)
1243            }
1244        }
1245
1246        impl Div<$t> for $n {
1247            type Output = Self;
1248            #[inline]
1249            fn div(self, rhs: $t) -> Self::Output {
1250                self.div_scalar(rhs)
1251            }
1252        }
1253
1254        impl Div<&$t> for $n {
1255            type Output = Self;
1256            #[inline]
1257            fn div(self, rhs: &$t) -> Self::Output {
1258                self.div(*rhs)
1259            }
1260        }
1261
1262        impl Div<$t> for &$n {
1263            type Output = $n;
1264            #[inline]
1265            fn div(self, rhs: $t) -> Self::Output {
1266                (*self).div(rhs)
1267            }
1268        }
1269
1270        impl Div<&$t> for &$n {
1271            type Output = $n;
1272            #[inline]
1273            fn div(self, rhs: &$t) -> Self::Output {
1274                (*self).div(*rhs)
1275            }
1276        }
1277
1278        impl DivAssign<$t> for $n {
1279            #[inline]
1280            fn div_assign(&mut self, rhs: $t) {
1281                *self = self.div(rhs);
1282            }
1283        }
1284
1285        impl DivAssign<&$t> for $n {
1286            #[inline]
1287            fn div_assign(&mut self, rhs: &$t) {
1288                self.div_assign(*rhs);
1289            }
1290        }
1291
1292        impl From<$n> for $nonsymmetricn {
1293            #[inline]
1294            fn from(mat: $n) -> Self {
1295                mat.to_mat4()
1296            }
1297        }
1298
1299        impl Sum<$n> for $n {
1300            fn sum<I: Iterator<Item = $n>>(iter: I) -> Self {
1301                iter.fold(Self::ZERO, Self::add)
1302            }
1303        }
1304
1305        impl<'a> Sum<&'a $n> for $n {
1306            fn sum<I: Iterator<Item = &'a $n>>(iter: I) -> Self {
1307                iter.fold(Self::ZERO, |a, &b| a.add(b))
1308            }
1309        }
1310
1311        #[cfg(feature = "approx")]
1312        impl approx::AbsDiffEq for $n {
1313            type Epsilon = $t;
1314
1315            #[inline]
1316            fn default_epsilon() -> Self::Epsilon {
1317                $t::default_epsilon()
1318            }
1319
1320            #[inline]
1321            fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
1322                self.m00.abs_diff_eq(&other.m00, epsilon)
1323                    && self.m01.abs_diff_eq(&other.m01, epsilon)
1324                    && self.m02.abs_diff_eq(&other.m02, epsilon)
1325                    && self.m03.abs_diff_eq(&other.m03, epsilon)
1326                    && self.m11.abs_diff_eq(&other.m11, epsilon)
1327                    && self.m12.abs_diff_eq(&other.m12, epsilon)
1328                    && self.m13.abs_diff_eq(&other.m13, epsilon)
1329                    && self.m22.abs_diff_eq(&other.m22, epsilon)
1330                    && self.m23.abs_diff_eq(&other.m23, epsilon)
1331                    && self.m33.abs_diff_eq(&other.m33, epsilon)
1332            }
1333        }
1334
1335        #[cfg(feature = "approx")]
1336        impl approx::RelativeEq for $n {
1337            #[inline]
1338            fn default_max_relative() -> Self::Epsilon {
1339                $t::default_max_relative()
1340            }
1341
1342            #[inline]
1343            fn relative_eq(
1344                &self,
1345                other: &Self,
1346                epsilon: Self::Epsilon,
1347                max_relative: Self::Epsilon,
1348            ) -> bool {
1349                self.m00.relative_eq(&other.m00, epsilon, max_relative)
1350                    && self.m01.relative_eq(&other.m01, epsilon, max_relative)
1351                    && self.m02.relative_eq(&other.m02, epsilon, max_relative)
1352                    && self.m03.relative_eq(&other.m03, epsilon, max_relative)
1353                    && self.m11.relative_eq(&other.m11, epsilon, max_relative)
1354                    && self.m12.relative_eq(&other.m12, epsilon, max_relative)
1355                    && self.m13.relative_eq(&other.m13, epsilon, max_relative)
1356                    && self.m22.relative_eq(&other.m22, epsilon, max_relative)
1357                    && self.m23.relative_eq(&other.m23, epsilon, max_relative)
1358                    && self.m33.relative_eq(&other.m33, epsilon, max_relative)
1359            }
1360        }
1361
1362        #[cfg(feature = "approx")]
1363        impl approx::UlpsEq for $n {
1364            #[inline]
1365            fn default_max_ulps() -> u32 {
1366                $t::default_max_ulps()
1367            }
1368
1369            #[inline]
1370            fn ulps_eq(
1371                &self,
1372                other: &Self,
1373                epsilon: Self::Epsilon,
1374                max_ulps: u32,
1375            ) -> bool {
1376                self.m00.ulps_eq(&other.m00, epsilon, max_ulps)
1377                    && self.m01.ulps_eq(&other.m01, epsilon, max_ulps)
1378                    && self.m02.ulps_eq(&other.m02, epsilon, max_ulps)
1379                    && self.m03.ulps_eq(&other.m03, epsilon, max_ulps)
1380                    && self.m11.ulps_eq(&other.m11, epsilon, max_ulps)
1381                    && self.m12.ulps_eq(&other.m12, epsilon, max_ulps)
1382                    && self.m13.ulps_eq(&other.m13, epsilon, max_ulps)
1383                    && self.m22.ulps_eq(&other.m22, epsilon, max_ulps)
1384                    && self.m23.ulps_eq(&other.m23, epsilon, max_ulps)
1385                    && self.m33.ulps_eq(&other.m33, epsilon, max_ulps)
1386            }
1387        }
1388
1389        impl core::fmt::Debug for $n {
1390            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1391                f.debug_struct(stringify!($n))
1392                    .field("m00", &self.m00)
1393                    .field("m01", &self.m01)
1394                    .field("m02", &self.m02)
1395                    .field("m03", &self.m03)
1396                    .field("m11", &self.m11)
1397                    .field("m12", &self.m12)
1398                    .field("m13", &self.m13)
1399                    .field("m22", &self.m22)
1400                    .field("m23", &self.m23)
1401                    .field("m33", &self.m33)
1402                    .finish()
1403            }
1404        }
1405
1406        impl core::fmt::Display for $n {
1407            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1408                if let Some(p) = f.precision() {
1409                    write!(
1410                        f,
1411                        "[[{:.*}, {:.*}, {:.*}, {:.*}], [{:.*}, {:.*}, {:.*}, {:.*}], [{:.*}, {:.*}, {:.*}, {:.*}], [{:.*}, {:.*}, {:.*}, {:.*}]]",
1412                        p, self.m00, p, self.m01, p, self.m02, p, self.m03,
1413                        p, self.m01, p, self.m11, p, self.m12, p, self.m13,
1414                        p, self.m02, p, self.m12, p, self.m22, p, self.m23,
1415                        p, self.m03, p, self.m13, p, self.m23, p, self.m33,
1416                    )
1417                } else {
1418                    write!(
1419                        f,
1420                        "[[{}, {}, {}, {}], [{}, {}, {}, {}], [{}, {}, {}, {}], [{}, {}, {}, {}]]",
1421                        self.m00, self.m01, self.m02, self.m03,
1422                        self.m01, self.m11, self.m12, self.m13,
1423                        self.m02, self.m12, self.m22, self.m23,
1424                        self.m03, self.m13, self.m23, self.m33,
1425                    )
1426                }
1427            }
1428        }
1429        )+
1430    }
1431}
1432
1433#[cfg(feature = "f32")]
1434symmetric_mat4s!(SymmetricMat4 => Mat4, Vec4, f32);
1435
1436#[cfg(feature = "f64")]
1437symmetric_mat4s!(SymmetricDMat4 => DMat4, DVec4, f64);
1438
1439#[cfg(all(feature = "f32", feature = "f64"))]
1440impl SymmetricMat4 {
1441    /// Returns the double precision version of `self`.
1442    #[inline]
1443    #[must_use]
1444    pub fn as_symmetric_dmat4(&self) -> SymmetricDMat4 {
1445        SymmetricDMat4 {
1446            m00: self.m00 as f64,
1447            m01: self.m01 as f64,
1448            m02: self.m02 as f64,
1449            m03: self.m03 as f64,
1450            m11: self.m11 as f64,
1451            m12: self.m12 as f64,
1452            m13: self.m13 as f64,
1453            m22: self.m22 as f64,
1454            m23: self.m23 as f64,
1455            m33: self.m33 as f64,
1456        }
1457    }
1458}
1459
1460#[cfg(all(feature = "f32", feature = "f64"))]
1461impl SymmetricDMat4 {
1462    /// Returns the single precision version of `self`.
1463    #[inline]
1464    #[must_use]
1465    pub fn as_symmetric_mat4(&self) -> SymmetricMat4 {
1466        SymmetricMat4 {
1467            m00: self.m00 as f32,
1468            m01: self.m01 as f32,
1469            m02: self.m02 as f32,
1470            m03: self.m03 as f32,
1471            m11: self.m11 as f32,
1472            m12: self.m12 as f32,
1473            m13: self.m13 as f32,
1474            m22: self.m22 as f32,
1475            m23: self.m23 as f32,
1476            m33: self.m33 as f32,
1477        }
1478    }
1479}
1480
1481#[cfg(test)]
1482mod tests {
1483    use approx::assert_relative_eq;
1484
1485    use crate::SymmetricMat4;
1486
1487    #[test]
1488    fn determinant() {
1489        let mat = SymmetricMat4::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0);
1490        assert_relative_eq!(mat.determinant(), mat.to_mat4().determinant());
1491    }
1492
1493    #[test]
1494    fn inverse() {
1495        let mat = SymmetricMat4::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0);
1496        assert_relative_eq!(mat.inverse().to_mat4(), mat.to_mat4().inverse());
1497    }
1498}