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