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