Skip to main content

glam/f64/
dmat4.rs

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