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