glam/f64/
dmat4.rs

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