glam/f64/
dmat4.rs

1// Generated from mat.rs.tera template. Edit the template, not the generated file.
2
3use crate::{
4    euler::{FromEuler, ToEuler},
5    f64::math,
6    swizzles::*,
7    DMat3, DQuat, DVec3, DVec4, EulerRot, Mat4,
8};
9use core::fmt;
10use core::iter::{Product, Sum};
11use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
12
13#[cfg(feature = "zerocopy")]
14use zerocopy_derive::*;
15
16/// Creates a 4x4 matrix from four column vectors.
17#[inline(always)]
18#[must_use]
19pub const fn dmat4(x_axis: DVec4, y_axis: DVec4, z_axis: DVec4, w_axis: DVec4) -> DMat4 {
20    DMat4::from_cols(x_axis, y_axis, z_axis, w_axis)
21}
22
23/// A 4x4 column major matrix.
24///
25/// This 4x4 matrix type features convenience methods for creating and using affine transforms and
26/// perspective projections. If you are primarily dealing with 3D affine transformations
27/// considering using [`DAffine3`](crate::DAffine3) which is faster than a 4x4 matrix
28/// for some affine operations.
29///
30/// Affine transformations including 3D translation, rotation and scale can be created
31/// using methods such as [`Self::from_translation()`], [`Self::from_quat()`],
32/// [`Self::from_scale()`] and [`Self::from_scale_rotation_translation()`].
33///
34/// Orthographic projections can be created using the methods [`Self::orthographic_lh()`] for
35/// left-handed coordinate systems and [`Self::orthographic_rh()`] for right-handed
36/// systems. The resulting matrix is also an affine transformation.
37///
38/// The [`Self::transform_point3()`] and [`Self::transform_vector3()`] convenience methods
39/// are provided for performing affine transformations on 3D vectors and points. These
40/// multiply 3D inputs as 4D vectors with an implicit `w` value of `1` for points and `0`
41/// for vectors respectively. These methods assume that `Self` contains a valid affine
42/// transform.
43///
44/// Perspective projections can be created using methods such as
45/// [`Self::perspective_lh()`], [`Self::perspective_infinite_lh()`] and
46/// [`Self::perspective_infinite_reverse_lh()`] for left-handed co-ordinate systems and
47/// [`Self::perspective_rh()`], [`Self::perspective_infinite_rh()`] and
48/// [`Self::perspective_infinite_reverse_rh()`] for right-handed co-ordinate systems.
49///
50/// The resulting perspective project can be use to transform 3D vectors as points with
51/// perspective correction using the [`Self::project_point3()`] convenience method.
52#[derive(Clone, Copy)]
53#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
54#[cfg_attr(
55    feature = "zerocopy",
56    derive(FromBytes, Immutable, IntoBytes, KnownLayout)
57)]
58#[cfg_attr(feature = "cuda", repr(align(16)))]
59#[repr(C)]
60pub struct DMat4 {
61    pub x_axis: DVec4,
62    pub y_axis: DVec4,
63    pub z_axis: DVec4,
64    pub w_axis: DVec4,
65}
66
67impl DMat4 {
68    /// A 4x4 matrix with all elements set to `0.0`.
69    pub const ZERO: Self = Self::from_cols(DVec4::ZERO, DVec4::ZERO, DVec4::ZERO, DVec4::ZERO);
70
71    /// A 4x4 identity matrix, where all diagonal elements are `1`, and all off-diagonal elements are `0`.
72    pub const IDENTITY: Self = Self::from_cols(DVec4::X, DVec4::Y, DVec4::Z, DVec4::W);
73
74    /// All NAN:s.
75    pub const NAN: Self = Self::from_cols(DVec4::NAN, DVec4::NAN, DVec4::NAN, DVec4::NAN);
76
77    #[allow(clippy::too_many_arguments)]
78    #[inline(always)]
79    #[must_use]
80    const fn new(
81        m00: f64,
82        m01: f64,
83        m02: f64,
84        m03: f64,
85        m10: f64,
86        m11: f64,
87        m12: f64,
88        m13: f64,
89        m20: f64,
90        m21: f64,
91        m22: f64,
92        m23: f64,
93        m30: f64,
94        m31: f64,
95        m32: f64,
96        m33: f64,
97    ) -> Self {
98        Self {
99            x_axis: DVec4::new(m00, m01, m02, m03),
100            y_axis: DVec4::new(m10, m11, m12, m13),
101            z_axis: DVec4::new(m20, m21, m22, m23),
102            w_axis: DVec4::new(m30, m31, m32, m33),
103        }
104    }
105
106    /// Creates a 4x4 matrix from four column vectors.
107    #[inline(always)]
108    #[must_use]
109    pub const fn from_cols(x_axis: DVec4, y_axis: DVec4, z_axis: DVec4, w_axis: DVec4) -> Self {
110        Self {
111            x_axis,
112            y_axis,
113            z_axis,
114            w_axis,
115        }
116    }
117
118    /// Creates a 4x4 matrix from a `[f64; 16]` array stored in column major order.
119    /// If your data is stored in row major you will need to `transpose` the returned
120    /// matrix.
121    #[inline]
122    #[must_use]
123    pub const fn from_cols_array(m: &[f64; 16]) -> Self {
124        Self::new(
125            m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], m[12], m[13],
126            m[14], m[15],
127        )
128    }
129
130    /// Creates a `[f64; 16]` array storing data in column major order.
131    /// If you require data in row major order `transpose` the matrix first.
132    #[inline]
133    #[must_use]
134    pub const fn to_cols_array(&self) -> [f64; 16] {
135        [
136            self.x_axis.x,
137            self.x_axis.y,
138            self.x_axis.z,
139            self.x_axis.w,
140            self.y_axis.x,
141            self.y_axis.y,
142            self.y_axis.z,
143            self.y_axis.w,
144            self.z_axis.x,
145            self.z_axis.y,
146            self.z_axis.z,
147            self.z_axis.w,
148            self.w_axis.x,
149            self.w_axis.y,
150            self.w_axis.z,
151            self.w_axis.w,
152        ]
153    }
154
155    /// Creates a 4x4 matrix from a `[[f64; 4]; 4]` 4D array stored in column major order.
156    /// If your data is in row major order you will need to `transpose` the returned
157    /// matrix.
158    #[inline]
159    #[must_use]
160    pub const fn from_cols_array_2d(m: &[[f64; 4]; 4]) -> Self {
161        Self::from_cols(
162            DVec4::from_array(m[0]),
163            DVec4::from_array(m[1]),
164            DVec4::from_array(m[2]),
165            DVec4::from_array(m[3]),
166        )
167    }
168
169    /// Creates a `[[f64; 4]; 4]` 4D array storing data in column major order.
170    /// If you require data in row major order `transpose` the matrix first.
171    #[inline]
172    #[must_use]
173    pub const fn to_cols_array_2d(&self) -> [[f64; 4]; 4] {
174        [
175            self.x_axis.to_array(),
176            self.y_axis.to_array(),
177            self.z_axis.to_array(),
178            self.w_axis.to_array(),
179        ]
180    }
181
182    /// Creates a 4x4 matrix with its diagonal set to `diagonal` and all other entries set to 0.
183    #[doc(alias = "scale")]
184    #[inline]
185    #[must_use]
186    pub const fn from_diagonal(diagonal: DVec4) -> Self {
187        Self::new(
188            diagonal.x, 0.0, 0.0, 0.0, 0.0, diagonal.y, 0.0, 0.0, 0.0, 0.0, diagonal.z, 0.0, 0.0,
189            0.0, 0.0, diagonal.w,
190        )
191    }
192
193    #[inline]
194    #[must_use]
195    fn quat_to_axes(rotation: DQuat) -> (DVec4, DVec4, DVec4) {
196        glam_assert!(rotation.is_normalized());
197
198        let (x, y, z, w) = rotation.into();
199        let x2 = x + x;
200        let y2 = y + y;
201        let z2 = z + z;
202        let xx = x * x2;
203        let xy = x * y2;
204        let xz = x * z2;
205        let yy = y * y2;
206        let yz = y * z2;
207        let zz = z * z2;
208        let wx = w * x2;
209        let wy = w * y2;
210        let wz = w * z2;
211
212        let x_axis = DVec4::new(1.0 - (yy + zz), xy + wz, xz - wy, 0.0);
213        let y_axis = DVec4::new(xy - wz, 1.0 - (xx + zz), yz + wx, 0.0);
214        let z_axis = DVec4::new(xz + wy, yz - wx, 1.0 - (xx + yy), 0.0);
215        (x_axis, y_axis, z_axis)
216    }
217
218    /// Creates an affine transformation matrix from the given 3D `scale`, `rotation` and
219    /// `translation`.
220    ///
221    /// The resulting matrix can be used to transform 3D points and vectors. See
222    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
223    ///
224    /// # Panics
225    ///
226    /// Will panic if `rotation` is not normalized when `glam_assert` is enabled.
227    #[inline]
228    #[must_use]
229    pub fn from_scale_rotation_translation(
230        scale: DVec3,
231        rotation: DQuat,
232        translation: DVec3,
233    ) -> Self {
234        let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation);
235        Self::from_cols(
236            x_axis.mul(scale.x),
237            y_axis.mul(scale.y),
238            z_axis.mul(scale.z),
239            DVec4::from((translation, 1.0)),
240        )
241    }
242
243    /// Creates an affine transformation matrix from the given 3D `translation`.
244    ///
245    /// The resulting matrix can be used to transform 3D points and vectors. See
246    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
247    ///
248    /// # Panics
249    ///
250    /// Will panic if `rotation` is not normalized when `glam_assert` is enabled.
251    #[inline]
252    #[must_use]
253    pub fn from_rotation_translation(rotation: DQuat, translation: DVec3) -> Self {
254        let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation);
255        Self::from_cols(x_axis, y_axis, z_axis, DVec4::from((translation, 1.0)))
256    }
257
258    /// Extracts `scale`, `rotation` and `translation` from `self`. The input matrix is
259    /// expected to be a 3D affine transformation matrix otherwise the output will be invalid.
260    ///
261    /// # Panics
262    ///
263    /// Will panic if the determinant of `self` is zero or if the resulting scale vector
264    /// contains any zero elements when `glam_assert` is enabled.
265    #[inline]
266    #[must_use]
267    pub fn to_scale_rotation_translation(&self) -> (DVec3, DQuat, DVec3) {
268        let det = self.determinant();
269        glam_assert!(det != 0.0);
270
271        let scale = DVec3::new(
272            self.x_axis.length() * math::signum(det),
273            self.y_axis.length(),
274            self.z_axis.length(),
275        );
276
277        glam_assert!(scale.cmpne(DVec3::ZERO).all());
278
279        let inv_scale = scale.recip();
280
281        let rotation = DQuat::from_rotation_axes(
282            self.x_axis.mul(inv_scale.x).xyz(),
283            self.y_axis.mul(inv_scale.y).xyz(),
284            self.z_axis.mul(inv_scale.z).xyz(),
285        );
286
287        let translation = self.w_axis.xyz();
288
289        (scale, rotation, translation)
290    }
291
292    /// Creates an affine transformation matrix from the given `rotation` quaternion.
293    ///
294    /// The resulting matrix can be used to transform 3D points and vectors. See
295    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
296    ///
297    /// # Panics
298    ///
299    /// Will panic if `rotation` is not normalized when `glam_assert` is enabled.
300    #[inline]
301    #[must_use]
302    pub fn from_quat(rotation: DQuat) -> Self {
303        let (x_axis, y_axis, z_axis) = Self::quat_to_axes(rotation);
304        Self::from_cols(x_axis, y_axis, z_axis, DVec4::W)
305    }
306
307    /// Creates an affine transformation matrix from the given 3x3 linear transformation
308    /// matrix.
309    ///
310    /// The resulting matrix can be used to transform 3D points and vectors. See
311    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
312    #[inline]
313    #[must_use]
314    pub fn from_mat3(m: DMat3) -> Self {
315        Self::from_cols(
316            DVec4::from((m.x_axis, 0.0)),
317            DVec4::from((m.y_axis, 0.0)),
318            DVec4::from((m.z_axis, 0.0)),
319            DVec4::W,
320        )
321    }
322
323    /// Creates an affine transformation matrics from a 3x3 matrix (expressing scale, shear and
324    /// rotation) and a translation vector.
325    ///
326    /// Equivalent to `DMat4::from_translation(translation) * DMat4::from_mat3(mat3)`
327    #[inline]
328    #[must_use]
329    pub fn from_mat3_translation(mat3: DMat3, translation: DVec3) -> Self {
330        Self::from_cols(
331            DVec4::from((mat3.x_axis, 0.0)),
332            DVec4::from((mat3.y_axis, 0.0)),
333            DVec4::from((mat3.z_axis, 0.0)),
334            DVec4::from((translation, 1.0)),
335        )
336    }
337
338    /// Creates an affine transformation matrix from the given 3D `translation`.
339    ///
340    /// The resulting matrix can be used to transform 3D points and vectors. See
341    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
342    #[inline]
343    #[must_use]
344    pub fn from_translation(translation: DVec3) -> Self {
345        Self::from_cols(
346            DVec4::X,
347            DVec4::Y,
348            DVec4::Z,
349            DVec4::new(translation.x, translation.y, translation.z, 1.0),
350        )
351    }
352
353    /// Creates an affine transformation matrix containing a 3D rotation around a normalized
354    /// rotation `axis` of `angle` (in radians).
355    ///
356    /// The resulting matrix can be used to transform 3D points and vectors. See
357    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
358    ///
359    /// # Panics
360    ///
361    /// Will panic if `axis` is not normalized when `glam_assert` is enabled.
362    #[inline]
363    #[must_use]
364    pub fn from_axis_angle(axis: DVec3, angle: f64) -> Self {
365        glam_assert!(axis.is_normalized());
366
367        let (sin, cos) = math::sin_cos(angle);
368        let axis_sin = axis.mul(sin);
369        let axis_sq = axis.mul(axis);
370        let omc = 1.0 - cos;
371        let xyomc = axis.x * axis.y * omc;
372        let xzomc = axis.x * axis.z * omc;
373        let yzomc = axis.y * axis.z * omc;
374        Self::from_cols(
375            DVec4::new(
376                axis_sq.x * omc + cos,
377                xyomc + axis_sin.z,
378                xzomc - axis_sin.y,
379                0.0,
380            ),
381            DVec4::new(
382                xyomc - axis_sin.z,
383                axis_sq.y * omc + cos,
384                yzomc + axis_sin.x,
385                0.0,
386            ),
387            DVec4::new(
388                xzomc + axis_sin.y,
389                yzomc - axis_sin.x,
390                axis_sq.z * omc + cos,
391                0.0,
392            ),
393            DVec4::W,
394        )
395    }
396
397    /// Creates a affine transformation matrix containing a rotation from the given euler
398    /// rotation sequence and angles (in radians).
399    ///
400    /// The resulting matrix can be used to transform 3D points and vectors. See
401    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
402    #[inline]
403    #[must_use]
404    pub fn from_euler(order: EulerRot, a: f64, b: f64, c: f64) -> Self {
405        Self::from_euler_angles(order, a, b, c)
406    }
407
408    /// Extract Euler angles with the given Euler rotation order.
409    ///
410    /// Note if the upper 3x3 matrix contain scales, shears, or other non-rotation transformations
411    /// then the resulting Euler angles will be ill-defined.
412    ///
413    /// # Panics
414    ///
415    /// Will panic if any column of the upper 3x3 rotation matrix is not normalized when
416    /// `glam_assert` is enabled.
417    #[inline]
418    #[must_use]
419    pub fn to_euler(&self, order: EulerRot) -> (f64, f64, f64) {
420        glam_assert!(
421            self.x_axis.xyz().is_normalized()
422                && self.y_axis.xyz().is_normalized()
423                && self.z_axis.xyz().is_normalized()
424        );
425        self.to_euler_angles(order)
426    }
427
428    /// Creates an affine transformation matrix containing a 3D rotation around the x axis of
429    /// `angle` (in radians).
430    ///
431    /// The resulting matrix can be used to transform 3D points and vectors. See
432    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
433    #[inline]
434    #[must_use]
435    pub fn from_rotation_x(angle: f64) -> Self {
436        let (sina, cosa) = math::sin_cos(angle);
437        Self::from_cols(
438            DVec4::X,
439            DVec4::new(0.0, cosa, sina, 0.0),
440            DVec4::new(0.0, -sina, cosa, 0.0),
441            DVec4::W,
442        )
443    }
444
445    /// Creates an affine transformation matrix containing a 3D rotation around the y axis of
446    /// `angle` (in radians).
447    ///
448    /// The resulting matrix can be used to transform 3D points and vectors. See
449    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
450    #[inline]
451    #[must_use]
452    pub fn from_rotation_y(angle: f64) -> Self {
453        let (sina, cosa) = math::sin_cos(angle);
454        Self::from_cols(
455            DVec4::new(cosa, 0.0, -sina, 0.0),
456            DVec4::Y,
457            DVec4::new(sina, 0.0, cosa, 0.0),
458            DVec4::W,
459        )
460    }
461
462    /// Creates an affine transformation matrix containing a 3D rotation around the z axis of
463    /// `angle` (in radians).
464    ///
465    /// The resulting matrix can be used to transform 3D points and vectors. See
466    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
467    #[inline]
468    #[must_use]
469    pub fn from_rotation_z(angle: f64) -> Self {
470        let (sina, cosa) = math::sin_cos(angle);
471        Self::from_cols(
472            DVec4::new(cosa, sina, 0.0, 0.0),
473            DVec4::new(-sina, cosa, 0.0, 0.0),
474            DVec4::Z,
475            DVec4::W,
476        )
477    }
478
479    /// Creates an affine transformation matrix containing the given 3D non-uniform `scale`.
480    ///
481    /// The resulting matrix can be used to transform 3D points and vectors. See
482    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
483    ///
484    /// # Panics
485    ///
486    /// Will panic if all elements of `scale` are zero when `glam_assert` is enabled.
487    #[inline]
488    #[must_use]
489    pub fn from_scale(scale: DVec3) -> Self {
490        // Do not panic as long as any component is non-zero
491        glam_assert!(scale.cmpne(DVec3::ZERO).any());
492
493        Self::from_cols(
494            DVec4::new(scale.x, 0.0, 0.0, 0.0),
495            DVec4::new(0.0, scale.y, 0.0, 0.0),
496            DVec4::new(0.0, 0.0, scale.z, 0.0),
497            DVec4::W,
498        )
499    }
500
501    /// Creates a 4x4 matrix from the first 16 values in `slice`.
502    ///
503    /// # Panics
504    ///
505    /// Panics if `slice` is less than 16 elements long.
506    #[inline]
507    #[must_use]
508    pub const fn from_cols_slice(slice: &[f64]) -> Self {
509        Self::new(
510            slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7],
511            slice[8], slice[9], slice[10], slice[11], slice[12], slice[13], slice[14], slice[15],
512        )
513    }
514
515    /// Writes the columns of `self` to the first 16 elements in `slice`.
516    ///
517    /// # Panics
518    ///
519    /// Panics if `slice` is less than 16 elements long.
520    #[inline]
521    pub fn write_cols_to_slice(self, slice: &mut [f64]) {
522        slice[0] = self.x_axis.x;
523        slice[1] = self.x_axis.y;
524        slice[2] = self.x_axis.z;
525        slice[3] = self.x_axis.w;
526        slice[4] = self.y_axis.x;
527        slice[5] = self.y_axis.y;
528        slice[6] = self.y_axis.z;
529        slice[7] = self.y_axis.w;
530        slice[8] = self.z_axis.x;
531        slice[9] = self.z_axis.y;
532        slice[10] = self.z_axis.z;
533        slice[11] = self.z_axis.w;
534        slice[12] = self.w_axis.x;
535        slice[13] = self.w_axis.y;
536        slice[14] = self.w_axis.z;
537        slice[15] = self.w_axis.w;
538    }
539
540    /// Returns the matrix column for the given `index`.
541    ///
542    /// # Panics
543    ///
544    /// Panics if `index` is greater than 3.
545    #[inline]
546    #[must_use]
547    pub fn col(&self, index: usize) -> DVec4 {
548        match index {
549            0 => self.x_axis,
550            1 => self.y_axis,
551            2 => self.z_axis,
552            3 => self.w_axis,
553            _ => panic!("index out of bounds"),
554        }
555    }
556
557    /// Returns a mutable reference to the matrix column for the given `index`.
558    ///
559    /// # Panics
560    ///
561    /// Panics if `index` is greater than 3.
562    #[inline]
563    pub fn col_mut(&mut self, index: usize) -> &mut DVec4 {
564        match index {
565            0 => &mut self.x_axis,
566            1 => &mut self.y_axis,
567            2 => &mut self.z_axis,
568            3 => &mut self.w_axis,
569            _ => panic!("index out of bounds"),
570        }
571    }
572
573    /// Returns the matrix row for the given `index`.
574    ///
575    /// # Panics
576    ///
577    /// Panics if `index` is greater than 3.
578    #[inline]
579    #[must_use]
580    pub fn row(&self, index: usize) -> DVec4 {
581        match index {
582            0 => DVec4::new(self.x_axis.x, self.y_axis.x, self.z_axis.x, self.w_axis.x),
583            1 => DVec4::new(self.x_axis.y, self.y_axis.y, self.z_axis.y, self.w_axis.y),
584            2 => DVec4::new(self.x_axis.z, self.y_axis.z, self.z_axis.z, self.w_axis.z),
585            3 => DVec4::new(self.x_axis.w, self.y_axis.w, self.z_axis.w, self.w_axis.w),
586            _ => panic!("index out of bounds"),
587        }
588    }
589
590    /// Returns `true` if, and only if, all elements are finite.
591    /// If any element is either `NaN`, positive or negative infinity, this will return `false`.
592    #[inline]
593    #[must_use]
594    pub fn is_finite(&self) -> bool {
595        self.x_axis.is_finite()
596            && self.y_axis.is_finite()
597            && self.z_axis.is_finite()
598            && self.w_axis.is_finite()
599    }
600
601    /// Returns `true` if any elements are `NaN`.
602    #[inline]
603    #[must_use]
604    pub fn is_nan(&self) -> bool {
605        self.x_axis.is_nan() || self.y_axis.is_nan() || self.z_axis.is_nan() || self.w_axis.is_nan()
606    }
607
608    /// Returns the transpose of `self`.
609    #[inline]
610    #[must_use]
611    pub fn transpose(&self) -> Self {
612        Self {
613            x_axis: DVec4::new(self.x_axis.x, self.y_axis.x, self.z_axis.x, self.w_axis.x),
614            y_axis: DVec4::new(self.x_axis.y, self.y_axis.y, self.z_axis.y, self.w_axis.y),
615            z_axis: DVec4::new(self.x_axis.z, self.y_axis.z, self.z_axis.z, self.w_axis.z),
616            w_axis: DVec4::new(self.x_axis.w, self.y_axis.w, self.z_axis.w, self.w_axis.w),
617        }
618    }
619
620    /// Returns the determinant of `self`.
621    #[must_use]
622    pub fn determinant(&self) -> f64 {
623        let (m00, m01, m02, m03) = self.x_axis.into();
624        let (m10, m11, m12, m13) = self.y_axis.into();
625        let (m20, m21, m22, m23) = self.z_axis.into();
626        let (m30, m31, m32, m33) = self.w_axis.into();
627
628        let a2323 = m22 * m33 - m23 * m32;
629        let a1323 = m21 * m33 - m23 * m31;
630        let a1223 = m21 * m32 - m22 * m31;
631        let a0323 = m20 * m33 - m23 * m30;
632        let a0223 = m20 * m32 - m22 * m30;
633        let a0123 = m20 * m31 - m21 * m30;
634
635        m00 * (m11 * a2323 - m12 * a1323 + m13 * a1223)
636            - m01 * (m10 * a2323 - m12 * a0323 + m13 * a0223)
637            + m02 * (m10 * a1323 - m11 * a0323 + m13 * a0123)
638            - m03 * (m10 * a1223 - m11 * a0223 + m12 * a0123)
639    }
640
641    /// Returns the inverse of `self`.
642    ///
643    /// If the matrix is not invertible the returned matrix will be invalid.
644    ///
645    /// # Panics
646    ///
647    /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled.
648    #[must_use]
649    pub fn inverse(&self) -> Self {
650        let (m00, m01, m02, m03) = self.x_axis.into();
651        let (m10, m11, m12, m13) = self.y_axis.into();
652        let (m20, m21, m22, m23) = self.z_axis.into();
653        let (m30, m31, m32, m33) = self.w_axis.into();
654
655        let coef00 = m22 * m33 - m32 * m23;
656        let coef02 = m12 * m33 - m32 * m13;
657        let coef03 = m12 * m23 - m22 * m13;
658
659        let coef04 = m21 * m33 - m31 * m23;
660        let coef06 = m11 * m33 - m31 * m13;
661        let coef07 = m11 * m23 - m21 * m13;
662
663        let coef08 = m21 * m32 - m31 * m22;
664        let coef10 = m11 * m32 - m31 * m12;
665        let coef11 = m11 * m22 - m21 * m12;
666
667        let coef12 = m20 * m33 - m30 * m23;
668        let coef14 = m10 * m33 - m30 * m13;
669        let coef15 = m10 * m23 - m20 * m13;
670
671        let coef16 = m20 * m32 - m30 * m22;
672        let coef18 = m10 * m32 - m30 * m12;
673        let coef19 = m10 * m22 - m20 * m12;
674
675        let coef20 = m20 * m31 - m30 * m21;
676        let coef22 = m10 * m31 - m30 * m11;
677        let coef23 = m10 * m21 - m20 * m11;
678
679        let fac0 = DVec4::new(coef00, coef00, coef02, coef03);
680        let fac1 = DVec4::new(coef04, coef04, coef06, coef07);
681        let fac2 = DVec4::new(coef08, coef08, coef10, coef11);
682        let fac3 = DVec4::new(coef12, coef12, coef14, coef15);
683        let fac4 = DVec4::new(coef16, coef16, coef18, coef19);
684        let fac5 = DVec4::new(coef20, coef20, coef22, coef23);
685
686        let vec0 = DVec4::new(m10, m00, m00, m00);
687        let vec1 = DVec4::new(m11, m01, m01, m01);
688        let vec2 = DVec4::new(m12, m02, m02, m02);
689        let vec3 = DVec4::new(m13, m03, m03, m03);
690
691        let inv0 = vec1.mul(fac0).sub(vec2.mul(fac1)).add(vec3.mul(fac2));
692        let inv1 = vec0.mul(fac0).sub(vec2.mul(fac3)).add(vec3.mul(fac4));
693        let inv2 = vec0.mul(fac1).sub(vec1.mul(fac3)).add(vec3.mul(fac5));
694        let inv3 = vec0.mul(fac2).sub(vec1.mul(fac4)).add(vec2.mul(fac5));
695
696        let sign_a = DVec4::new(1.0, -1.0, 1.0, -1.0);
697        let sign_b = DVec4::new(-1.0, 1.0, -1.0, 1.0);
698
699        let inverse = Self::from_cols(
700            inv0.mul(sign_a),
701            inv1.mul(sign_b),
702            inv2.mul(sign_a),
703            inv3.mul(sign_b),
704        );
705
706        let col0 = DVec4::new(
707            inverse.x_axis.x,
708            inverse.y_axis.x,
709            inverse.z_axis.x,
710            inverse.w_axis.x,
711        );
712
713        let dot0 = self.x_axis.mul(col0);
714        let dot1 = dot0.x + dot0.y + dot0.z + dot0.w;
715
716        glam_assert!(dot1 != 0.0);
717
718        let rcp_det = dot1.recip();
719        inverse.mul(rcp_det)
720    }
721
722    /// Creates a left-handed view matrix using a camera position, a facing direction and an up
723    /// direction
724    ///
725    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`.
726    ///
727    /// # Panics
728    ///
729    /// Will panic if `dir` or `up` are not normalized when `glam_assert` is enabled.
730    #[inline]
731    #[must_use]
732    pub fn look_to_lh(eye: DVec3, dir: DVec3, up: DVec3) -> Self {
733        Self::look_to_rh(eye, -dir, up)
734    }
735
736    /// Creates a right-handed view matrix using a camera position, a facing direction, and an up
737    /// direction.
738    ///
739    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`.
740    ///
741    /// # Panics
742    ///
743    /// Will panic if `dir` or `up` are not normalized when `glam_assert` is enabled.
744    #[inline]
745    #[must_use]
746    pub fn look_to_rh(eye: DVec3, dir: DVec3, up: DVec3) -> Self {
747        glam_assert!(dir.is_normalized());
748        glam_assert!(up.is_normalized());
749        let f = dir;
750        let s = f.cross(up).normalize();
751        let u = s.cross(f);
752
753        Self::from_cols(
754            DVec4::new(s.x, u.x, -f.x, 0.0),
755            DVec4::new(s.y, u.y, -f.y, 0.0),
756            DVec4::new(s.z, u.z, -f.z, 0.0),
757            DVec4::new(-eye.dot(s), -eye.dot(u), eye.dot(f), 1.0),
758        )
759    }
760
761    /// Creates a left-handed view matrix using a camera position, a focal points and an up
762    /// direction.
763    ///
764    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`.
765    ///
766    /// # Panics
767    ///
768    /// Will panic if `up` is not normalized when `glam_assert` is enabled.
769    #[inline]
770    #[must_use]
771    pub fn look_at_lh(eye: DVec3, center: DVec3, up: DVec3) -> Self {
772        Self::look_to_lh(eye, center.sub(eye).normalize(), up)
773    }
774
775    /// Creates a right-handed view matrix using a camera position, a focal point, and an up
776    /// direction.
777    ///
778    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`.
779    ///
780    /// # Panics
781    ///
782    /// Will panic if `up` is not normalized when `glam_assert` is enabled.
783    #[inline]
784    pub fn look_at_rh(eye: DVec3, center: DVec3, up: DVec3) -> Self {
785        Self::look_to_rh(eye, center.sub(eye).normalize(), up)
786    }
787
788    /// Creates a right-handed perspective projection matrix with [-1,1] depth range.
789    ///
790    /// This is the same as the OpenGL `glFrustum` function.
791    ///
792    /// See <https://registry.khronos.org/OpenGL-Refpages/gl2.1/xhtml/glFrustum.xml>
793    #[inline]
794    #[must_use]
795    pub fn frustum_rh_gl(
796        left: f64,
797        right: f64,
798        bottom: f64,
799        top: f64,
800        z_near: f64,
801        z_far: f64,
802    ) -> Self {
803        let inv_width = 1.0 / (right - left);
804        let inv_height = 1.0 / (top - bottom);
805        let inv_depth = 1.0 / (z_far - z_near);
806        let a = (right + left) * inv_width;
807        let b = (top + bottom) * inv_height;
808        let c = -(z_far + z_near) * inv_depth;
809        let d = -(2.0 * z_far * z_near) * inv_depth;
810        let two_z_near = 2.0 * z_near;
811        Self::from_cols(
812            DVec4::new(two_z_near * inv_width, 0.0, 0.0, 0.0),
813            DVec4::new(0.0, two_z_near * inv_height, 0.0, 0.0),
814            DVec4::new(a, b, c, -1.0),
815            DVec4::new(0.0, 0.0, d, 0.0),
816        )
817    }
818
819    /// Creates a left-handed perspective projection matrix with `[0,1]` depth range.
820    ///
821    /// # Panics
822    ///
823    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
824    /// enabled.
825    #[inline]
826    #[must_use]
827    pub fn frustum_lh(
828        left: f64,
829        right: f64,
830        bottom: f64,
831        top: f64,
832        z_near: f64,
833        z_far: f64,
834    ) -> Self {
835        glam_assert!(z_near > 0.0 && z_far > 0.0);
836        let inv_width = 1.0 / (right - left);
837        let inv_height = 1.0 / (top - bottom);
838        let inv_depth = 1.0 / (z_far - z_near);
839        let a = (right + left) * inv_width;
840        let b = (top + bottom) * inv_height;
841        let c = z_far * inv_depth;
842        let d = -(z_far * z_near) * inv_depth;
843        let two_z_near = 2.0 * z_near;
844        Self::from_cols(
845            DVec4::new(two_z_near * inv_width, 0.0, 0.0, 0.0),
846            DVec4::new(0.0, two_z_near * inv_height, 0.0, 0.0),
847            DVec4::new(a, b, c, 1.0),
848            DVec4::new(0.0, 0.0, d, 0.0),
849        )
850    }
851
852    /// Creates a right-handed perspective projection matrix with `[0,1]` depth range.
853    ///
854    /// # Panics
855    ///
856    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
857    /// enabled.
858    #[inline]
859    #[must_use]
860    pub fn frustum_rh(
861        left: f64,
862        right: f64,
863        bottom: f64,
864        top: f64,
865        z_near: f64,
866        z_far: f64,
867    ) -> Self {
868        glam_assert!(z_near > 0.0 && z_far > 0.0);
869        let inv_width = 1.0 / (right - left);
870        let inv_height = 1.0 / (top - bottom);
871        let inv_depth = 1.0 / (z_far - z_near);
872        let a = (right + left) * inv_width;
873        let b = (top + bottom) * inv_height;
874        let c = -z_far * inv_depth;
875        let d = -(z_far * z_near) * inv_depth;
876        let two_z_near = 2.0 * z_near;
877        Self::from_cols(
878            DVec4::new(two_z_near * inv_width, 0.0, 0.0, 0.0),
879            DVec4::new(0.0, two_z_near * inv_height, 0.0, 0.0),
880            DVec4::new(a, b, c, -1.0),
881            DVec4::new(0.0, 0.0, d, 0.0),
882        )
883    }
884
885    /// Creates a right-handed perspective projection matrix with `[-1,1]` depth range.
886    ///
887    /// Useful to map the standard right-handed coordinate system into what OpenGL expects.
888    ///
889    /// This is the same as the OpenGL `gluPerspective` function.
890    /// See <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml>
891    #[inline]
892    #[must_use]
893    pub fn perspective_rh_gl(
894        fov_y_radians: f64,
895        aspect_ratio: f64,
896        z_near: f64,
897        z_far: f64,
898    ) -> Self {
899        let inv_length = 1.0 / (z_near - z_far);
900        let f = 1.0 / math::tan(0.5 * fov_y_radians);
901        let a = f / aspect_ratio;
902        let b = (z_near + z_far) * inv_length;
903        let c = (2.0 * z_near * z_far) * inv_length;
904        Self::from_cols(
905            DVec4::new(a, 0.0, 0.0, 0.0),
906            DVec4::new(0.0, f, 0.0, 0.0),
907            DVec4::new(0.0, 0.0, b, -1.0),
908            DVec4::new(0.0, 0.0, c, 0.0),
909        )
910    }
911
912    /// Creates a left-handed perspective projection matrix with `[0,1]` depth range.
913    ///
914    /// Useful to map the standard left-handed coordinate system into what WebGPU/Metal/Direct3D expect.
915    ///
916    /// # Panics
917    ///
918    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
919    /// enabled.
920    #[inline]
921    #[must_use]
922    pub fn perspective_lh(fov_y_radians: f64, aspect_ratio: f64, z_near: f64, z_far: f64) -> Self {
923        glam_assert!(z_near > 0.0 && z_far > 0.0);
924        let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
925        let h = cos_fov / sin_fov;
926        let w = h / aspect_ratio;
927        let r = z_far / (z_far - z_near);
928        Self::from_cols(
929            DVec4::new(w, 0.0, 0.0, 0.0),
930            DVec4::new(0.0, h, 0.0, 0.0),
931            DVec4::new(0.0, 0.0, r, 1.0),
932            DVec4::new(0.0, 0.0, -r * z_near, 0.0),
933        )
934    }
935
936    /// Creates a right-handed perspective projection matrix with `[0,1]` depth range.
937    ///
938    /// Useful to map the standard right-handed coordinate system into what WebGPU/Metal/Direct3D expect.
939    ///
940    /// # Panics
941    ///
942    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
943    /// enabled.
944    #[inline]
945    #[must_use]
946    pub fn perspective_rh(fov_y_radians: f64, aspect_ratio: f64, z_near: f64, z_far: f64) -> Self {
947        glam_assert!(z_near > 0.0 && z_far > 0.0);
948        let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
949        let h = cos_fov / sin_fov;
950        let w = h / aspect_ratio;
951        let r = z_far / (z_near - z_far);
952        Self::from_cols(
953            DVec4::new(w, 0.0, 0.0, 0.0),
954            DVec4::new(0.0, h, 0.0, 0.0),
955            DVec4::new(0.0, 0.0, r, -1.0),
956            DVec4::new(0.0, 0.0, r * z_near, 0.0),
957        )
958    }
959
960    /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range.
961    ///
962    /// Like `perspective_lh`, but with an infinite value for `z_far`.
963    /// The result is that points near `z_near` are mapped to depth `0`, and as they move towards infinity the depth approaches `1`.
964    ///
965    /// # Panics
966    ///
967    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
968    /// enabled.
969    #[inline]
970    #[must_use]
971    pub fn perspective_infinite_lh(fov_y_radians: f64, aspect_ratio: f64, z_near: f64) -> Self {
972        glam_assert!(z_near > 0.0);
973        let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
974        let h = cos_fov / sin_fov;
975        let w = h / aspect_ratio;
976        Self::from_cols(
977            DVec4::new(w, 0.0, 0.0, 0.0),
978            DVec4::new(0.0, h, 0.0, 0.0),
979            DVec4::new(0.0, 0.0, 1.0, 1.0),
980            DVec4::new(0.0, 0.0, -z_near, 0.0),
981        )
982    }
983
984    /// Creates an infinite reverse left-handed perspective projection matrix with `[0,1]` depth range.
985    ///
986    /// Similar to `perspective_infinite_lh`, but maps `Z = z_near` to a depth of `1` and `Z = infinity` to a depth of `0`.
987    ///
988    /// # Panics
989    ///
990    /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
991    #[inline]
992    #[must_use]
993    pub fn perspective_infinite_reverse_lh(
994        fov_y_radians: f64,
995        aspect_ratio: f64,
996        z_near: f64,
997    ) -> Self {
998        glam_assert!(z_near > 0.0);
999        let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
1000        let h = cos_fov / sin_fov;
1001        let w = h / aspect_ratio;
1002        Self::from_cols(
1003            DVec4::new(w, 0.0, 0.0, 0.0),
1004            DVec4::new(0.0, h, 0.0, 0.0),
1005            DVec4::new(0.0, 0.0, 0.0, 1.0),
1006            DVec4::new(0.0, 0.0, z_near, 0.0),
1007        )
1008    }
1009
1010    /// Creates an infinite right-handed perspective projection matrix with `[0,1]` depth range.
1011    ///
1012    /// Like `perspective_rh`, but with an infinite value for `z_far`.
1013    /// The result is that points near `z_near` are mapped to depth `0`, and as they move towards infinity the depth approaches `1`.
1014    ///
1015    /// # Panics
1016    ///
1017    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
1018    /// enabled.
1019    #[inline]
1020    #[must_use]
1021    pub fn perspective_infinite_rh(fov_y_radians: f64, aspect_ratio: f64, z_near: f64) -> Self {
1022        glam_assert!(z_near > 0.0);
1023        let f = 1.0 / math::tan(0.5 * fov_y_radians);
1024        Self::from_cols(
1025            DVec4::new(f / aspect_ratio, 0.0, 0.0, 0.0),
1026            DVec4::new(0.0, f, 0.0, 0.0),
1027            DVec4::new(0.0, 0.0, -1.0, -1.0),
1028            DVec4::new(0.0, 0.0, -z_near, 0.0),
1029        )
1030    }
1031
1032    /// Creates an infinite reverse right-handed perspective projection matrix with `[0,1]` depth range.
1033    ///
1034    /// Similar to `perspective_infinite_rh`, but maps `Z = z_near` to a depth of `1` and `Z = infinity` to a depth of `0`.
1035    ///
1036    /// # Panics
1037    ///
1038    /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
1039    #[inline]
1040    #[must_use]
1041    pub fn perspective_infinite_reverse_rh(
1042        fov_y_radians: f64,
1043        aspect_ratio: f64,
1044        z_near: f64,
1045    ) -> Self {
1046        glam_assert!(z_near > 0.0);
1047        let f = 1.0 / math::tan(0.5 * fov_y_radians);
1048        Self::from_cols(
1049            DVec4::new(f / aspect_ratio, 0.0, 0.0, 0.0),
1050            DVec4::new(0.0, f, 0.0, 0.0),
1051            DVec4::new(0.0, 0.0, 0.0, -1.0),
1052            DVec4::new(0.0, 0.0, z_near, 0.0),
1053        )
1054    }
1055
1056    /// Creates a right-handed orthographic projection matrix with `[-1,1]` depth
1057    /// range.  This is the same as the OpenGL `glOrtho` function in OpenGL.
1058    /// See
1059    /// <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml>
1060    ///
1061    /// Useful to map a right-handed coordinate system to the normalized device coordinates that OpenGL expects.
1062    #[inline]
1063    #[must_use]
1064    pub fn orthographic_rh_gl(
1065        left: f64,
1066        right: f64,
1067        bottom: f64,
1068        top: f64,
1069        near: f64,
1070        far: f64,
1071    ) -> Self {
1072        let a = 2.0 / (right - left);
1073        let b = 2.0 / (top - bottom);
1074        let c = -2.0 / (far - near);
1075        let tx = -(right + left) / (right - left);
1076        let ty = -(top + bottom) / (top - bottom);
1077        let tz = -(far + near) / (far - near);
1078
1079        Self::from_cols(
1080            DVec4::new(a, 0.0, 0.0, 0.0),
1081            DVec4::new(0.0, b, 0.0, 0.0),
1082            DVec4::new(0.0, 0.0, c, 0.0),
1083            DVec4::new(tx, ty, tz, 1.0),
1084        )
1085    }
1086
1087    /// Creates a left-handed orthographic projection matrix with `[0,1]` depth range.
1088    ///
1089    /// Useful to map a left-handed coordinate system to the normalized device coordinates that WebGPU/Direct3D/Metal expect.
1090    #[inline]
1091    #[must_use]
1092    pub fn orthographic_lh(
1093        left: f64,
1094        right: f64,
1095        bottom: f64,
1096        top: f64,
1097        near: f64,
1098        far: f64,
1099    ) -> Self {
1100        let rcp_width = 1.0 / (right - left);
1101        let rcp_height = 1.0 / (top - bottom);
1102        let r = 1.0 / (far - near);
1103        Self::from_cols(
1104            DVec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0),
1105            DVec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0),
1106            DVec4::new(0.0, 0.0, r, 0.0),
1107            DVec4::new(
1108                -(left + right) * rcp_width,
1109                -(top + bottom) * rcp_height,
1110                -r * near,
1111                1.0,
1112            ),
1113        )
1114    }
1115
1116    /// Creates a right-handed orthographic projection matrix with `[0,1]` depth range.
1117    ///
1118    /// Useful to map a right-handed coordinate system to the normalized device coordinates that WebGPU/Direct3D/Metal expect.
1119    #[inline]
1120    #[must_use]
1121    pub fn orthographic_rh(
1122        left: f64,
1123        right: f64,
1124        bottom: f64,
1125        top: f64,
1126        near: f64,
1127        far: f64,
1128    ) -> Self {
1129        let rcp_width = 1.0 / (right - left);
1130        let rcp_height = 1.0 / (top - bottom);
1131        let r = 1.0 / (near - far);
1132        Self::from_cols(
1133            DVec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0),
1134            DVec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0),
1135            DVec4::new(0.0, 0.0, r, 0.0),
1136            DVec4::new(
1137                -(left + right) * rcp_width,
1138                -(top + bottom) * rcp_height,
1139                r * near,
1140                1.0,
1141            ),
1142        )
1143    }
1144
1145    /// Transforms the given 3D vector as a point, applying perspective correction.
1146    ///
1147    /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is `1.0`.
1148    /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`.
1149    ///
1150    /// This method assumes that `self` contains a projective transform.
1151    #[inline]
1152    #[must_use]
1153    pub fn project_point3(&self, rhs: DVec3) -> DVec3 {
1154        let mut res = self.x_axis.mul(rhs.x);
1155        res = self.y_axis.mul(rhs.y).add(res);
1156        res = self.z_axis.mul(rhs.z).add(res);
1157        res = self.w_axis.add(res);
1158        res = res.div(res.w);
1159        res.xyz()
1160    }
1161
1162    /// Transforms the given 3D vector as a point.
1163    ///
1164    /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is
1165    /// `1.0`.
1166    ///
1167    /// This method assumes that `self` contains a valid affine transform. It does not perform
1168    /// a perspective divide, if `self` contains a perspective transform, or if you are unsure,
1169    /// the [`Self::project_point3()`] method should be used instead.
1170    ///
1171    /// # Panics
1172    ///
1173    /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled.
1174    #[inline]
1175    #[must_use]
1176    pub fn transform_point3(&self, rhs: DVec3) -> DVec3 {
1177        glam_assert!(self.row(3).abs_diff_eq(DVec4::W, 1e-6));
1178        let mut res = self.x_axis.mul(rhs.x);
1179        res = self.y_axis.mul(rhs.y).add(res);
1180        res = self.z_axis.mul(rhs.z).add(res);
1181        res = self.w_axis.add(res);
1182        res.xyz()
1183    }
1184
1185    /// Transforms the give 3D vector as a direction.
1186    ///
1187    /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is
1188    /// `0.0`.
1189    ///
1190    /// This method assumes that `self` contains a valid affine transform.
1191    ///
1192    /// # Panics
1193    ///
1194    /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled.
1195    #[inline]
1196    #[must_use]
1197    pub fn transform_vector3(&self, rhs: DVec3) -> DVec3 {
1198        glam_assert!(self.row(3).abs_diff_eq(DVec4::W, 1e-6));
1199        let mut res = self.x_axis.mul(rhs.x);
1200        res = self.y_axis.mul(rhs.y).add(res);
1201        res = self.z_axis.mul(rhs.z).add(res);
1202        res.xyz()
1203    }
1204
1205    /// Transforms a 4D vector.
1206    #[inline]
1207    #[must_use]
1208    pub fn mul_vec4(&self, rhs: DVec4) -> DVec4 {
1209        let mut res = self.x_axis.mul(rhs.x);
1210        res = res.add(self.y_axis.mul(rhs.y));
1211        res = res.add(self.z_axis.mul(rhs.z));
1212        res = res.add(self.w_axis.mul(rhs.w));
1213        res
1214    }
1215
1216    /// Multiplies two 4x4 matrices.
1217    #[inline]
1218    #[must_use]
1219    pub fn mul_mat4(&self, rhs: &Self) -> Self {
1220        self.mul(rhs)
1221    }
1222
1223    /// Adds two 4x4 matrices.
1224    #[inline]
1225    #[must_use]
1226    pub fn add_mat4(&self, rhs: &Self) -> Self {
1227        self.add(rhs)
1228    }
1229
1230    /// Subtracts two 4x4 matrices.
1231    #[inline]
1232    #[must_use]
1233    pub fn sub_mat4(&self, rhs: &Self) -> Self {
1234        self.sub(rhs)
1235    }
1236
1237    /// Multiplies a 4x4 matrix by a scalar.
1238    #[inline]
1239    #[must_use]
1240    pub fn mul_scalar(&self, rhs: f64) -> Self {
1241        Self::from_cols(
1242            self.x_axis.mul(rhs),
1243            self.y_axis.mul(rhs),
1244            self.z_axis.mul(rhs),
1245            self.w_axis.mul(rhs),
1246        )
1247    }
1248
1249    /// Divides a 4x4 matrix by a scalar.
1250    #[inline]
1251    #[must_use]
1252    pub fn div_scalar(&self, rhs: f64) -> Self {
1253        let rhs = DVec4::splat(rhs);
1254        Self::from_cols(
1255            self.x_axis.div(rhs),
1256            self.y_axis.div(rhs),
1257            self.z_axis.div(rhs),
1258            self.w_axis.div(rhs),
1259        )
1260    }
1261
1262    /// Returns true if the absolute difference of all elements between `self` and `rhs`
1263    /// is less than or equal to `max_abs_diff`.
1264    ///
1265    /// This can be used to compare if two matrices contain similar elements. It works best
1266    /// when comparing with a known value. The `max_abs_diff` that should be used used
1267    /// depends on the values being compared against.
1268    ///
1269    /// For more see
1270    /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/).
1271    #[inline]
1272    #[must_use]
1273    pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f64) -> bool {
1274        self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff)
1275            && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff)
1276            && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff)
1277            && self.w_axis.abs_diff_eq(rhs.w_axis, max_abs_diff)
1278    }
1279
1280    /// Takes the absolute value of each element in `self`
1281    #[inline]
1282    #[must_use]
1283    pub fn abs(&self) -> Self {
1284        Self::from_cols(
1285            self.x_axis.abs(),
1286            self.y_axis.abs(),
1287            self.z_axis.abs(),
1288            self.w_axis.abs(),
1289        )
1290    }
1291
1292    #[inline]
1293    pub fn as_mat4(&self) -> Mat4 {
1294        Mat4::from_cols(
1295            self.x_axis.as_vec4(),
1296            self.y_axis.as_vec4(),
1297            self.z_axis.as_vec4(),
1298            self.w_axis.as_vec4(),
1299        )
1300    }
1301}
1302
1303impl Default for DMat4 {
1304    #[inline]
1305    fn default() -> Self {
1306        Self::IDENTITY
1307    }
1308}
1309
1310impl Add for DMat4 {
1311    type Output = Self;
1312    #[inline]
1313    fn add(self, rhs: Self) -> Self {
1314        Self::from_cols(
1315            self.x_axis.add(rhs.x_axis),
1316            self.y_axis.add(rhs.y_axis),
1317            self.z_axis.add(rhs.z_axis),
1318            self.w_axis.add(rhs.w_axis),
1319        )
1320    }
1321}
1322
1323impl Add<&Self> for DMat4 {
1324    type Output = Self;
1325    #[inline]
1326    fn add(self, rhs: &Self) -> Self {
1327        self.add(*rhs)
1328    }
1329}
1330
1331impl Add<&DMat4> for &DMat4 {
1332    type Output = DMat4;
1333    #[inline]
1334    fn add(self, rhs: &DMat4) -> DMat4 {
1335        (*self).add(*rhs)
1336    }
1337}
1338
1339impl Add<DMat4> for &DMat4 {
1340    type Output = DMat4;
1341    #[inline]
1342    fn add(self, rhs: DMat4) -> DMat4 {
1343        (*self).add(rhs)
1344    }
1345}
1346
1347impl AddAssign for DMat4 {
1348    #[inline]
1349    fn add_assign(&mut self, rhs: Self) {
1350        *self = self.add(rhs);
1351    }
1352}
1353
1354impl AddAssign<&Self> for DMat4 {
1355    #[inline]
1356    fn add_assign(&mut self, rhs: &Self) {
1357        self.add_assign(*rhs);
1358    }
1359}
1360
1361impl Sub for DMat4 {
1362    type Output = Self;
1363    #[inline]
1364    fn sub(self, rhs: Self) -> Self {
1365        Self::from_cols(
1366            self.x_axis.sub(rhs.x_axis),
1367            self.y_axis.sub(rhs.y_axis),
1368            self.z_axis.sub(rhs.z_axis),
1369            self.w_axis.sub(rhs.w_axis),
1370        )
1371    }
1372}
1373
1374impl Sub<&Self> for DMat4 {
1375    type Output = Self;
1376    #[inline]
1377    fn sub(self, rhs: &Self) -> Self {
1378        self.sub(*rhs)
1379    }
1380}
1381
1382impl Sub<&DMat4> for &DMat4 {
1383    type Output = DMat4;
1384    #[inline]
1385    fn sub(self, rhs: &DMat4) -> DMat4 {
1386        (*self).sub(*rhs)
1387    }
1388}
1389
1390impl Sub<DMat4> for &DMat4 {
1391    type Output = DMat4;
1392    #[inline]
1393    fn sub(self, rhs: DMat4) -> DMat4 {
1394        (*self).sub(rhs)
1395    }
1396}
1397
1398impl SubAssign for DMat4 {
1399    #[inline]
1400    fn sub_assign(&mut self, rhs: Self) {
1401        *self = self.sub(rhs);
1402    }
1403}
1404
1405impl SubAssign<&Self> for DMat4 {
1406    #[inline]
1407    fn sub_assign(&mut self, rhs: &Self) {
1408        self.sub_assign(*rhs);
1409    }
1410}
1411
1412impl Neg for DMat4 {
1413    type Output = Self;
1414    #[inline]
1415    fn neg(self) -> Self::Output {
1416        Self::from_cols(
1417            self.x_axis.neg(),
1418            self.y_axis.neg(),
1419            self.z_axis.neg(),
1420            self.w_axis.neg(),
1421        )
1422    }
1423}
1424
1425impl Neg for &DMat4 {
1426    type Output = DMat4;
1427    #[inline]
1428    fn neg(self) -> DMat4 {
1429        (*self).neg()
1430    }
1431}
1432
1433impl Mul for DMat4 {
1434    type Output = Self;
1435    #[inline]
1436    fn mul(self, rhs: Self) -> Self {
1437        Self::from_cols(
1438            self.mul(rhs.x_axis),
1439            self.mul(rhs.y_axis),
1440            self.mul(rhs.z_axis),
1441            self.mul(rhs.w_axis),
1442        )
1443    }
1444}
1445
1446impl Mul<&Self> for DMat4 {
1447    type Output = Self;
1448    #[inline]
1449    fn mul(self, rhs: &Self) -> Self {
1450        self.mul(*rhs)
1451    }
1452}
1453
1454impl Mul<&DMat4> for &DMat4 {
1455    type Output = DMat4;
1456    #[inline]
1457    fn mul(self, rhs: &DMat4) -> DMat4 {
1458        (*self).mul(*rhs)
1459    }
1460}
1461
1462impl Mul<DMat4> for &DMat4 {
1463    type Output = DMat4;
1464    #[inline]
1465    fn mul(self, rhs: DMat4) -> DMat4 {
1466        (*self).mul(rhs)
1467    }
1468}
1469
1470impl MulAssign for DMat4 {
1471    #[inline]
1472    fn mul_assign(&mut self, rhs: Self) {
1473        *self = self.mul(rhs);
1474    }
1475}
1476
1477impl MulAssign<&Self> for DMat4 {
1478    #[inline]
1479    fn mul_assign(&mut self, rhs: &Self) {
1480        self.mul_assign(*rhs);
1481    }
1482}
1483
1484impl Mul<DVec4> for DMat4 {
1485    type Output = DVec4;
1486    #[inline]
1487    fn mul(self, rhs: DVec4) -> Self::Output {
1488        self.mul_vec4(rhs)
1489    }
1490}
1491
1492impl Mul<&DVec4> for DMat4 {
1493    type Output = DVec4;
1494    #[inline]
1495    fn mul(self, rhs: &DVec4) -> DVec4 {
1496        self.mul(*rhs)
1497    }
1498}
1499
1500impl Mul<&DVec4> for &DMat4 {
1501    type Output = DVec4;
1502    #[inline]
1503    fn mul(self, rhs: &DVec4) -> DVec4 {
1504        (*self).mul(*rhs)
1505    }
1506}
1507
1508impl Mul<DVec4> for &DMat4 {
1509    type Output = DVec4;
1510    #[inline]
1511    fn mul(self, rhs: DVec4) -> DVec4 {
1512        (*self).mul(rhs)
1513    }
1514}
1515
1516impl Mul<DMat4> for f64 {
1517    type Output = DMat4;
1518    #[inline]
1519    fn mul(self, rhs: DMat4) -> Self::Output {
1520        rhs.mul_scalar(self)
1521    }
1522}
1523
1524impl Mul<&DMat4> for f64 {
1525    type Output = DMat4;
1526    #[inline]
1527    fn mul(self, rhs: &DMat4) -> DMat4 {
1528        self.mul(*rhs)
1529    }
1530}
1531
1532impl Mul<&DMat4> for &f64 {
1533    type Output = DMat4;
1534    #[inline]
1535    fn mul(self, rhs: &DMat4) -> DMat4 {
1536        (*self).mul(*rhs)
1537    }
1538}
1539
1540impl Mul<DMat4> for &f64 {
1541    type Output = DMat4;
1542    #[inline]
1543    fn mul(self, rhs: DMat4) -> DMat4 {
1544        (*self).mul(rhs)
1545    }
1546}
1547
1548impl Mul<f64> for DMat4 {
1549    type Output = Self;
1550    #[inline]
1551    fn mul(self, rhs: f64) -> Self {
1552        self.mul_scalar(rhs)
1553    }
1554}
1555
1556impl Mul<&f64> for DMat4 {
1557    type Output = Self;
1558    #[inline]
1559    fn mul(self, rhs: &f64) -> Self {
1560        self.mul(*rhs)
1561    }
1562}
1563
1564impl Mul<&f64> for &DMat4 {
1565    type Output = DMat4;
1566    #[inline]
1567    fn mul(self, rhs: &f64) -> DMat4 {
1568        (*self).mul(*rhs)
1569    }
1570}
1571
1572impl Mul<f64> for &DMat4 {
1573    type Output = DMat4;
1574    #[inline]
1575    fn mul(self, rhs: f64) -> DMat4 {
1576        (*self).mul(rhs)
1577    }
1578}
1579
1580impl MulAssign<f64> for DMat4 {
1581    #[inline]
1582    fn mul_assign(&mut self, rhs: f64) {
1583        *self = self.mul(rhs);
1584    }
1585}
1586
1587impl MulAssign<&f64> for DMat4 {
1588    #[inline]
1589    fn mul_assign(&mut self, rhs: &f64) {
1590        self.mul_assign(*rhs);
1591    }
1592}
1593
1594impl Div<DMat4> for f64 {
1595    type Output = DMat4;
1596    #[inline]
1597    fn div(self, rhs: DMat4) -> Self::Output {
1598        rhs.div_scalar(self)
1599    }
1600}
1601
1602impl Div<&DMat4> for f64 {
1603    type Output = DMat4;
1604    #[inline]
1605    fn div(self, rhs: &DMat4) -> DMat4 {
1606        self.div(*rhs)
1607    }
1608}
1609
1610impl Div<&DMat4> for &f64 {
1611    type Output = DMat4;
1612    #[inline]
1613    fn div(self, rhs: &DMat4) -> DMat4 {
1614        (*self).div(*rhs)
1615    }
1616}
1617
1618impl Div<DMat4> for &f64 {
1619    type Output = DMat4;
1620    #[inline]
1621    fn div(self, rhs: DMat4) -> DMat4 {
1622        (*self).div(rhs)
1623    }
1624}
1625
1626impl Div<f64> for DMat4 {
1627    type Output = Self;
1628    #[inline]
1629    fn div(self, rhs: f64) -> Self {
1630        self.div_scalar(rhs)
1631    }
1632}
1633
1634impl Div<&f64> for DMat4 {
1635    type Output = Self;
1636    #[inline]
1637    fn div(self, rhs: &f64) -> Self {
1638        self.div(*rhs)
1639    }
1640}
1641
1642impl Div<&f64> for &DMat4 {
1643    type Output = DMat4;
1644    #[inline]
1645    fn div(self, rhs: &f64) -> DMat4 {
1646        (*self).div(*rhs)
1647    }
1648}
1649
1650impl Div<f64> for &DMat4 {
1651    type Output = DMat4;
1652    #[inline]
1653    fn div(self, rhs: f64) -> DMat4 {
1654        (*self).div(rhs)
1655    }
1656}
1657
1658impl DivAssign<f64> for DMat4 {
1659    #[inline]
1660    fn div_assign(&mut self, rhs: f64) {
1661        *self = self.div(rhs);
1662    }
1663}
1664
1665impl DivAssign<&f64> for DMat4 {
1666    #[inline]
1667    fn div_assign(&mut self, rhs: &f64) {
1668        self.div_assign(*rhs);
1669    }
1670}
1671
1672impl Sum<Self> for DMat4 {
1673    fn sum<I>(iter: I) -> Self
1674    where
1675        I: Iterator<Item = Self>,
1676    {
1677        iter.fold(Self::ZERO, Self::add)
1678    }
1679}
1680
1681impl<'a> Sum<&'a Self> for DMat4 {
1682    fn sum<I>(iter: I) -> Self
1683    where
1684        I: Iterator<Item = &'a Self>,
1685    {
1686        iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
1687    }
1688}
1689
1690impl Product for DMat4 {
1691    fn product<I>(iter: I) -> Self
1692    where
1693        I: Iterator<Item = Self>,
1694    {
1695        iter.fold(Self::IDENTITY, Self::mul)
1696    }
1697}
1698
1699impl<'a> Product<&'a Self> for DMat4 {
1700    fn product<I>(iter: I) -> Self
1701    where
1702        I: Iterator<Item = &'a Self>,
1703    {
1704        iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
1705    }
1706}
1707
1708impl PartialEq for DMat4 {
1709    #[inline]
1710    fn eq(&self, rhs: &Self) -> bool {
1711        self.x_axis.eq(&rhs.x_axis)
1712            && self.y_axis.eq(&rhs.y_axis)
1713            && self.z_axis.eq(&rhs.z_axis)
1714            && self.w_axis.eq(&rhs.w_axis)
1715    }
1716}
1717
1718impl AsRef<[f64; 16]> for DMat4 {
1719    #[inline]
1720    fn as_ref(&self) -> &[f64; 16] {
1721        unsafe { &*(self as *const Self as *const [f64; 16]) }
1722    }
1723}
1724
1725impl AsMut<[f64; 16]> for DMat4 {
1726    #[inline]
1727    fn as_mut(&mut self) -> &mut [f64; 16] {
1728        unsafe { &mut *(self as *mut Self as *mut [f64; 16]) }
1729    }
1730}
1731
1732impl fmt::Debug for DMat4 {
1733    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1734        fmt.debug_struct(stringify!(DMat4))
1735            .field("x_axis", &self.x_axis)
1736            .field("y_axis", &self.y_axis)
1737            .field("z_axis", &self.z_axis)
1738            .field("w_axis", &self.w_axis)
1739            .finish()
1740    }
1741}
1742
1743impl fmt::Display for DMat4 {
1744    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1745        if let Some(p) = f.precision() {
1746            write!(
1747                f,
1748                "[{:.*}, {:.*}, {:.*}, {:.*}]",
1749                p, self.x_axis, p, self.y_axis, p, self.z_axis, p, self.w_axis
1750            )
1751        } else {
1752            write!(
1753                f,
1754                "[{}, {}, {}, {}]",
1755                self.x_axis, self.y_axis, self.z_axis, self.w_axis
1756            )
1757        }
1758    }
1759}