glam/f32/sse2/
mat4.rs

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