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