glam/f64/
dmat4.rs

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