glam/f32/sse2/
mat4.rs

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