Skip to main content

glam/f32/sse2/
mat4.rs

1// Generated from mat.rs.tera template. Edit the template, not the generated file.
2
3#[cfg(feature = "f64")]
4use crate::DMat4;
5
6use crate::{
7    euler::{FromEuler, ToEuler},
8    f32::math,
9    sse2::*,
10    swizzles::*,
11    EulerRot, Mat3, Mat3A, Quat, Vec3, Vec3A, Vec4,
12};
13use core::fmt;
14use core::iter::{Product, Sum};
15use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
16
17#[cfg(target_arch = "x86")]
18use core::arch::x86::*;
19#[cfg(target_arch = "x86_64")]
20use core::arch::x86_64::*;
21
22#[cfg(feature = "zerocopy")]
23use zerocopy_derive::*;
24
25/// Creates a 4x4 matrix from four column vectors.
26#[inline(always)]
27#[must_use]
28pub const fn mat4(x_axis: Vec4, y_axis: Vec4, z_axis: Vec4, w_axis: Vec4) -> Mat4 {
29    Mat4::from_cols(x_axis, y_axis, z_axis, w_axis)
30}
31
32/// A 4x4 column major matrix.
33///
34/// If you are primarily dealing with 3D affine transformations
35/// considering using [`Affine3A`](crate::Affine3A) which is faster than a 4x4 matrix
36/// for some affine operations.
37///
38/// Affine transformations including 3D translation, rotation and scale can be created
39/// using methods such as [`Self::from_translation()`], [`Self::from_quat()`],
40/// [`Self::from_scale()`] and [`Self::from_scale_rotation_translation()`].
41///
42/// The [`Self::transform_point3()`] and [`Self::transform_vector3()`] convenience methods
43/// are provided for performing affine transformations on 3D vectors and points. These
44/// multiply 3D inputs as 4D vectors with an implicit `w` value of `1` for points and `0`
45/// for vectors respectively. These methods assume that `Self` contains a valid affine
46/// transform.
47#[derive(Clone, Copy)]
48#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
49#[cfg_attr(
50    feature = "zerocopy",
51    derive(FromBytes, Immutable, IntoBytes, KnownLayout)
52)]
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 matrics from a 3x3 matrix (expressing scale, shear and
306    /// rotation) and a translation vector.
307    ///
308    /// Equivalent to `Mat4::from_translation(translation) * Mat4::from_mat3(mat3)`
309    #[inline]
310    #[must_use]
311    pub fn from_mat3_translation(mat3: Mat3, translation: Vec3) -> Self {
312        Self::from_cols(
313            Vec4::from((mat3.x_axis, 0.0)),
314            Vec4::from((mat3.y_axis, 0.0)),
315            Vec4::from((mat3.z_axis, 0.0)),
316            Vec4::from((translation, 1.0)),
317        )
318    }
319
320    /// Creates an affine transformation matrix from the given 3x3 linear transformation
321    /// matrix.
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_mat3a(m: Mat3A) -> Self {
328        Self::from_cols(
329            Vec4::from((m.x_axis, 0.0)),
330            Vec4::from((m.y_axis, 0.0)),
331            Vec4::from((m.z_axis, 0.0)),
332            Vec4::W,
333        )
334    }
335
336    /// Creates an affine transformation matrix from the given 3D `translation`.
337    ///
338    /// The resulting matrix can be used to transform 3D points and vectors. See
339    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
340    #[inline]
341    #[must_use]
342    pub fn from_translation(translation: Vec3) -> Self {
343        Self::from_cols(
344            Vec4::X,
345            Vec4::Y,
346            Vec4::Z,
347            Vec4::new(translation.x, translation.y, translation.z, 1.0),
348        )
349    }
350
351    /// Creates an affine transformation matrix containing a 3D rotation around a normalized
352    /// rotation `axis` of `angle` (in radians).
353    ///
354    /// The resulting matrix can be used to transform 3D points and vectors. See
355    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
356    ///
357    /// # Panics
358    ///
359    /// Will panic if `axis` is not normalized when `glam_assert` is enabled.
360    #[inline]
361    #[must_use]
362    pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self {
363        glam_assert!(axis.is_normalized());
364
365        let (sin, cos) = math::sin_cos(angle);
366        let axis_sin = axis.mul(sin);
367        let axis_sq = axis.mul(axis);
368        let omc = 1.0 - cos;
369        let xyomc = axis.x * axis.y * omc;
370        let xzomc = axis.x * axis.z * omc;
371        let yzomc = axis.y * axis.z * omc;
372        Self::from_cols(
373            Vec4::new(
374                axis_sq.x * omc + cos,
375                xyomc + axis_sin.z,
376                xzomc - axis_sin.y,
377                0.0,
378            ),
379            Vec4::new(
380                xyomc - axis_sin.z,
381                axis_sq.y * omc + cos,
382                yzomc + axis_sin.x,
383                0.0,
384            ),
385            Vec4::new(
386                xzomc + axis_sin.y,
387                yzomc - axis_sin.x,
388                axis_sq.z * omc + cos,
389                0.0,
390            ),
391            Vec4::W,
392        )
393    }
394
395    /// Creates a affine transformation matrix containing a rotation from the given euler
396    /// rotation sequence and angles (in radians).
397    ///
398    /// The resulting matrix can be used to transform 3D points and vectors. See
399    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
400    #[inline]
401    #[must_use]
402    pub fn from_euler(order: EulerRot, a: f32, b: f32, c: f32) -> Self {
403        Self::from_euler_angles(order, a, b, c)
404    }
405
406    /// Extract Euler angles with the given Euler rotation order.
407    ///
408    /// Note if the upper 3x3 matrix contain scales, shears, or other non-rotation transformations
409    /// then the resulting Euler angles will be ill-defined.
410    ///
411    /// # Panics
412    ///
413    /// Will panic if any column of the upper 3x3 rotation matrix is not normalized when
414    /// `glam_assert` is enabled.
415    #[inline]
416    #[must_use]
417    pub fn to_euler(&self, order: EulerRot) -> (f32, f32, f32) {
418        glam_assert!(
419            self.x_axis.xyz().is_normalized()
420                && self.y_axis.xyz().is_normalized()
421                && self.z_axis.xyz().is_normalized()
422        );
423        self.to_euler_angles(order)
424    }
425
426    /// Creates an affine transformation matrix containing a 3D rotation around the x 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_x(angle: f32) -> Self {
434        let (sina, cosa) = math::sin_cos(angle);
435        Self::from_cols(
436            Vec4::X,
437            Vec4::new(0.0, cosa, sina, 0.0),
438            Vec4::new(0.0, -sina, cosa, 0.0),
439            Vec4::W,
440        )
441    }
442
443    /// Creates an affine transformation matrix containing a 3D rotation around the y axis of
444    /// `angle` (in radians).
445    ///
446    /// The resulting matrix can be used to transform 3D points and vectors. See
447    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
448    #[inline]
449    #[must_use]
450    pub fn from_rotation_y(angle: f32) -> Self {
451        let (sina, cosa) = math::sin_cos(angle);
452        Self::from_cols(
453            Vec4::new(cosa, 0.0, -sina, 0.0),
454            Vec4::Y,
455            Vec4::new(sina, 0.0, cosa, 0.0),
456            Vec4::W,
457        )
458    }
459
460    /// Creates an affine transformation matrix containing a 3D rotation around the z axis of
461    /// `angle` (in radians).
462    ///
463    /// The resulting matrix can be used to transform 3D points and vectors. See
464    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
465    #[inline]
466    #[must_use]
467    pub fn from_rotation_z(angle: f32) -> Self {
468        let (sina, cosa) = math::sin_cos(angle);
469        Self::from_cols(
470            Vec4::new(cosa, sina, 0.0, 0.0),
471            Vec4::new(-sina, cosa, 0.0, 0.0),
472            Vec4::Z,
473            Vec4::W,
474        )
475    }
476
477    /// Creates an affine transformation matrix containing the given 3D non-uniform `scale`.
478    ///
479    /// The resulting matrix can be used to transform 3D points and vectors. See
480    /// [`Self::transform_point3()`] and [`Self::transform_vector3()`].
481    ///
482    /// # Panics
483    ///
484    /// Will panic if all elements of `scale` are zero when `glam_assert` is enabled.
485    #[inline]
486    #[must_use]
487    pub fn from_scale(scale: Vec3) -> Self {
488        // Do not panic as long as any component is non-zero
489        glam_assert!(scale.cmpne(Vec3::ZERO).any());
490
491        Self::from_cols(
492            Vec4::new(scale.x, 0.0, 0.0, 0.0),
493            Vec4::new(0.0, scale.y, 0.0, 0.0),
494            Vec4::new(0.0, 0.0, scale.z, 0.0),
495            Vec4::W,
496        )
497    }
498
499    /// Creates a 4x4 matrix from the first 16 values in `slice`.
500    ///
501    /// # Panics
502    ///
503    /// Panics if `slice` is less than 16 elements long.
504    #[inline]
505    #[must_use]
506    pub const fn from_cols_slice(slice: &[f32]) -> Self {
507        Self::new(
508            slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7],
509            slice[8], slice[9], slice[10], slice[11], slice[12], slice[13], slice[14], slice[15],
510        )
511    }
512
513    /// Writes the columns of `self` to the first 16 elements in `slice`.
514    ///
515    /// # Panics
516    ///
517    /// Panics if `slice` is less than 16 elements long.
518    #[inline]
519    pub fn write_cols_to_slice(&self, slice: &mut [f32]) {
520        slice[0] = self.x_axis.x;
521        slice[1] = self.x_axis.y;
522        slice[2] = self.x_axis.z;
523        slice[3] = self.x_axis.w;
524        slice[4] = self.y_axis.x;
525        slice[5] = self.y_axis.y;
526        slice[6] = self.y_axis.z;
527        slice[7] = self.y_axis.w;
528        slice[8] = self.z_axis.x;
529        slice[9] = self.z_axis.y;
530        slice[10] = self.z_axis.z;
531        slice[11] = self.z_axis.w;
532        slice[12] = self.w_axis.x;
533        slice[13] = self.w_axis.y;
534        slice[14] = self.w_axis.z;
535        slice[15] = self.w_axis.w;
536    }
537
538    /// Returns the matrix column for the given `index`.
539    ///
540    /// # Panics
541    ///
542    /// Panics if `index` is greater than 3.
543    #[inline]
544    #[must_use]
545    pub fn col(&self, index: usize) -> Vec4 {
546        match index {
547            0 => self.x_axis,
548            1 => self.y_axis,
549            2 => self.z_axis,
550            3 => self.w_axis,
551            _ => panic!("index out of bounds"),
552        }
553    }
554
555    /// Returns a mutable reference to the matrix column for the given `index`.
556    ///
557    /// # Panics
558    ///
559    /// Panics if `index` is greater than 3.
560    #[inline]
561    pub fn col_mut(&mut self, index: usize) -> &mut Vec4 {
562        match index {
563            0 => &mut self.x_axis,
564            1 => &mut self.y_axis,
565            2 => &mut self.z_axis,
566            3 => &mut self.w_axis,
567            _ => panic!("index out of bounds"),
568        }
569    }
570
571    /// Returns the matrix row for the given `index`.
572    ///
573    /// # Panics
574    ///
575    /// Panics if `index` is greater than 3.
576    #[inline]
577    #[must_use]
578    pub fn row(&self, index: usize) -> Vec4 {
579        match index {
580            0 => Vec4::new(self.x_axis.x, self.y_axis.x, self.z_axis.x, self.w_axis.x),
581            1 => Vec4::new(self.x_axis.y, self.y_axis.y, self.z_axis.y, self.w_axis.y),
582            2 => Vec4::new(self.x_axis.z, self.y_axis.z, self.z_axis.z, self.w_axis.z),
583            3 => Vec4::new(self.x_axis.w, self.y_axis.w, self.z_axis.w, self.w_axis.w),
584            _ => panic!("index out of bounds"),
585        }
586    }
587
588    /// Returns `true` if, and only if, all elements are finite.
589    /// If any element is either `NaN`, positive or negative infinity, this will return `false`.
590    #[inline]
591    #[must_use]
592    pub fn is_finite(&self) -> bool {
593        self.x_axis.is_finite()
594            && self.y_axis.is_finite()
595            && self.z_axis.is_finite()
596            && self.w_axis.is_finite()
597    }
598
599    /// Returns `true` if any elements are `NaN`.
600    #[inline]
601    #[must_use]
602    pub fn is_nan(&self) -> bool {
603        self.x_axis.is_nan() || self.y_axis.is_nan() || self.z_axis.is_nan() || self.w_axis.is_nan()
604    }
605
606    /// Returns the transpose of `self`.
607    #[inline]
608    #[must_use]
609    pub fn transpose(&self) -> Self {
610        unsafe {
611            // Based on https://github.com/microsoft/DirectXMath `XMMatrixTranspose`
612            let tmp0 = _mm_shuffle_ps(self.x_axis.0, self.y_axis.0, 0b01_00_01_00);
613            let tmp1 = _mm_shuffle_ps(self.x_axis.0, self.y_axis.0, 0b11_10_11_10);
614            let tmp2 = _mm_shuffle_ps(self.z_axis.0, self.w_axis.0, 0b01_00_01_00);
615            let tmp3 = _mm_shuffle_ps(self.z_axis.0, self.w_axis.0, 0b11_10_11_10);
616
617            Self {
618                x_axis: Vec4(_mm_shuffle_ps(tmp0, tmp2, 0b10_00_10_00)),
619                y_axis: Vec4(_mm_shuffle_ps(tmp0, tmp2, 0b11_01_11_01)),
620                z_axis: Vec4(_mm_shuffle_ps(tmp1, tmp3, 0b10_00_10_00)),
621                w_axis: Vec4(_mm_shuffle_ps(tmp1, tmp3, 0b11_01_11_01)),
622            }
623        }
624    }
625
626    /// Returns the diagonal of `self`.
627    #[inline]
628    #[must_use]
629    pub fn diagonal(&self) -> Vec4 {
630        Vec4::new(self.x_axis.x, self.y_axis.y, self.z_axis.z, self.w_axis.w)
631    }
632
633    /// Returns the determinant of `self`.
634    #[must_use]
635    pub fn determinant(&self) -> f32 {
636        unsafe {
637            // Based on https://github.com/g-truc/glm `glm_mat4_determinant_lowp`
638            let swp2a = _mm_shuffle_ps(self.z_axis.0, self.z_axis.0, 0b00_01_01_10);
639            let swp3a = _mm_shuffle_ps(self.w_axis.0, self.w_axis.0, 0b11_10_11_11);
640            let swp2b = _mm_shuffle_ps(self.z_axis.0, self.z_axis.0, 0b11_10_11_11);
641            let swp3b = _mm_shuffle_ps(self.w_axis.0, self.w_axis.0, 0b00_01_01_10);
642            let swp2c = _mm_shuffle_ps(self.z_axis.0, self.z_axis.0, 0b00_00_01_10);
643            let swp3c = _mm_shuffle_ps(self.w_axis.0, self.w_axis.0, 0b01_10_00_00);
644
645            let mula = _mm_mul_ps(swp2a, swp3a);
646            let mulb = _mm_mul_ps(swp2b, swp3b);
647            let mulc = _mm_mul_ps(swp2c, swp3c);
648            let sube = _mm_sub_ps(mula, mulb);
649            let subf = _mm_sub_ps(_mm_movehl_ps(mulc, mulc), mulc);
650
651            let subfaca = _mm_shuffle_ps(sube, sube, 0b10_01_00_00);
652            let swpfaca = _mm_shuffle_ps(self.y_axis.0, self.y_axis.0, 0b00_00_00_01);
653            let mulfaca = _mm_mul_ps(swpfaca, subfaca);
654
655            let subtmpb = _mm_shuffle_ps(sube, subf, 0b00_00_11_01);
656            let subfacb = _mm_shuffle_ps(subtmpb, subtmpb, 0b11_01_01_00);
657            let swpfacb = _mm_shuffle_ps(self.y_axis.0, self.y_axis.0, 0b01_01_10_10);
658            let mulfacb = _mm_mul_ps(swpfacb, subfacb);
659
660            let subres = _mm_sub_ps(mulfaca, mulfacb);
661            let subtmpc = _mm_shuffle_ps(sube, subf, 0b01_00_10_10);
662            let subfacc = _mm_shuffle_ps(subtmpc, subtmpc, 0b11_11_10_00);
663            let swpfacc = _mm_shuffle_ps(self.y_axis.0, self.y_axis.0, 0b10_11_11_11);
664            let mulfacc = _mm_mul_ps(swpfacc, subfacc);
665
666            let addres = _mm_add_ps(subres, mulfacc);
667            let detcof = _mm_mul_ps(addres, _mm_setr_ps(1.0, -1.0, 1.0, -1.0));
668
669            dot4(self.x_axis.0, detcof)
670        }
671    }
672
673    /// If `CHECKED` is true then if the determinant is zero this function will return a tuple
674    /// containing a zero matrix and false. If the determinant is non zero a tuple containing the
675    /// inverted matrix and true is returned.
676    ///
677    /// If `CHECKED` is false then the determinant is not checked and if it is zero the resulting
678    /// inverted matrix will be invalid. Will panic if the determinant of `self` is zero when
679    /// `glam_assert` is enabled.
680    ///
681    /// A tuple containing the inverted matrix and a bool is used instead of an option here as
682    /// regular Rust enums put the discriminant first which can result in a lot of padding if the
683    /// matrix is aligned.
684    #[inline(always)]
685    #[must_use]
686    fn inverse_checked<const CHECKED: bool>(&self) -> (Self, bool) {
687        unsafe {
688            // Based on https://github.com/g-truc/glm `glm_mat4_inverse`
689            let fac0 = {
690                let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b11_11_11_11);
691                let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b10_10_10_10);
692
693                let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b10_10_10_10);
694                let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00);
695                let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00);
696                let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b11_11_11_11);
697
698                let mul00 = _mm_mul_ps(swp00, swp01);
699                let mul01 = _mm_mul_ps(swp02, swp03);
700                _mm_sub_ps(mul00, mul01)
701            };
702            let fac1 = {
703                let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b11_11_11_11);
704                let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b01_01_01_01);
705
706                let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b01_01_01_01);
707                let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00);
708                let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00);
709                let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b11_11_11_11);
710
711                let mul00 = _mm_mul_ps(swp00, swp01);
712                let mul01 = _mm_mul_ps(swp02, swp03);
713                _mm_sub_ps(mul00, mul01)
714            };
715            let fac2 = {
716                let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b10_10_10_10);
717                let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b01_01_01_01);
718
719                let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b01_01_01_01);
720                let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00);
721                let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00);
722                let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b10_10_10_10);
723
724                let mul00 = _mm_mul_ps(swp00, swp01);
725                let mul01 = _mm_mul_ps(swp02, swp03);
726                _mm_sub_ps(mul00, mul01)
727            };
728            let fac3 = {
729                let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b11_11_11_11);
730                let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b00_00_00_00);
731
732                let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b00_00_00_00);
733                let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00);
734                let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00);
735                let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b11_11_11_11);
736
737                let mul00 = _mm_mul_ps(swp00, swp01);
738                let mul01 = _mm_mul_ps(swp02, swp03);
739                _mm_sub_ps(mul00, mul01)
740            };
741            let fac4 = {
742                let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b10_10_10_10);
743                let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b00_00_00_00);
744
745                let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b00_00_00_00);
746                let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00);
747                let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00);
748                let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b10_10_10_10);
749
750                let mul00 = _mm_mul_ps(swp00, swp01);
751                let mul01 = _mm_mul_ps(swp02, swp03);
752                _mm_sub_ps(mul00, mul01)
753            };
754            let fac5 = {
755                let swp0a = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b01_01_01_01);
756                let swp0b = _mm_shuffle_ps(self.w_axis.0, self.z_axis.0, 0b00_00_00_00);
757
758                let swp00 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b00_00_00_00);
759                let swp01 = _mm_shuffle_ps(swp0a, swp0a, 0b10_00_00_00);
760                let swp02 = _mm_shuffle_ps(swp0b, swp0b, 0b10_00_00_00);
761                let swp03 = _mm_shuffle_ps(self.z_axis.0, self.y_axis.0, 0b01_01_01_01);
762
763                let mul00 = _mm_mul_ps(swp00, swp01);
764                let mul01 = _mm_mul_ps(swp02, swp03);
765                _mm_sub_ps(mul00, mul01)
766            };
767            let sign_a = _mm_set_ps(1.0, -1.0, 1.0, -1.0);
768            let sign_b = _mm_set_ps(-1.0, 1.0, -1.0, 1.0);
769
770            let temp0 = _mm_shuffle_ps(self.y_axis.0, self.x_axis.0, 0b00_00_00_00);
771            let vec0 = _mm_shuffle_ps(temp0, temp0, 0b10_10_10_00);
772
773            let temp1 = _mm_shuffle_ps(self.y_axis.0, self.x_axis.0, 0b01_01_01_01);
774            let vec1 = _mm_shuffle_ps(temp1, temp1, 0b10_10_10_00);
775
776            let temp2 = _mm_shuffle_ps(self.y_axis.0, self.x_axis.0, 0b10_10_10_10);
777            let vec2 = _mm_shuffle_ps(temp2, temp2, 0b10_10_10_00);
778
779            let temp3 = _mm_shuffle_ps(self.y_axis.0, self.x_axis.0, 0b11_11_11_11);
780            let vec3 = _mm_shuffle_ps(temp3, temp3, 0b10_10_10_00);
781
782            let mul00 = _mm_mul_ps(vec1, fac0);
783            let mul01 = _mm_mul_ps(vec2, fac1);
784            let mul02 = _mm_mul_ps(vec3, fac2);
785            let sub00 = _mm_sub_ps(mul00, mul01);
786            let add00 = _mm_add_ps(sub00, mul02);
787            let inv0 = _mm_mul_ps(sign_b, add00);
788
789            let mul03 = _mm_mul_ps(vec0, fac0);
790            let mul04 = _mm_mul_ps(vec2, fac3);
791            let mul05 = _mm_mul_ps(vec3, fac4);
792            let sub01 = _mm_sub_ps(mul03, mul04);
793            let add01 = _mm_add_ps(sub01, mul05);
794            let inv1 = _mm_mul_ps(sign_a, add01);
795
796            let mul06 = _mm_mul_ps(vec0, fac1);
797            let mul07 = _mm_mul_ps(vec1, fac3);
798            let mul08 = _mm_mul_ps(vec3, fac5);
799            let sub02 = _mm_sub_ps(mul06, mul07);
800            let add02 = _mm_add_ps(sub02, mul08);
801            let inv2 = _mm_mul_ps(sign_b, add02);
802
803            let mul09 = _mm_mul_ps(vec0, fac2);
804            let mul10 = _mm_mul_ps(vec1, fac4);
805            let mul11 = _mm_mul_ps(vec2, fac5);
806            let sub03 = _mm_sub_ps(mul09, mul10);
807            let add03 = _mm_add_ps(sub03, mul11);
808            let inv3 = _mm_mul_ps(sign_a, add03);
809
810            let row0 = _mm_shuffle_ps(inv0, inv1, 0b00_00_00_00);
811            let row1 = _mm_shuffle_ps(inv2, inv3, 0b00_00_00_00);
812            let row2 = _mm_shuffle_ps(row0, row1, 0b10_00_10_00);
813
814            let dot0 = dot4(self.x_axis.0, row2);
815
816            if CHECKED {
817                if dot0 == 0.0 {
818                    return (Self::ZERO, false);
819                }
820            } else {
821                glam_assert!(dot0 != 0.0);
822            }
823
824            let rcp0 = _mm_set1_ps(dot0.recip());
825
826            (
827                Self {
828                    x_axis: Vec4(_mm_mul_ps(inv0, rcp0)),
829                    y_axis: Vec4(_mm_mul_ps(inv1, rcp0)),
830                    z_axis: Vec4(_mm_mul_ps(inv2, rcp0)),
831                    w_axis: Vec4(_mm_mul_ps(inv3, rcp0)),
832                },
833                true,
834            )
835        }
836    }
837
838    /// Returns the inverse of `self`.
839    ///
840    /// If the matrix is not invertible the returned matrix will be invalid.
841    ///
842    /// # Panics
843    ///
844    /// Will panic if the determinant of `self` is zero when `glam_assert` is enabled.
845    #[must_use]
846    pub fn inverse(&self) -> Self {
847        self.inverse_checked::<false>().0
848    }
849
850    /// Returns the inverse of `self` or `None` if the matrix is not invertible.
851    #[must_use]
852    pub fn try_inverse(&self) -> Option<Self> {
853        let (m, is_valid) = self.inverse_checked::<true>();
854        if is_valid {
855            Some(m)
856        } else {
857            None
858        }
859    }
860
861    /// Returns the inverse of `self` or `Mat4::ZERO` if the matrix is not invertible.
862    #[must_use]
863    pub fn inverse_or_zero(&self) -> Self {
864        self.inverse_checked::<true>().0
865    }
866
867    /// Creates a left-handed view matrix using a camera position, a facing direction and an up
868    /// direction
869    ///
870    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`.
871    ///
872    /// # Panics
873    ///
874    /// Will panic if `dir` or `up` are not normalized when `glam_assert` is enabled.
875    #[deprecated(
876        since = "0.33.1",
877        note = "use the `glam::camera::lh::view::look_to_mat4` function instead"
878    )]
879    #[inline]
880    #[must_use]
881    pub fn look_to_lh(eye: Vec3, dir: Vec3, up: Vec3) -> Self {
882        #[allow(deprecated)]
883        Self::look_to_rh(eye, -dir, up)
884    }
885
886    /// Creates a right-handed view matrix using a camera position, a facing direction, and an up
887    /// direction.
888    ///
889    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`.
890    ///
891    /// # Panics
892    ///
893    /// Will panic if `dir` or `up` are not normalized when `glam_assert` is enabled.
894    #[deprecated(
895        since = "0.33.1",
896        note = "use the `glam::camera::rh::view::look_to_mat4` function instead"
897    )]
898    #[inline]
899    #[must_use]
900    pub fn look_to_rh(eye: Vec3, dir: Vec3, up: Vec3) -> Self {
901        glam_assert!(dir.is_normalized());
902        glam_assert!(up.is_normalized());
903        let f = dir;
904        let s = f.cross(up).normalize();
905        let u = s.cross(f);
906
907        Self::from_cols(
908            Vec4::new(s.x, u.x, -f.x, 0.0),
909            Vec4::new(s.y, u.y, -f.y, 0.0),
910            Vec4::new(s.z, u.z, -f.z, 0.0),
911            Vec4::new(-eye.dot(s), -eye.dot(u), eye.dot(f), 1.0),
912        )
913    }
914
915    /// Creates a left-handed view matrix using a camera position, a focal points and an up
916    /// direction.
917    ///
918    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`.
919    ///
920    /// # Panics
921    ///
922    /// Will panic if `up` is not normalized when `glam_assert` is enabled.
923    #[deprecated(
924        since = "0.33.1",
925        note = "use the `glam::camera::lh::view::look_at_mat4` function instead"
926    )]
927    #[inline]
928    #[must_use]
929    pub fn look_at_lh(eye: Vec3, center: Vec3, up: Vec3) -> Self {
930        #[allow(deprecated)]
931        Self::look_to_lh(eye, center.sub(eye).normalize(), up)
932    }
933
934    /// Creates a right-handed view matrix using a camera position, a focal point, and an up
935    /// direction.
936    ///
937    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`.
938    ///
939    /// # Panics
940    ///
941    /// Will panic if `up` is not normalized when `glam_assert` is enabled.
942    #[deprecated(
943        since = "0.33.1",
944        note = "use the `glam::camera::rh::view::look_at_mat4` function instead"
945    )]
946    #[inline]
947    pub fn look_at_rh(eye: Vec3, center: Vec3, up: Vec3) -> Self {
948        #[allow(deprecated)]
949        Self::look_to_rh(eye, center.sub(eye).normalize(), up)
950    }
951
952    /// Creates a right-handed perspective projection matrix with [-1,1] depth range.
953    ///
954    /// This is the same as the OpenGL `glFrustum` function.
955    ///
956    /// See <https://registry.khronos.org/OpenGL-Refpages/gl2.1/xhtml/glFrustum.xml>
957    #[deprecated(
958        since = "0.33.1",
959        note = "use the `glam::camera::rh::proj::opengl::frustum` function instead"
960    )]
961    #[inline]
962    #[must_use]
963    pub fn frustum_rh_gl(
964        left: f32,
965        right: f32,
966        bottom: f32,
967        top: f32,
968        z_near: f32,
969        z_far: f32,
970    ) -> Self {
971        let inv_width = 1.0 / (right - left);
972        let inv_height = 1.0 / (top - bottom);
973        let inv_depth = 1.0 / (z_far - z_near);
974        let a = (right + left) * inv_width;
975        let b = (top + bottom) * inv_height;
976        let c = -(z_far + z_near) * inv_depth;
977        let d = -(2.0 * z_far * z_near) * inv_depth;
978        let two_z_near = 2.0 * z_near;
979        Self::from_cols(
980            Vec4::new(two_z_near * inv_width, 0.0, 0.0, 0.0),
981            Vec4::new(0.0, two_z_near * inv_height, 0.0, 0.0),
982            Vec4::new(a, b, c, -1.0),
983            Vec4::new(0.0, 0.0, d, 0.0),
984        )
985    }
986
987    /// Creates a left-handed perspective projection matrix with `[0,1]` depth range.
988    ///
989    /// # Panics
990    ///
991    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
992    /// enabled.
993    #[deprecated(
994        since = "0.33.1",
995        note = "use the `glam::camera::lh::proj::directx::frustum` function instead"
996    )]
997    #[inline]
998    #[must_use]
999    pub fn frustum_lh(
1000        left: f32,
1001        right: f32,
1002        bottom: f32,
1003        top: f32,
1004        z_near: f32,
1005        z_far: f32,
1006    ) -> Self {
1007        glam_assert!(z_near > 0.0 && z_far > 0.0);
1008        let inv_width = 1.0 / (right - left);
1009        let inv_height = 1.0 / (top - bottom);
1010        let inv_depth = 1.0 / (z_far - z_near);
1011        let a = (right + left) * inv_width;
1012        let b = (top + bottom) * inv_height;
1013        let c = z_far * inv_depth;
1014        let d = -(z_far * z_near) * inv_depth;
1015        let two_z_near = 2.0 * z_near;
1016        Self::from_cols(
1017            Vec4::new(two_z_near * inv_width, 0.0, 0.0, 0.0),
1018            Vec4::new(0.0, two_z_near * inv_height, 0.0, 0.0),
1019            Vec4::new(a, b, c, 1.0),
1020            Vec4::new(0.0, 0.0, d, 0.0),
1021        )
1022    }
1023
1024    /// Creates a right-handed perspective projection matrix with `[0,1]` depth range.
1025    ///
1026    /// # Panics
1027    ///
1028    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
1029    /// enabled.
1030    #[deprecated(
1031        since = "0.33.1",
1032        note = "use the `glam::camera::rh::proj::directx::frustum` function instead"
1033    )]
1034    #[inline]
1035    #[must_use]
1036    pub fn frustum_rh(
1037        left: f32,
1038        right: f32,
1039        bottom: f32,
1040        top: f32,
1041        z_near: f32,
1042        z_far: f32,
1043    ) -> Self {
1044        glam_assert!(z_near > 0.0 && z_far > 0.0);
1045        let inv_width = 1.0 / (right - left);
1046        let inv_height = 1.0 / (top - bottom);
1047        let inv_depth = 1.0 / (z_far - z_near);
1048        let a = (right + left) * inv_width;
1049        let b = (top + bottom) * inv_height;
1050        let c = -z_far * inv_depth;
1051        let d = -(z_far * z_near) * inv_depth;
1052        let two_z_near = 2.0 * z_near;
1053        Self::from_cols(
1054            Vec4::new(two_z_near * inv_width, 0.0, 0.0, 0.0),
1055            Vec4::new(0.0, two_z_near * inv_height, 0.0, 0.0),
1056            Vec4::new(a, b, c, -1.0),
1057            Vec4::new(0.0, 0.0, d, 0.0),
1058        )
1059    }
1060
1061    /// Creates a right-handed perspective projection matrix with `[-1,1]` depth range.
1062    ///
1063    /// Useful to map the standard right-handed coordinate system into what OpenGL expects.
1064    ///
1065    /// This is the same as the OpenGL `gluPerspective` function.
1066    /// See <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml>
1067    #[deprecated(
1068        since = "0.33.1",
1069        note = "use the `glam::camera::rh::proj::opengl::perspective` function instead"
1070    )]
1071    #[inline]
1072    #[must_use]
1073    pub fn perspective_rh_gl(
1074        fov_y_radians: f32,
1075        aspect_ratio: f32,
1076        z_near: f32,
1077        z_far: f32,
1078    ) -> Self {
1079        let inv_length = 1.0 / (z_near - z_far);
1080        let f = 1.0 / math::tan(0.5 * fov_y_radians);
1081        let a = f / aspect_ratio;
1082        let b = (z_near + z_far) * inv_length;
1083        let c = (2.0 * z_near * z_far) * inv_length;
1084        Self::from_cols(
1085            Vec4::new(a, 0.0, 0.0, 0.0),
1086            Vec4::new(0.0, f, 0.0, 0.0),
1087            Vec4::new(0.0, 0.0, b, -1.0),
1088            Vec4::new(0.0, 0.0, c, 0.0),
1089        )
1090    }
1091
1092    /// Creates a left-handed perspective projection matrix with `[0,1]` depth range.
1093    ///
1094    /// Useful to map the standard left-handed coordinate system into what WebGPU/Metal/Direct3D expect.
1095    ///
1096    /// # Panics
1097    ///
1098    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
1099    /// enabled.
1100    #[deprecated(
1101        since = "0.33.1",
1102        note = "use the `glam::camera::lh::proj::directx::perspective` function instead"
1103    )]
1104    #[inline]
1105    #[must_use]
1106    pub fn perspective_lh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Self {
1107        glam_assert!(z_near > 0.0 && z_far > 0.0);
1108        let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
1109        let h = cos_fov / sin_fov;
1110        let w = h / aspect_ratio;
1111        let r = z_far / (z_far - z_near);
1112        Self::from_cols(
1113            Vec4::new(w, 0.0, 0.0, 0.0),
1114            Vec4::new(0.0, h, 0.0, 0.0),
1115            Vec4::new(0.0, 0.0, r, 1.0),
1116            Vec4::new(0.0, 0.0, -r * z_near, 0.0),
1117        )
1118    }
1119
1120    /// Creates a right-handed perspective projection matrix with `[0,1]` depth range.
1121    ///
1122    /// Useful to map the standard right-handed coordinate system into what WebGPU/Metal/Direct3D expect.
1123    ///
1124    /// # Panics
1125    ///
1126    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
1127    /// enabled.
1128    #[deprecated(
1129        since = "0.33.1",
1130        note = "use the `glam::camera::rh::proj::directx::perspective` function instead"
1131    )]
1132    #[inline]
1133    #[must_use]
1134    pub fn perspective_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Self {
1135        glam_assert!(z_near > 0.0 && z_far > 0.0);
1136        let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
1137        let h = cos_fov / sin_fov;
1138        let w = h / aspect_ratio;
1139        let r = z_far / (z_near - z_far);
1140        Self::from_cols(
1141            Vec4::new(w, 0.0, 0.0, 0.0),
1142            Vec4::new(0.0, h, 0.0, 0.0),
1143            Vec4::new(0.0, 0.0, r, -1.0),
1144            Vec4::new(0.0, 0.0, r * z_near, 0.0),
1145        )
1146    }
1147
1148    /// Creates an infinite left-handed perspective projection matrix with `[0,1]` depth range.
1149    ///
1150    /// Like `perspective_lh`, but with an infinite value for `z_far`.
1151    /// The result is that points near `z_near` are mapped to depth `0`, and as they move towards infinity the depth approaches `1`.
1152    ///
1153    /// # Panics
1154    ///
1155    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
1156    /// enabled.
1157    #[deprecated(
1158        since = "0.33.1",
1159        note = "use the `glam::camera::lh::proj::directx::perspective_infinite` function instead"
1160    )]
1161    #[inline]
1162    #[must_use]
1163    pub fn perspective_infinite_lh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self {
1164        glam_assert!(z_near > 0.0);
1165        let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
1166        let h = cos_fov / sin_fov;
1167        let w = h / aspect_ratio;
1168        Self::from_cols(
1169            Vec4::new(w, 0.0, 0.0, 0.0),
1170            Vec4::new(0.0, h, 0.0, 0.0),
1171            Vec4::new(0.0, 0.0, 1.0, 1.0),
1172            Vec4::new(0.0, 0.0, -z_near, 0.0),
1173        )
1174    }
1175
1176    /// Creates an infinite reverse left-handed perspective projection matrix with `[0,1]` depth range.
1177    ///
1178    /// Similar to `perspective_infinite_lh`, but maps `Z = z_near` to a depth of `1` and `Z = infinity` to a depth of `0`.
1179    ///
1180    /// # Panics
1181    ///
1182    /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
1183    #[deprecated(
1184        since = "0.33.1",
1185        note = "use the `glam::camera::lh::proj::directx::perspective_infinite_reverse` function instead"
1186    )]
1187    #[inline]
1188    #[must_use]
1189    pub fn perspective_infinite_reverse_lh(
1190        fov_y_radians: f32,
1191        aspect_ratio: f32,
1192        z_near: f32,
1193    ) -> Self {
1194        glam_assert!(z_near > 0.0);
1195        let (sin_fov, cos_fov) = math::sin_cos(0.5 * fov_y_radians);
1196        let h = cos_fov / sin_fov;
1197        let w = h / aspect_ratio;
1198        Self::from_cols(
1199            Vec4::new(w, 0.0, 0.0, 0.0),
1200            Vec4::new(0.0, h, 0.0, 0.0),
1201            Vec4::new(0.0, 0.0, 0.0, 1.0),
1202            Vec4::new(0.0, 0.0, z_near, 0.0),
1203        )
1204    }
1205
1206    /// Creates an infinite right-handed perspective projection matrix with `[0,1]` depth range.
1207    ///
1208    /// Like `perspective_rh`, but with an infinite value for `z_far`.
1209    /// The result is that points near `z_near` are mapped to depth `0`, and as they move towards infinity the depth approaches `1`.
1210    ///
1211    /// # Panics
1212    ///
1213    /// Will panic if `z_near` or `z_far` are less than or equal to zero when `glam_assert` is
1214    /// enabled.
1215    #[deprecated(
1216        since = "0.33.1",
1217        note = "use the `glam::camera::rh::proj::directx::perspective_infinite` function instead"
1218    )]
1219    #[inline]
1220    #[must_use]
1221    pub fn perspective_infinite_rh(fov_y_radians: f32, aspect_ratio: f32, z_near: f32) -> Self {
1222        glam_assert!(z_near > 0.0);
1223        let f = 1.0 / math::tan(0.5 * fov_y_radians);
1224        Self::from_cols(
1225            Vec4::new(f / aspect_ratio, 0.0, 0.0, 0.0),
1226            Vec4::new(0.0, f, 0.0, 0.0),
1227            Vec4::new(0.0, 0.0, -1.0, -1.0),
1228            Vec4::new(0.0, 0.0, -z_near, 0.0),
1229        )
1230    }
1231
1232    /// Creates an infinite reverse right-handed perspective projection matrix with `[0,1]` depth range.
1233    ///
1234    /// Similar to `perspective_infinite_rh`, but maps `Z = z_near` to a depth of `1` and `Z = infinity` to a depth of `0`.
1235    ///
1236    /// # Panics
1237    ///
1238    /// Will panic if `z_near` is less than or equal to zero when `glam_assert` is enabled.
1239    #[deprecated(
1240        since = "0.33.1",
1241        note = "use the `glam::camera::rh::proj::directx::perspective_infinite_reverse` function instead"
1242    )]
1243    #[inline]
1244    #[must_use]
1245    pub fn perspective_infinite_reverse_rh(
1246        fov_y_radians: f32,
1247        aspect_ratio: f32,
1248        z_near: f32,
1249    ) -> Self {
1250        glam_assert!(z_near > 0.0);
1251        let f = 1.0 / math::tan(0.5 * fov_y_radians);
1252        Self::from_cols(
1253            Vec4::new(f / aspect_ratio, 0.0, 0.0, 0.0),
1254            Vec4::new(0.0, f, 0.0, 0.0),
1255            Vec4::new(0.0, 0.0, 0.0, -1.0),
1256            Vec4::new(0.0, 0.0, z_near, 0.0),
1257        )
1258    }
1259
1260    /// Creates a right-handed orthographic projection matrix with `[-1,1]` depth
1261    /// range.  This is the same as the OpenGL `glOrtho` function in OpenGL.
1262    /// See
1263    /// <https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml>
1264    ///
1265    /// Useful to map a right-handed coordinate system to the normalized device coordinates that OpenGL expects.
1266    #[deprecated(
1267        since = "0.33.1",
1268        note = "use the `glam::camera::rh::proj::opengl::orthographic` function instead"
1269    )]
1270    #[inline]
1271    #[must_use]
1272    pub fn orthographic_rh_gl(
1273        left: f32,
1274        right: f32,
1275        bottom: f32,
1276        top: f32,
1277        near: f32,
1278        far: f32,
1279    ) -> Self {
1280        let a = 2.0 / (right - left);
1281        let b = 2.0 / (top - bottom);
1282        let c = 2.0 / (near - far);
1283        let tx = -(right + left) / (right - left);
1284        let ty = -(top + bottom) / (top - bottom);
1285        let tz = -(far + near) / (far - near);
1286
1287        Self::from_cols(
1288            Vec4::new(a, 0.0, 0.0, 0.0),
1289            Vec4::new(0.0, b, 0.0, 0.0),
1290            Vec4::new(0.0, 0.0, c, 0.0),
1291            Vec4::new(tx, ty, tz, 1.0),
1292        )
1293    }
1294
1295    /// Creates a left-handed orthographic projection matrix with `[0,1]` depth range.
1296    ///
1297    /// Useful to map a left-handed coordinate system to the normalized device coordinates that WebGPU/Direct3D/Metal expect.
1298    #[deprecated(
1299        since = "0.33.1",
1300        note = "use the `glam::camera::lh::proj::directx::orthographic` function instead"
1301    )]
1302    #[inline]
1303    #[must_use]
1304    pub fn orthographic_lh(
1305        left: f32,
1306        right: f32,
1307        bottom: f32,
1308        top: f32,
1309        near: f32,
1310        far: f32,
1311    ) -> Self {
1312        let rcp_width = 1.0 / (right - left);
1313        let rcp_height = 1.0 / (top - bottom);
1314        let r = 1.0 / (far - near);
1315        Self::from_cols(
1316            Vec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0),
1317            Vec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0),
1318            Vec4::new(0.0, 0.0, r, 0.0),
1319            Vec4::new(
1320                -(left + right) * rcp_width,
1321                -(top + bottom) * rcp_height,
1322                -r * near,
1323                1.0,
1324            ),
1325        )
1326    }
1327
1328    /// Creates a right-handed orthographic projection matrix with `[0,1]` depth range.
1329    ///
1330    /// Useful to map a right-handed coordinate system to the normalized device coordinates that WebGPU/Direct3D/Metal expect.
1331    #[deprecated(
1332        since = "0.33.1",
1333        note = "use the `glam::camera::rh::proj::directx::orthographic` function instead"
1334    )]
1335    #[inline]
1336    #[must_use]
1337    pub fn orthographic_rh(
1338        left: f32,
1339        right: f32,
1340        bottom: f32,
1341        top: f32,
1342        near: f32,
1343        far: f32,
1344    ) -> Self {
1345        let rcp_width = 1.0 / (right - left);
1346        let rcp_height = 1.0 / (top - bottom);
1347        let r = 1.0 / (near - far);
1348        Self::from_cols(
1349            Vec4::new(rcp_width + rcp_width, 0.0, 0.0, 0.0),
1350            Vec4::new(0.0, rcp_height + rcp_height, 0.0, 0.0),
1351            Vec4::new(0.0, 0.0, r, 0.0),
1352            Vec4::new(
1353                -(left + right) * rcp_width,
1354                -(top + bottom) * rcp_height,
1355                r * near,
1356                1.0,
1357            ),
1358        )
1359    }
1360
1361    /// Transforms the given 3D vector as a point, applying perspective correction.
1362    ///
1363    /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is `1.0`.
1364    /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`.
1365    ///
1366    /// This method assumes that `self` contains a projective transform.
1367    #[inline]
1368    #[must_use]
1369    pub fn project_point3(&self, rhs: Vec3) -> Vec3 {
1370        let mut res = self.x_axis.mul(rhs.x);
1371        res = self.y_axis.mul(rhs.y).add(res);
1372        res = self.z_axis.mul(rhs.z).add(res);
1373        res = self.w_axis.add(res);
1374        res = res.div(res.w);
1375        res.xyz()
1376    }
1377
1378    /// Transforms the given 3D vector as a point.
1379    ///
1380    /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is
1381    /// `1.0`.
1382    ///
1383    /// This method assumes that `self` contains a valid affine transform. It does not perform
1384    /// a perspective divide, if `self` contains a perspective transform, or if you are unsure,
1385    /// the [`Self::project_point3()`] method should be used instead.
1386    ///
1387    /// # Panics
1388    ///
1389    /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled.
1390    #[inline]
1391    #[must_use]
1392    pub fn transform_point3(&self, rhs: Vec3) -> Vec3 {
1393        glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6));
1394        let mut res = self.x_axis.mul(rhs.x);
1395        res = self.y_axis.mul(rhs.y).add(res);
1396        res = self.z_axis.mul(rhs.z).add(res);
1397        res = self.w_axis.add(res);
1398        res.xyz()
1399    }
1400
1401    /// Transforms the given 3D vector as a direction.
1402    ///
1403    /// This is the equivalent of multiplying the 3D vector as a 4D vector where `w` is
1404    /// `0.0`.
1405    ///
1406    /// This method assumes that `self` contains a valid affine transform.
1407    ///
1408    /// # Panics
1409    ///
1410    /// Will panic if the 3rd row of `self` is not `(0, 0, 0, 1)` when `glam_assert` is enabled.
1411    #[inline]
1412    #[must_use]
1413    pub fn transform_vector3(&self, rhs: Vec3) -> Vec3 {
1414        glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6));
1415        let mut res = self.x_axis.mul(rhs.x);
1416        res = self.y_axis.mul(rhs.y).add(res);
1417        res = self.z_axis.mul(rhs.z).add(res);
1418        res.xyz()
1419    }
1420
1421    /// Transforms the given [`Vec3A`] as a 3D point, applying perspective correction.
1422    ///
1423    /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`.
1424    /// The perspective divide is performed meaning the resulting 3D vector is divided by `w`.
1425    ///
1426    /// This method assumes that `self` contains a projective transform.
1427    #[inline]
1428    #[must_use]
1429    pub fn project_point3a(&self, rhs: Vec3A) -> Vec3A {
1430        let mut res = self.x_axis.mul(rhs.xxxx());
1431        res = self.y_axis.mul(rhs.yyyy()).add(res);
1432        res = self.z_axis.mul(rhs.zzzz()).add(res);
1433        res = self.w_axis.add(res);
1434        res = res.div(res.wwww());
1435        Vec3A::from_vec4(res)
1436    }
1437
1438    /// Transforms the given [`Vec3A`] as 3D point.
1439    ///
1440    /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `1.0`.
1441    #[inline]
1442    #[must_use]
1443    pub fn transform_point3a(&self, rhs: Vec3A) -> Vec3A {
1444        glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6));
1445        let mut res = self.x_axis.mul(rhs.xxxx());
1446        res = self.y_axis.mul(rhs.yyyy()).add(res);
1447        res = self.z_axis.mul(rhs.zzzz()).add(res);
1448        res = self.w_axis.add(res);
1449        Vec3A::from_vec4(res)
1450    }
1451
1452    /// Transforms the give [`Vec3A`] as 3D vector.
1453    ///
1454    /// This is the equivalent of multiplying the [`Vec3A`] as a 4D vector where `w` is `0.0`.
1455    #[inline]
1456    #[must_use]
1457    pub fn transform_vector3a(&self, rhs: Vec3A) -> Vec3A {
1458        glam_assert!(self.row(3).abs_diff_eq(Vec4::W, 1e-6));
1459        let mut res = self.x_axis.mul(rhs.xxxx());
1460        res = self.y_axis.mul(rhs.yyyy()).add(res);
1461        res = self.z_axis.mul(rhs.zzzz()).add(res);
1462        Vec3A::from_vec4(res)
1463    }
1464
1465    /// Transforms a 4D vector.
1466    #[inline]
1467    #[must_use]
1468    pub fn mul_vec4(&self, rhs: Vec4) -> Vec4 {
1469        let mut res = self.x_axis.mul(rhs.xxxx());
1470        res = res.add(self.y_axis.mul(rhs.yyyy()));
1471        res = res.add(self.z_axis.mul(rhs.zzzz()));
1472        res = res.add(self.w_axis.mul(rhs.wwww()));
1473        res
1474    }
1475
1476    /// Transforms a 4D vector by the transpose of `self`.
1477    #[inline]
1478    #[must_use]
1479    pub fn mul_transpose_vec4(&self, rhs: Vec4) -> Vec4 {
1480        Vec4::new(
1481            self.x_axis.dot(rhs),
1482            self.y_axis.dot(rhs),
1483            self.z_axis.dot(rhs),
1484            self.w_axis.dot(rhs),
1485        )
1486    }
1487
1488    /// Multiplies two 4x4 matrices.
1489    #[inline]
1490    #[must_use]
1491    pub fn mul_mat4(&self, rhs: &Self) -> Self {
1492        self.mul(rhs)
1493    }
1494
1495    /// Adds two 4x4 matrices.
1496    #[inline]
1497    #[must_use]
1498    pub fn add_mat4(&self, rhs: &Self) -> Self {
1499        self.add(rhs)
1500    }
1501
1502    /// Subtracts two 4x4 matrices.
1503    #[inline]
1504    #[must_use]
1505    pub fn sub_mat4(&self, rhs: &Self) -> Self {
1506        self.sub(rhs)
1507    }
1508
1509    /// Multiplies a 4x4 matrix by a scalar.
1510    #[inline]
1511    #[must_use]
1512    pub fn mul_scalar(&self, rhs: f32) -> Self {
1513        Self::from_cols(
1514            self.x_axis.mul(rhs),
1515            self.y_axis.mul(rhs),
1516            self.z_axis.mul(rhs),
1517            self.w_axis.mul(rhs),
1518        )
1519    }
1520
1521    /// Multiply `self` by a scaling vector `scale`.
1522    /// This is faster than creating a whole diagonal scaling matrix and then multiplying that.
1523    /// This operation is commutative.
1524    #[inline]
1525    #[must_use]
1526    pub fn mul_diagonal_scale(&self, scale: Vec4) -> Self {
1527        Self::from_cols(
1528            self.x_axis * scale.x,
1529            self.y_axis * scale.y,
1530            self.z_axis * scale.z,
1531            self.w_axis * scale.w,
1532        )
1533    }
1534
1535    /// Divides a 4x4 matrix by a scalar.
1536    #[inline]
1537    #[must_use]
1538    pub fn div_scalar(&self, rhs: f32) -> Self {
1539        let rhs = Vec4::splat(rhs);
1540        Self::from_cols(
1541            self.x_axis.div(rhs),
1542            self.y_axis.div(rhs),
1543            self.z_axis.div(rhs),
1544            self.w_axis.div(rhs),
1545        )
1546    }
1547
1548    /// Returns a matrix containing the reciprocal `1.0/n` of each element of `self`.
1549    #[inline]
1550    #[must_use]
1551    pub fn recip(&self) -> Self {
1552        Self::from_cols(
1553            self.x_axis.recip(),
1554            self.y_axis.recip(),
1555            self.z_axis.recip(),
1556            self.w_axis.recip(),
1557        )
1558    }
1559
1560    /// Returns true if the absolute difference of all elements between `self` and `rhs`
1561    /// is less than or equal to `max_abs_diff`.
1562    ///
1563    /// This can be used to compare if two matrices contain similar elements. It works best
1564    /// when comparing with a known value. The `max_abs_diff` that should be used used
1565    /// depends on the values being compared against.
1566    ///
1567    /// For more see
1568    /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/).
1569    #[inline]
1570    #[must_use]
1571    pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool {
1572        self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff)
1573            && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff)
1574            && self.z_axis.abs_diff_eq(rhs.z_axis, max_abs_diff)
1575            && self.w_axis.abs_diff_eq(rhs.w_axis, max_abs_diff)
1576    }
1577
1578    /// Takes the absolute value of each element in `self`
1579    #[inline]
1580    #[must_use]
1581    pub fn abs(&self) -> Self {
1582        Self::from_cols(
1583            self.x_axis.abs(),
1584            self.y_axis.abs(),
1585            self.z_axis.abs(),
1586            self.w_axis.abs(),
1587        )
1588    }
1589
1590    #[cfg(feature = "f64")]
1591    #[inline]
1592    #[must_use]
1593    pub fn as_dmat4(&self) -> DMat4 {
1594        DMat4::from_cols(
1595            self.x_axis.as_dvec4(),
1596            self.y_axis.as_dvec4(),
1597            self.z_axis.as_dvec4(),
1598            self.w_axis.as_dvec4(),
1599        )
1600    }
1601}
1602
1603impl Default for Mat4 {
1604    #[inline]
1605    fn default() -> Self {
1606        Self::IDENTITY
1607    }
1608}
1609
1610impl Add for Mat4 {
1611    type Output = Self;
1612    #[inline]
1613    fn add(self, rhs: Self) -> Self {
1614        Self::from_cols(
1615            self.x_axis.add(rhs.x_axis),
1616            self.y_axis.add(rhs.y_axis),
1617            self.z_axis.add(rhs.z_axis),
1618            self.w_axis.add(rhs.w_axis),
1619        )
1620    }
1621}
1622
1623impl Add<&Self> for Mat4 {
1624    type Output = Self;
1625    #[inline]
1626    fn add(self, rhs: &Self) -> Self {
1627        self.add(*rhs)
1628    }
1629}
1630
1631impl Add<&Mat4> for &Mat4 {
1632    type Output = Mat4;
1633    #[inline]
1634    fn add(self, rhs: &Mat4) -> Mat4 {
1635        (*self).add(*rhs)
1636    }
1637}
1638
1639impl Add<Mat4> for &Mat4 {
1640    type Output = Mat4;
1641    #[inline]
1642    fn add(self, rhs: Mat4) -> Mat4 {
1643        (*self).add(rhs)
1644    }
1645}
1646
1647impl AddAssign for Mat4 {
1648    #[inline]
1649    fn add_assign(&mut self, rhs: Self) {
1650        *self = self.add(rhs);
1651    }
1652}
1653
1654impl AddAssign<&Self> for Mat4 {
1655    #[inline]
1656    fn add_assign(&mut self, rhs: &Self) {
1657        self.add_assign(*rhs);
1658    }
1659}
1660
1661impl Sub for Mat4 {
1662    type Output = Self;
1663    #[inline]
1664    fn sub(self, rhs: Self) -> Self {
1665        Self::from_cols(
1666            self.x_axis.sub(rhs.x_axis),
1667            self.y_axis.sub(rhs.y_axis),
1668            self.z_axis.sub(rhs.z_axis),
1669            self.w_axis.sub(rhs.w_axis),
1670        )
1671    }
1672}
1673
1674impl Sub<&Self> for Mat4 {
1675    type Output = Self;
1676    #[inline]
1677    fn sub(self, rhs: &Self) -> Self {
1678        self.sub(*rhs)
1679    }
1680}
1681
1682impl Sub<&Mat4> for &Mat4 {
1683    type Output = Mat4;
1684    #[inline]
1685    fn sub(self, rhs: &Mat4) -> Mat4 {
1686        (*self).sub(*rhs)
1687    }
1688}
1689
1690impl Sub<Mat4> for &Mat4 {
1691    type Output = Mat4;
1692    #[inline]
1693    fn sub(self, rhs: Mat4) -> Mat4 {
1694        (*self).sub(rhs)
1695    }
1696}
1697
1698impl SubAssign for Mat4 {
1699    #[inline]
1700    fn sub_assign(&mut self, rhs: Self) {
1701        *self = self.sub(rhs);
1702    }
1703}
1704
1705impl SubAssign<&Self> for Mat4 {
1706    #[inline]
1707    fn sub_assign(&mut self, rhs: &Self) {
1708        self.sub_assign(*rhs);
1709    }
1710}
1711
1712impl Neg for Mat4 {
1713    type Output = Self;
1714    #[inline]
1715    fn neg(self) -> Self::Output {
1716        Self::from_cols(
1717            self.x_axis.neg(),
1718            self.y_axis.neg(),
1719            self.z_axis.neg(),
1720            self.w_axis.neg(),
1721        )
1722    }
1723}
1724
1725impl Neg for &Mat4 {
1726    type Output = Mat4;
1727    #[inline]
1728    fn neg(self) -> Mat4 {
1729        (*self).neg()
1730    }
1731}
1732
1733impl Mul for Mat4 {
1734    type Output = Self;
1735    #[inline]
1736    fn mul(self, rhs: Self) -> Self {
1737        Self::from_cols(
1738            self.mul(rhs.x_axis),
1739            self.mul(rhs.y_axis),
1740            self.mul(rhs.z_axis),
1741            self.mul(rhs.w_axis),
1742        )
1743    }
1744}
1745
1746impl Mul<&Self> for Mat4 {
1747    type Output = Self;
1748    #[inline]
1749    fn mul(self, rhs: &Self) -> Self {
1750        self.mul(*rhs)
1751    }
1752}
1753
1754impl Mul<&Mat4> for &Mat4 {
1755    type Output = Mat4;
1756    #[inline]
1757    fn mul(self, rhs: &Mat4) -> Mat4 {
1758        (*self).mul(*rhs)
1759    }
1760}
1761
1762impl Mul<Mat4> for &Mat4 {
1763    type Output = Mat4;
1764    #[inline]
1765    fn mul(self, rhs: Mat4) -> Mat4 {
1766        (*self).mul(rhs)
1767    }
1768}
1769
1770impl MulAssign for Mat4 {
1771    #[inline]
1772    fn mul_assign(&mut self, rhs: Self) {
1773        *self = self.mul(rhs);
1774    }
1775}
1776
1777impl MulAssign<&Self> for Mat4 {
1778    #[inline]
1779    fn mul_assign(&mut self, rhs: &Self) {
1780        self.mul_assign(*rhs);
1781    }
1782}
1783
1784impl Mul<Vec4> for Mat4 {
1785    type Output = Vec4;
1786    #[inline]
1787    fn mul(self, rhs: Vec4) -> Self::Output {
1788        self.mul_vec4(rhs)
1789    }
1790}
1791
1792impl Mul<&Vec4> for Mat4 {
1793    type Output = Vec4;
1794    #[inline]
1795    fn mul(self, rhs: &Vec4) -> Vec4 {
1796        self.mul(*rhs)
1797    }
1798}
1799
1800impl Mul<&Vec4> for &Mat4 {
1801    type Output = Vec4;
1802    #[inline]
1803    fn mul(self, rhs: &Vec4) -> Vec4 {
1804        (*self).mul(*rhs)
1805    }
1806}
1807
1808impl Mul<Vec4> for &Mat4 {
1809    type Output = Vec4;
1810    #[inline]
1811    fn mul(self, rhs: Vec4) -> Vec4 {
1812        (*self).mul(rhs)
1813    }
1814}
1815
1816impl Mul<Mat4> for f32 {
1817    type Output = Mat4;
1818    #[inline]
1819    fn mul(self, rhs: Mat4) -> Self::Output {
1820        rhs.mul_scalar(self)
1821    }
1822}
1823
1824impl Mul<&Mat4> for f32 {
1825    type Output = Mat4;
1826    #[inline]
1827    fn mul(self, rhs: &Mat4) -> Mat4 {
1828        self.mul(*rhs)
1829    }
1830}
1831
1832impl Mul<&Mat4> for &f32 {
1833    type Output = Mat4;
1834    #[inline]
1835    fn mul(self, rhs: &Mat4) -> Mat4 {
1836        (*self).mul(*rhs)
1837    }
1838}
1839
1840impl Mul<Mat4> for &f32 {
1841    type Output = Mat4;
1842    #[inline]
1843    fn mul(self, rhs: Mat4) -> Mat4 {
1844        (*self).mul(rhs)
1845    }
1846}
1847
1848impl Mul<f32> for Mat4 {
1849    type Output = Self;
1850    #[inline]
1851    fn mul(self, rhs: f32) -> Self {
1852        self.mul_scalar(rhs)
1853    }
1854}
1855
1856impl Mul<&f32> for Mat4 {
1857    type Output = Self;
1858    #[inline]
1859    fn mul(self, rhs: &f32) -> Self {
1860        self.mul(*rhs)
1861    }
1862}
1863
1864impl Mul<&f32> for &Mat4 {
1865    type Output = Mat4;
1866    #[inline]
1867    fn mul(self, rhs: &f32) -> Mat4 {
1868        (*self).mul(*rhs)
1869    }
1870}
1871
1872impl Mul<f32> for &Mat4 {
1873    type Output = Mat4;
1874    #[inline]
1875    fn mul(self, rhs: f32) -> Mat4 {
1876        (*self).mul(rhs)
1877    }
1878}
1879
1880impl MulAssign<f32> for Mat4 {
1881    #[inline]
1882    fn mul_assign(&mut self, rhs: f32) {
1883        *self = self.mul(rhs);
1884    }
1885}
1886
1887impl MulAssign<&f32> for Mat4 {
1888    #[inline]
1889    fn mul_assign(&mut self, rhs: &f32) {
1890        self.mul_assign(*rhs);
1891    }
1892}
1893
1894impl Div<Mat4> for f32 {
1895    type Output = Mat4;
1896    #[inline]
1897    fn div(self, rhs: Mat4) -> Self::Output {
1898        Mat4::from_cols(
1899            self.div(rhs.x_axis),
1900            self.div(rhs.y_axis),
1901            self.div(rhs.z_axis),
1902            self.div(rhs.w_axis),
1903        )
1904    }
1905}
1906
1907impl Div<&Mat4> for f32 {
1908    type Output = Mat4;
1909    #[inline]
1910    fn div(self, rhs: &Mat4) -> Mat4 {
1911        self.div(*rhs)
1912    }
1913}
1914
1915impl Div<&Mat4> for &f32 {
1916    type Output = Mat4;
1917    #[inline]
1918    fn div(self, rhs: &Mat4) -> Mat4 {
1919        (*self).div(*rhs)
1920    }
1921}
1922
1923impl Div<Mat4> for &f32 {
1924    type Output = Mat4;
1925    #[inline]
1926    fn div(self, rhs: Mat4) -> Mat4 {
1927        (*self).div(rhs)
1928    }
1929}
1930
1931impl Div<f32> for Mat4 {
1932    type Output = Self;
1933    #[inline]
1934    fn div(self, rhs: f32) -> Self {
1935        self.div_scalar(rhs)
1936    }
1937}
1938
1939impl Div<&f32> for Mat4 {
1940    type Output = Self;
1941    #[inline]
1942    fn div(self, rhs: &f32) -> Self {
1943        self.div(*rhs)
1944    }
1945}
1946
1947impl Div<&f32> for &Mat4 {
1948    type Output = Mat4;
1949    #[inline]
1950    fn div(self, rhs: &f32) -> Mat4 {
1951        (*self).div(*rhs)
1952    }
1953}
1954
1955impl Div<f32> for &Mat4 {
1956    type Output = Mat4;
1957    #[inline]
1958    fn div(self, rhs: f32) -> Mat4 {
1959        (*self).div(rhs)
1960    }
1961}
1962
1963impl DivAssign<f32> for Mat4 {
1964    #[inline]
1965    fn div_assign(&mut self, rhs: f32) {
1966        *self = self.div(rhs);
1967    }
1968}
1969
1970impl DivAssign<&f32> for Mat4 {
1971    #[inline]
1972    fn div_assign(&mut self, rhs: &f32) {
1973        self.div_assign(*rhs);
1974    }
1975}
1976
1977impl Sum<Self> for Mat4 {
1978    fn sum<I>(iter: I) -> Self
1979    where
1980        I: Iterator<Item = Self>,
1981    {
1982        iter.fold(Self::ZERO, Self::add)
1983    }
1984}
1985
1986impl<'a> Sum<&'a Self> for Mat4 {
1987    fn sum<I>(iter: I) -> Self
1988    where
1989        I: Iterator<Item = &'a Self>,
1990    {
1991        iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
1992    }
1993}
1994
1995impl Product for Mat4 {
1996    fn product<I>(iter: I) -> Self
1997    where
1998        I: Iterator<Item = Self>,
1999    {
2000        iter.fold(Self::IDENTITY, Self::mul)
2001    }
2002}
2003
2004impl<'a> Product<&'a Self> for Mat4 {
2005    fn product<I>(iter: I) -> Self
2006    where
2007        I: Iterator<Item = &'a Self>,
2008    {
2009        iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
2010    }
2011}
2012
2013impl PartialEq for Mat4 {
2014    #[inline]
2015    fn eq(&self, rhs: &Self) -> bool {
2016        self.x_axis.eq(&rhs.x_axis)
2017            && self.y_axis.eq(&rhs.y_axis)
2018            && self.z_axis.eq(&rhs.z_axis)
2019            && self.w_axis.eq(&rhs.w_axis)
2020    }
2021}
2022
2023impl AsRef<[f32; 16]> for Mat4 {
2024    #[inline]
2025    fn as_ref(&self) -> &[f32; 16] {
2026        unsafe { &*(self as *const Self as *const [f32; 16]) }
2027    }
2028}
2029
2030impl AsMut<[f32; 16]> for Mat4 {
2031    #[inline]
2032    fn as_mut(&mut self) -> &mut [f32; 16] {
2033        unsafe { &mut *(self as *mut Self as *mut [f32; 16]) }
2034    }
2035}
2036
2037impl fmt::Debug for Mat4 {
2038    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
2039        fmt.debug_struct(stringify!(Mat4))
2040            .field("x_axis", &self.x_axis)
2041            .field("y_axis", &self.y_axis)
2042            .field("z_axis", &self.z_axis)
2043            .field("w_axis", &self.w_axis)
2044            .finish()
2045    }
2046}
2047
2048impl fmt::Display for Mat4 {
2049    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2050        if let Some(p) = f.precision() {
2051            write!(
2052                f,
2053                "[{:.*}, {:.*}, {:.*}, {:.*}]",
2054                p, self.x_axis, p, self.y_axis, p, self.z_axis, p, self.w_axis
2055            )
2056        } else {
2057            write!(
2058                f,
2059                "[{}, {}, {}, {}]",
2060                self.x_axis, self.y_axis, self.z_axis, self.w_axis
2061            )
2062        }
2063    }
2064}