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