1use 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#[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 pub const ZERO: Self = Self {
49 matrix3: Mat3A::ZERO,
50 translation: Vec3A::ZERO,
51 };
52
53 pub const IDENTITY: Self = Self {
57 matrix3: Mat3A::IDENTITY,
58 translation: Vec3A::ZERO,
59 };
60
61 pub const NAN: Self = Self {
63 matrix3: Mat3A::NAN,
64 translation: Vec3A::NAN,
65 };
66
67 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[inline]
480 #[must_use]
481 pub fn transform_point3a(&self, rhs: Vec3A) -> Vec3A {
482 self.matrix3 * rhs + self.translation
483 }
484
485 #[inline]
490 #[must_use]
491 pub fn transform_vector3a(&self, rhs: Vec3A) -> Vec3A {
492 self.matrix3 * rhs
493 }
494
495 #[inline]
500 #[must_use]
501 pub fn is_finite(&self) -> bool {
502 self.matrix3.is_finite() && self.translation.is_finite()
503 }
504
505 #[inline]
507 #[must_use]
508 pub fn is_nan(&self) -> bool {
509 self.matrix3.is_nan() || self.translation.is_nan()
510 }
511
512 #[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 #[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 let translation = -(matrix3 * self.translation);
542
543 Self {
544 matrix3,
545 translation,
546 }
547 }
548
549 #[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}