glam/f32/sse2/
mat4.rs

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