Skip to main content

glam/f32/sse2/
mat4.rs

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