Skip to main content

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