Skip to main content

glam/f32/
affine3a.rs

1// Generated from affine.rs.tera template. Edit the template, not the generated file.
2
3use crate::{Affine3, Mat3, Mat3A, Mat4, Quat, Vec3, Vec3A};
4use core::ops::{Deref, DerefMut, Mul, MulAssign};
5
6#[cfg(all(feature = "zerocopy-08", not(feature = "core-simd")))]
7use zerocopy_derive_08::*;
8
9/// A 3D affine transform, which can represent translation, rotation, scaling and shear.
10///
11/// This type is 16 byte aligned.
12#[derive(Copy, Clone)]
13#[cfg_attr(
14    all(feature = "bytemuck", not(target_arch = "spirv")),
15    derive(bytemuck::Pod, bytemuck::Zeroable)
16)]
17#[cfg_attr(
18    all(feature = "bytemuck", target_arch = "spirv"),
19    derive(bytemuck::AnyBitPattern)
20)]
21#[cfg_attr(
22    all(
23        feature = "zerocopy-08",
24        not(feature = "core-simd"),
25        not(target_arch = "spirv")
26    ),
27    derive(FromBytes, Immutable, IntoBytes, KnownLayout)
28)]
29#[cfg_attr(
30    all(
31        feature = "zerocopy-08",
32        not(feature = "core-simd"),
33        target_arch = "spirv"
34    ),
35    derive(FromBytes, Immutable, KnownLayout)
36)]
37#[repr(C)]
38pub struct Affine3A {
39    pub matrix3: Mat3A,
40    pub translation: Vec3A,
41}
42
43impl Affine3A {
44    /// The degenerate zero transform.
45    ///
46    /// This transforms any finite vector and point to zero.
47    /// The zero transform is non-invertible.
48    pub const ZERO: Self = Self {
49        matrix3: Mat3A::ZERO,
50        translation: Vec3A::ZERO,
51    };
52
53    /// The identity transform.
54    ///
55    /// Multiplying a vector with this returns the same vector.
56    pub const IDENTITY: Self = Self {
57        matrix3: Mat3A::IDENTITY,
58        translation: Vec3A::ZERO,
59    };
60
61    /// All NAN:s.
62    pub const NAN: Self = Self {
63        matrix3: Mat3A::NAN,
64        translation: Vec3A::NAN,
65    };
66
67    /// Creates an affine transform from three column vectors.
68    #[inline(always)]
69    #[must_use]
70    pub const fn from_cols(x_axis: Vec3A, y_axis: Vec3A, z_axis: Vec3A, w_axis: Vec3A) -> Self {
71        Self {
72            matrix3: Mat3A::from_cols(x_axis, y_axis, z_axis),
73            translation: w_axis,
74        }
75    }
76
77    /// Creates an affine transform from a `[f32; 12]` array stored in column major order.
78    #[inline]
79    #[must_use]
80    pub fn from_cols_array(m: &[f32; 12]) -> Self {
81        Self {
82            matrix3: Mat3A::from_cols_array(&[
83                m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8],
84            ]),
85            translation: Vec3A::from_array([m[9], m[10], m[11]]),
86        }
87    }
88
89    /// Creates a `[f32; 12]` array storing data in column major order.
90    #[inline]
91    #[must_use]
92    pub fn to_cols_array(&self) -> [f32; 12] {
93        let x = &self.matrix3.x_axis;
94        let y = &self.matrix3.y_axis;
95        let z = &self.matrix3.z_axis;
96        let w = &self.translation;
97        [x.x, x.y, x.z, y.x, y.y, y.z, z.x, z.y, z.z, w.x, w.y, w.z]
98    }
99
100    /// Creates an affine transform from a `[[f32; 3]; 4]`
101    /// 3D array stored in column major order.
102    /// If your data is in row major order you will need to `transpose` the returned
103    /// matrix.
104    #[inline]
105    #[must_use]
106    pub fn from_cols_array_2d(m: &[[f32; 3]; 4]) -> Self {
107        Self {
108            matrix3: Mat3A::from_cols(m[0].into(), m[1].into(), m[2].into()),
109            translation: m[3].into(),
110        }
111    }
112
113    /// Creates a `[[f32; 3]; 4]` 3D array storing data in
114    /// column major order.
115    /// If you require data in row major order `transpose` the matrix first.
116    #[inline]
117    #[must_use]
118    pub fn to_cols_array_2d(&self) -> [[f32; 3]; 4] {
119        [
120            self.matrix3.x_axis.into(),
121            self.matrix3.y_axis.into(),
122            self.matrix3.z_axis.into(),
123            self.translation.into(),
124        ]
125    }
126
127    /// Creates an affine transform from the first 12 values in `slice`.
128    ///
129    /// # Panics
130    ///
131    /// Panics if `slice` is less than 12 elements long.
132    #[inline]
133    #[must_use]
134    pub fn from_cols_slice(slice: &[f32]) -> Self {
135        Self {
136            matrix3: Mat3A::from_cols_slice(&slice[0..9]),
137            translation: Vec3A::from_slice(&slice[9..12]),
138        }
139    }
140
141    /// Writes the columns of `self` to the first 12 elements in `slice`.
142    ///
143    /// # Panics
144    ///
145    /// Panics if `slice` is less than 12 elements long.
146    #[inline]
147    pub fn write_cols_to_slice(&self, slice: &mut [f32]) {
148        self.matrix3.write_cols_to_slice(&mut slice[0..9]);
149        self.translation.write_to_slice(&mut slice[9..12]);
150    }
151
152    /// Creates an affine transform that changes scale.
153    /// Note that if any scale is zero the transform will be non-invertible.
154    #[inline]
155    #[must_use]
156    pub fn from_scale(scale: Vec3) -> Self {
157        Self {
158            matrix3: Mat3A::from_diagonal(scale),
159            translation: Vec3A::ZERO,
160        }
161    }
162    /// Creates an affine transform from the given `rotation` quaternion.
163    ///
164    /// # Panics
165    ///
166    /// Will panic if `rotation` is not normalized when `glam_assert` is enabled.
167    #[inline]
168    #[must_use]
169    #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
170    pub fn from_quat(rotation: Quat) -> Self {
171        Self {
172            matrix3: Mat3A::from_quat(rotation),
173            translation: Vec3A::ZERO,
174        }
175    }
176
177    /// Creates an affine transform containing a 3D rotation around a normalized
178    /// rotation `axis` of `angle` (in radians).
179    ///
180    /// # Panics
181    ///
182    /// Will panic if `axis` is not normalized when `glam_assert` is enabled.
183    #[inline]
184    #[must_use]
185    #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
186    pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self {
187        Self {
188            matrix3: Mat3A::from_axis_angle(axis, angle),
189            translation: Vec3A::ZERO,
190        }
191    }
192
193    /// Creates an affine transform containing a 3D rotation around the x axis of
194    /// `angle` (in radians).
195    #[inline]
196    #[must_use]
197    pub fn from_rotation_x(angle: f32) -> Self {
198        Self {
199            matrix3: Mat3A::from_rotation_x(angle),
200            translation: Vec3A::ZERO,
201        }
202    }
203
204    /// Creates an affine transform containing a 3D rotation around the y axis of
205    /// `angle` (in radians).
206    #[inline]
207    #[must_use]
208    pub fn from_rotation_y(angle: f32) -> Self {
209        Self {
210            matrix3: Mat3A::from_rotation_y(angle),
211            translation: Vec3A::ZERO,
212        }
213    }
214
215    /// Creates an affine transform containing a 3D rotation around the z axis of
216    /// `angle` (in radians).
217    #[inline]
218    #[must_use]
219    pub fn from_rotation_z(angle: f32) -> Self {
220        Self {
221            matrix3: Mat3A::from_rotation_z(angle),
222            translation: Vec3A::ZERO,
223        }
224    }
225
226    /// Creates an affine transformation from the given 3D `translation`.
227    #[inline]
228    #[must_use]
229    pub fn from_translation(translation: Vec3) -> Self {
230        #[allow(clippy::useless_conversion)]
231        Self {
232            matrix3: Mat3A::IDENTITY,
233            translation: translation.into(),
234        }
235    }
236
237    /// Creates an affine transform from a 3x3 matrix (expressing scale, shear and
238    /// rotation)
239    #[inline]
240    #[must_use]
241    pub fn from_mat3(mat3: Mat3) -> Self {
242        #[allow(clippy::useless_conversion)]
243        Self {
244            matrix3: mat3.into(),
245            translation: Vec3A::ZERO,
246        }
247    }
248
249    /// Creates an affine transform from a 3x3 matrix (expressing scale, shear and rotation)
250    /// and a translation vector.
251    ///
252    /// Equivalent to `Affine3A::from_translation(translation) * Affine3A::from_mat3(mat3)`
253    #[inline]
254    #[must_use]
255    pub fn from_mat3_translation(mat3: Mat3, translation: Vec3) -> Self {
256        #[allow(clippy::useless_conversion)]
257        Self {
258            matrix3: mat3.into(),
259            translation: translation.into(),
260        }
261    }
262
263    /// Creates an affine transform from the given 3D `scale`, `rotation` and
264    /// `translation`.
265    ///
266    /// Equivalent to `Affine3A::from_translation(translation) *
267    /// Affine3A::from_quat(rotation) * Affine3A::from_scale(scale)`
268    ///
269    /// # Panics
270    ///
271    /// Will panic if `rotation` is not normalized when `glam_assert` is enabled.
272    #[inline]
273    #[must_use]
274    #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
275    pub fn from_scale_rotation_translation(scale: Vec3, rotation: Quat, translation: Vec3) -> Self {
276        let rotation = Mat3A::from_quat(rotation);
277        #[allow(clippy::useless_conversion)]
278        Self {
279            matrix3: Mat3A::from_cols(
280                rotation.x_axis * scale.x,
281                rotation.y_axis * scale.y,
282                rotation.z_axis * scale.z,
283            ),
284            translation: translation.into(),
285        }
286    }
287
288    /// Creates an affine transform from the given 3D `rotation` and `translation`.
289    ///
290    /// Equivalent to `Affine3A::from_translation(translation) * Affine3A::from_quat(rotation)`
291    ///
292    /// # Panics
293    ///
294    /// Will panic if `rotation` is not normalized when `glam_assert` is enabled.
295    #[inline]
296    #[must_use]
297    #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
298    pub fn from_rotation_translation(rotation: Quat, translation: Vec3) -> Self {
299        #[allow(clippy::useless_conversion)]
300        Self {
301            matrix3: Mat3A::from_quat(rotation),
302            translation: translation.into(),
303        }
304    }
305
306    /// The given `Mat4` must be an affine transform,
307    /// i.e. contain no perspective transform.
308    #[inline]
309    #[must_use]
310    pub fn from_mat4(m: Mat4) -> Self {
311        Self {
312            matrix3: Mat3A::from_cols(
313                Vec3A::from_vec4(m.x_axis),
314                Vec3A::from_vec4(m.y_axis),
315                Vec3A::from_vec4(m.z_axis),
316            ),
317            translation: Vec3A::from_vec4(m.w_axis),
318        }
319    }
320
321    /// Extracts `scale`, `rotation` and `translation` from `self`.
322    ///
323    /// The transform is expected to be non-degenerate and without shearing, or the output
324    /// will be invalid.
325    ///
326    /// # Panics
327    ///
328    /// Will panic if the determinant `self.matrix3` is zero or if the resulting scale
329    /// vector contains any zero elements when `glam_assert` is enabled.
330    #[inline]
331    #[must_use]
332    #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
333    pub fn to_scale_rotation_translation(&self) -> (Vec3, Quat, Vec3) {
334        use crate::f32::math;
335        let det = self.matrix3.determinant();
336        glam_assert!(det != 0.0);
337
338        let scale = Vec3::new(
339            self.matrix3.x_axis.length() * math::signum(det),
340            self.matrix3.y_axis.length(),
341            self.matrix3.z_axis.length(),
342        );
343
344        glam_assert!(scale.cmpne(Vec3::ZERO).all());
345
346        let inv_scale = scale.recip();
347
348        #[allow(clippy::useless_conversion)]
349        let rotation = Quat::from_mat3(&Mat3::from_cols(
350            (self.matrix3.x_axis * inv_scale.x).into(),
351            (self.matrix3.y_axis * inv_scale.y).into(),
352            (self.matrix3.z_axis * inv_scale.z).into(),
353        ));
354
355        #[allow(clippy::useless_conversion)]
356        (scale, rotation, self.translation.into())
357    }
358
359    /// Creates a left-handed view transform using a camera position, an up direction, and a facing
360    /// direction.
361    ///
362    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`.
363    ///
364    /// # Panics
365    ///
366    /// Will panic if `dir` or `up` is zero length or not finite, or if `dir` and `up` are parallel,
367    /// when `glam_assert` is enabled.
368    #[deprecated(
369        since = "0.33.1",
370        note = "use the `glam::camera::lh::view::look_to_affine3` function instead"
371    )]
372    #[inline]
373    #[must_use]
374    #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
375    pub fn look_to_lh(eye: Vec3, dir: Vec3, up: Vec3) -> Self {
376        #[allow(deprecated)]
377        Self::look_to_rh(eye, -dir, up)
378    }
379
380    /// Creates a right-handed view transform using a camera position, an up direction, and a facing
381    /// direction.
382    ///
383    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`.
384    ///
385    /// # Panics
386    ///
387    /// Will panic if `dir` or `up` is zero length or not finite, or if `dir` and `up` are parallel,
388    /// when `glam_assert` is enabled.
389    #[deprecated(
390        since = "0.33.1",
391        note = "use the `glam::camera::rh::view::look_to_affine3` function instead"
392    )]
393    #[inline]
394    #[must_use]
395    #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
396    pub fn look_to_rh(eye: Vec3, dir: Vec3, up: Vec3) -> Self {
397        let f = dir.normalize();
398        let s = f.cross(up).normalize();
399        let u = s.cross(f);
400
401        Self {
402            matrix3: Mat3A::from_cols(
403                Vec3A::new(s.x, u.x, -f.x),
404                Vec3A::new(s.y, u.y, -f.y),
405                Vec3A::new(s.z, u.z, -f.z),
406            ),
407            translation: Vec3A::new(-eye.dot(s), -eye.dot(u), eye.dot(f)),
408        }
409    }
410
411    /// Creates a left-handed view transform using a camera position, an up direction, and a focal
412    /// point.
413    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=forward`.
414    ///
415    /// # Panics
416    ///
417    /// Will panic if `up` is not normalized, if `center` is equal to `eye`, or if the view
418    /// direction is parallel to `up`, when `glam_assert` is enabled.
419    #[deprecated(
420        since = "0.33.1",
421        note = "use the `glam::camera::lh::view::look_at_affine3` function instead"
422    )]
423    #[inline]
424    #[must_use]
425    #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
426    pub fn look_at_lh(eye: Vec3, center: Vec3, up: Vec3) -> Self {
427        glam_assert!(up.is_normalized());
428        #[allow(deprecated)]
429        Self::look_to_lh(eye, center - eye, up)
430    }
431
432    /// Creates a right-handed view transform using a camera position, an up direction, and a focal
433    /// point.
434    /// For a view coordinate system with `+X=right`, `+Y=up` and `+Z=back`.
435    ///
436    /// # Panics
437    ///
438    /// Will panic if `up` is not normalized, if `center` is equal to `eye`, or if the view
439    /// direction is parallel to `up`, when `glam_assert` is enabled.
440    #[deprecated(
441        since = "0.33.1",
442        note = "use the `glam::camera::rh::view::look_at_affine3` function instead"
443    )]
444    #[inline]
445    #[must_use]
446    #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
447    pub fn look_at_rh(eye: Vec3, center: Vec3, up: Vec3) -> Self {
448        glam_assert!(up.is_normalized());
449        #[allow(deprecated)]
450        Self::look_to_rh(eye, center - eye, up)
451    }
452
453    /// Transforms the given 3D points, applying shear, scale, rotation and translation.
454    #[inline]
455    pub fn transform_point3(&self, rhs: Vec3) -> Vec3 {
456        #[allow(clippy::useless_conversion)]
457        ((self.matrix3.x_axis * rhs.x)
458            + (self.matrix3.y_axis * rhs.y)
459            + (self.matrix3.z_axis * rhs.z)
460            + self.translation)
461            .into()
462    }
463
464    /// Transforms the given 3D vector, applying shear, scale and rotation (but NOT
465    /// translation).
466    ///
467    /// To also apply translation, use [`Self::transform_point3()`] instead.
468    #[inline]
469    #[must_use]
470    pub fn transform_vector3(&self, rhs: Vec3) -> Vec3 {
471        #[allow(clippy::useless_conversion)]
472        ((self.matrix3.x_axis * rhs.x)
473            + (self.matrix3.y_axis * rhs.y)
474            + (self.matrix3.z_axis * rhs.z))
475            .into()
476    }
477
478    /// Transforms the given [`Vec3A`], applying shear, scale, rotation and translation.
479    #[inline]
480    #[must_use]
481    pub fn transform_point3a(&self, rhs: Vec3A) -> Vec3A {
482        self.matrix3 * rhs + self.translation
483    }
484
485    /// Transforms the given [`Vec3A`], applying shear, scale and rotation (but NOT
486    /// translation).
487    ///
488    /// To also apply translation, use [`Self::transform_point3a()`] instead.
489    #[inline]
490    #[must_use]
491    pub fn transform_vector3a(&self, rhs: Vec3A) -> Vec3A {
492        self.matrix3 * rhs
493    }
494
495    /// Returns `true` if, and only if, all elements are finite.
496    ///
497    /// If any element is either `NaN`, positive or negative infinity, this will return
498    /// `false`.
499    #[inline]
500    #[must_use]
501    pub fn is_finite(&self) -> bool {
502        self.matrix3.is_finite() && self.translation.is_finite()
503    }
504
505    /// Returns `true` if any elements are `NaN`.
506    #[inline]
507    #[must_use]
508    pub fn is_nan(&self) -> bool {
509        self.matrix3.is_nan() || self.translation.is_nan()
510    }
511
512    /// Returns true if the absolute difference of all elements between `self` and `rhs`
513    /// is less than or equal to `max_abs_diff`.
514    ///
515    /// This can be used to compare if two 3x4 matrices contain similar elements. It works
516    /// best when comparing with a known value. The `max_abs_diff` that should be used used
517    /// depends on the values being compared against.
518    ///
519    /// For more see
520    /// [comparing floating point numbers](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/).
521    #[inline]
522    #[must_use]
523    pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool {
524        self.matrix3.abs_diff_eq(rhs.matrix3, max_abs_diff)
525            && self.translation.abs_diff_eq(rhs.translation, max_abs_diff)
526    }
527
528    /// Return the inverse of this transform.
529    ///
530    /// Note that if the transform is not invertible the result will be invalid.
531    ///
532    /// # Panics
533    ///
534    /// Will panic if the resulting inverted matrix is not finite when `glam_assert` is enabled.
535    #[inline]
536    #[must_use]
537    #[cfg_attr(any(debug_assertions, feature = "glam-assert"), track_caller)]
538    pub fn inverse(&self) -> Self {
539        let matrix3 = self.matrix3.inverse();
540        // transform negative translation by the matrix inverse:
541        let translation = -(matrix3 * self.translation);
542
543        Self {
544            matrix3,
545            translation,
546        }
547    }
548
549    /// Casts all elements of `self` to `f64`.
550    #[cfg(feature = "f64")]
551    #[inline]
552    #[must_use]
553    pub fn as_daffine3(&self) -> crate::DAffine3 {
554        crate::DAffine3::from_mat3_translation(self.matrix3.as_dmat3(), self.translation.as_dvec3())
555    }
556}
557
558impl Default for Affine3A {
559    #[inline(always)]
560    fn default() -> Self {
561        Self::IDENTITY
562    }
563}
564
565impl Deref for Affine3A {
566    type Target = crate::deref::Cols4<Vec3A>;
567    #[inline(always)]
568    fn deref(&self) -> &Self::Target {
569        unsafe { &*(self as *const Self as *const Self::Target) }
570    }
571}
572
573impl DerefMut for Affine3A {
574    #[inline(always)]
575    fn deref_mut(&mut self) -> &mut Self::Target {
576        unsafe { &mut *(self as *mut Self as *mut Self::Target) }
577    }
578}
579
580impl PartialEq for Affine3A {
581    #[inline]
582    fn eq(&self, rhs: &Self) -> bool {
583        self.matrix3.eq(&rhs.matrix3) && self.translation.eq(&rhs.translation)
584    }
585}
586
587impl core::fmt::Debug for Affine3A {
588    fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
589        fmt.debug_struct(stringify!(Affine3A))
590            .field("matrix3", &self.matrix3)
591            .field("translation", &self.translation)
592            .finish()
593    }
594}
595
596impl core::fmt::Display for Affine3A {
597    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
598        if let Some(p) = f.precision() {
599            write!(
600                f,
601                "[{:.*}, {:.*}, {:.*}, {:.*}]",
602                p,
603                self.matrix3.x_axis,
604                p,
605                self.matrix3.y_axis,
606                p,
607                self.matrix3.z_axis,
608                p,
609                self.translation
610            )
611        } else {
612            write!(
613                f,
614                "[{}, {}, {}, {}]",
615                self.matrix3.x_axis, self.matrix3.y_axis, self.matrix3.z_axis, self.translation
616            )
617        }
618    }
619}
620
621impl<'a> core::iter::Product<&'a Self> for Affine3A {
622    fn product<I>(iter: I) -> Self
623    where
624        I: Iterator<Item = &'a Self>,
625    {
626        iter.fold(Self::IDENTITY, |a, &b| a * b)
627    }
628}
629
630impl Mul for Affine3A {
631    type Output = Self;
632
633    #[inline]
634    fn mul(self, rhs: Self) -> Self {
635        Self {
636            matrix3: self.matrix3 * rhs.matrix3,
637            translation: self.matrix3 * rhs.translation + self.translation,
638        }
639    }
640}
641
642impl Mul<&Self> for Affine3A {
643    type Output = Self;
644    #[inline]
645    fn mul(self, rhs: &Self) -> Self {
646        self.mul(*rhs)
647    }
648}
649
650impl Mul<&Affine3A> for &Affine3A {
651    type Output = Affine3A;
652    #[inline]
653    fn mul(self, rhs: &Affine3A) -> Affine3A {
654        (*self).mul(*rhs)
655    }
656}
657
658impl Mul<Affine3A> for &Affine3A {
659    type Output = Affine3A;
660    #[inline]
661    fn mul(self, rhs: Affine3A) -> Affine3A {
662        (*self).mul(rhs)
663    }
664}
665
666impl MulAssign for Affine3A {
667    #[inline]
668    fn mul_assign(&mut self, rhs: Self) {
669        *self = self.mul(rhs);
670    }
671}
672
673impl MulAssign<&Self> for Affine3A {
674    #[inline]
675    fn mul_assign(&mut self, rhs: &Self) {
676        self.mul_assign(*rhs);
677    }
678}
679
680impl Mul<Mat4> for Affine3A {
681    type Output = Mat4;
682
683    #[inline]
684    fn mul(self, rhs: Mat4) -> Self::Output {
685        Mat4::from(self) * rhs
686    }
687}
688
689impl Mul<&Mat4> for Affine3A {
690    type Output = Mat4;
691    #[inline]
692    fn mul(self, rhs: &Mat4) -> Mat4 {
693        self.mul(*rhs)
694    }
695}
696
697impl Mul<&Mat4> for &Affine3A {
698    type Output = Mat4;
699    #[inline]
700    fn mul(self, rhs: &Mat4) -> Mat4 {
701        (*self).mul(*rhs)
702    }
703}
704
705impl Mul<Mat4> for &Affine3A {
706    type Output = Mat4;
707    #[inline]
708    fn mul(self, rhs: Mat4) -> Mat4 {
709        (*self).mul(rhs)
710    }
711}
712
713impl Mul<Affine3A> for Mat4 {
714    type Output = Self;
715
716    #[inline]
717    fn mul(self, rhs: Affine3A) -> Self {
718        self * Self::from(rhs)
719    }
720}
721
722impl Mul<&Affine3A> for Mat4 {
723    type Output = Self;
724    #[inline]
725    fn mul(self, rhs: &Affine3A) -> Self {
726        self.mul(*rhs)
727    }
728}
729
730impl Mul<&Affine3A> for &Mat4 {
731    type Output = Mat4;
732    #[inline]
733    fn mul(self, rhs: &Affine3A) -> Mat4 {
734        (*self).mul(*rhs)
735    }
736}
737
738impl Mul<Affine3A> for &Mat4 {
739    type Output = Mat4;
740    #[inline]
741    fn mul(self, rhs: Affine3A) -> Mat4 {
742        (*self).mul(rhs)
743    }
744}
745
746impl MulAssign<Affine3A> for Mat4 {
747    #[inline]
748    fn mul_assign(&mut self, rhs: Affine3A) {
749        *self = self.mul(rhs);
750    }
751}
752
753impl MulAssign<&Affine3A> for Mat4 {
754    #[inline]
755    fn mul_assign(&mut self, rhs: &Affine3A) {
756        self.mul_assign(*rhs);
757    }
758}
759
760impl From<Affine3A> for Mat4 {
761    #[inline]
762    fn from(m: Affine3A) -> Self {
763        Self::from_cols(
764            m.matrix3.x_axis.extend(0.0),
765            m.matrix3.y_axis.extend(0.0),
766            m.matrix3.z_axis.extend(0.0),
767            m.translation.extend(1.0),
768        )
769    }
770}
771
772impl From<Affine3> for Affine3A {
773    #[inline]
774    fn from(a: Affine3) -> Self {
775        Self::from_cols(
776            a.matrix3.x_axis.into(),
777            a.matrix3.y_axis.into(),
778            a.matrix3.z_axis.into(),
779            a.translation.into(),
780        )
781    }
782}