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