1use crate::{Mat3, Mat3A, Mat4, Quat, Vec3, Vec3A};
4use core::ops::{Deref, DerefMut, Mul, MulAssign};
5
6#[derive(Copy, Clone)]
10#[repr(C)]
11pub struct Affine3A {
12 pub matrix3: Mat3A,
13 pub translation: Vec3A,
14}
15
16impl Affine3A {
17 pub const ZERO: Self = Self {
22 matrix3: Mat3A::ZERO,
23 translation: Vec3A::ZERO,
24 };
25
26 pub const IDENTITY: Self = Self {
30 matrix3: Mat3A::IDENTITY,
31 translation: Vec3A::ZERO,
32 };
33
34 pub const NAN: Self = Self {
36 matrix3: Mat3A::NAN,
37 translation: Vec3A::NAN,
38 };
39
40 #[inline(always)]
42 pub const fn from_cols(x_axis: Vec3A, y_axis: Vec3A, z_axis: Vec3A, w_axis: Vec3A) -> Self {
43 Self {
44 matrix3: Mat3A::from_cols(x_axis, y_axis, z_axis),
45 translation: w_axis,
46 }
47 }
48
49 #[inline]
51 pub fn from_cols_array(m: &[f32; 12]) -> Self {
52 Self {
53 matrix3: Mat3A::from_cols_slice(&m[0..9]),
54 translation: Vec3A::from_slice(&m[9..12]),
55 }
56 }
57
58 #[inline]
60 pub fn to_cols_array(&self) -> [f32; 12] {
61 let x = &self.matrix3.x_axis;
62 let y = &self.matrix3.y_axis;
63 let z = &self.matrix3.z_axis;
64 let w = &self.translation;
65 [x.x, x.y, x.z, y.x, y.y, y.z, z.x, z.y, z.z, w.x, w.y, w.z]
66 }
67
68 #[inline]
73 pub fn from_cols_array_2d(m: &[[f32; 3]; 4]) -> Self {
74 Self {
75 matrix3: Mat3A::from_cols(m[0].into(), m[1].into(), m[2].into()),
76 translation: m[3].into(),
77 }
78 }
79
80 #[inline]
84 pub fn to_cols_array_2d(&self) -> [[f32; 3]; 4] {
85 [
86 self.matrix3.x_axis.into(),
87 self.matrix3.y_axis.into(),
88 self.matrix3.z_axis.into(),
89 self.translation.into(),
90 ]
91 }
92
93 #[inline]
99 pub fn from_cols_slice(slice: &[f32]) -> Self {
100 Self {
101 matrix3: Mat3A::from_cols_slice(&slice[0..9]),
102 translation: Vec3A::from_slice(&slice[9..12]),
103 }
104 }
105
106 #[inline]
112 pub fn write_cols_to_slice(self, slice: &mut [f32]) {
113 self.matrix3.write_cols_to_slice(&mut slice[0..9]);
114 self.translation.write_to_slice(&mut slice[9..12]);
115 }
116
117 #[inline]
120 pub fn from_scale(scale: Vec3) -> Self {
121 Self {
122 matrix3: Mat3A::from_diagonal(scale),
123 translation: Vec3A::ZERO,
124 }
125 }
126 #[inline]
128 pub fn from_quat(rotation: Quat) -> Self {
129 Self {
130 matrix3: Mat3A::from_quat(rotation),
131 translation: Vec3A::ZERO,
132 }
133 }
134
135 #[inline]
138 pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self {
139 Self {
140 matrix3: Mat3A::from_axis_angle(axis, angle),
141 translation: Vec3A::ZERO,
142 }
143 }
144
145 #[inline]
148 pub fn from_rotation_x(angle: f32) -> Self {
149 Self {
150 matrix3: Mat3A::from_rotation_x(angle),
151 translation: Vec3A::ZERO,
152 }
153 }
154
155 #[inline]
158 pub fn from_rotation_y(angle: f32) -> Self {
159 Self {
160 matrix3: Mat3A::from_rotation_y(angle),
161 translation: Vec3A::ZERO,
162 }
163 }
164
165 #[inline]
168 pub fn from_rotation_z(angle: f32) -> Self {
169 Self {
170 matrix3: Mat3A::from_rotation_z(angle),
171 translation: Vec3A::ZERO,
172 }
173 }
174
175 #[inline]
177 pub fn from_translation(translation: Vec3) -> Self {
178 #[allow(clippy::useless_conversion)]
179 Self {
180 matrix3: Mat3A::IDENTITY,
181 translation: translation.into(),
182 }
183 }
184
185 #[inline]
188 pub fn from_mat3(mat3: Mat3) -> Self {
189 #[allow(clippy::useless_conversion)]
190 Self {
191 matrix3: mat3.into(),
192 translation: Vec3A::ZERO,
193 }
194 }
195
196 #[inline]
201 pub fn from_mat3_translation(mat3: Mat3, translation: Vec3) -> Self {
202 #[allow(clippy::useless_conversion)]
203 Self {
204 matrix3: mat3.into(),
205 translation: translation.into(),
206 }
207 }
208
209 #[inline]
215 pub fn from_scale_rotation_translation(scale: Vec3, rotation: Quat, translation: Vec3) -> Self {
216 let rotation = Mat3A::from_quat(rotation);
217 #[allow(clippy::useless_conversion)]
218 Self {
219 matrix3: Mat3A::from_cols(
220 rotation.x_axis * scale.x,
221 rotation.y_axis * scale.y,
222 rotation.z_axis * scale.z,
223 ),
224 translation: translation.into(),
225 }
226 }
227
228 #[inline]
232 pub fn from_rotation_translation(rotation: Quat, translation: Vec3) -> Self {
233 #[allow(clippy::useless_conversion)]
234 Self {
235 matrix3: Mat3A::from_quat(rotation),
236 translation: translation.into(),
237 }
238 }
239
240 #[inline]
243 pub fn from_mat4(m: Mat4) -> Self {
244 Self {
245 matrix3: Mat3A::from_cols(
246 Vec3A::from_vec4(m.x_axis),
247 Vec3A::from_vec4(m.y_axis),
248 Vec3A::from_vec4(m.z_axis),
249 ),
250 translation: Vec3A::from_vec4(m.w_axis),
251 }
252 }
253
254 #[inline]
264 pub fn to_scale_rotation_translation(&self) -> (Vec3, Quat, Vec3) {
265 use crate::f32::math;
266 let det = self.matrix3.determinant();
267 glam_assert!(det != 0.0);
268
269 let scale = Vec3::new(
270 self.matrix3.x_axis.length() * math::signum(det),
271 self.matrix3.y_axis.length(),
272 self.matrix3.z_axis.length(),
273 );
274
275 glam_assert!(scale.cmpne(Vec3::ZERO).all());
276
277 let inv_scale = scale.recip();
278
279 #[allow(clippy::useless_conversion)]
280 let rotation = Quat::from_mat3(&Mat3::from_cols(
281 (self.matrix3.x_axis * inv_scale.x).into(),
282 (self.matrix3.y_axis * inv_scale.y).into(),
283 (self.matrix3.z_axis * inv_scale.z).into(),
284 ));
285
286 #[allow(clippy::useless_conversion)]
287 (scale, rotation, self.translation.into())
288 }
289
290 #[inline]
295 pub fn look_to_lh(eye: Vec3, dir: Vec3, up: Vec3) -> Self {
296 Self::look_to_rh(eye, -dir, up)
297 }
298
299 #[inline]
304 pub fn look_to_rh(eye: Vec3, dir: Vec3, up: Vec3) -> Self {
305 let f = dir.normalize();
306 let s = f.cross(up).normalize();
307 let u = s.cross(f);
308
309 Self {
310 matrix3: Mat3A::from_cols(
311 Vec3A::new(s.x, u.x, -f.x),
312 Vec3A::new(s.y, u.y, -f.y),
313 Vec3A::new(s.z, u.z, -f.z),
314 ),
315 translation: Vec3A::new(-eye.dot(s), -eye.dot(u), eye.dot(f)),
316 }
317 }
318
319 #[inline]
327 pub fn look_at_lh(eye: Vec3, center: Vec3, up: Vec3) -> Self {
328 glam_assert!(up.is_normalized());
329 Self::look_to_lh(eye, center - eye, up)
330 }
331
332 #[inline]
340 pub fn look_at_rh(eye: Vec3, center: Vec3, up: Vec3) -> Self {
341 glam_assert!(up.is_normalized());
342 Self::look_to_rh(eye, center - eye, up)
343 }
344
345 #[inline]
347 pub fn transform_point3(&self, rhs: Vec3) -> Vec3 {
348 #[allow(clippy::useless_conversion)]
349 ((self.matrix3.x_axis * rhs.x)
350 + (self.matrix3.y_axis * rhs.y)
351 + (self.matrix3.z_axis * rhs.z)
352 + self.translation)
353 .into()
354 }
355
356 #[inline]
361 pub fn transform_vector3(&self, rhs: Vec3) -> Vec3 {
362 #[allow(clippy::useless_conversion)]
363 ((self.matrix3.x_axis * rhs.x)
364 + (self.matrix3.y_axis * rhs.y)
365 + (self.matrix3.z_axis * rhs.z))
366 .into()
367 }
368
369 #[inline]
371 pub fn transform_point3a(&self, rhs: Vec3A) -> Vec3A {
372 self.matrix3 * rhs + self.translation
373 }
374
375 #[inline]
380 pub fn transform_vector3a(&self, rhs: Vec3A) -> Vec3A {
381 self.matrix3 * rhs
382 }
383
384 #[inline]
389 pub fn is_finite(&self) -> bool {
390 self.matrix3.is_finite() && self.translation.is_finite()
391 }
392
393 #[inline]
395 pub fn is_nan(&self) -> bool {
396 self.matrix3.is_nan() || self.translation.is_nan()
397 }
398
399 #[inline]
409 pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool {
410 self.matrix3.abs_diff_eq(rhs.matrix3, max_abs_diff)
411 && self.translation.abs_diff_eq(rhs.translation, max_abs_diff)
412 }
413
414 #[must_use]
418 #[inline]
419 pub fn inverse(&self) -> Self {
420 let matrix3 = self.matrix3.inverse();
421 let translation = -(matrix3 * self.translation);
423
424 Self {
425 matrix3,
426 translation,
427 }
428 }
429}
430
431impl Default for Affine3A {
432 #[inline(always)]
433 fn default() -> Self {
434 Self::IDENTITY
435 }
436}
437
438impl Deref for Affine3A {
439 type Target = crate::deref::Cols4<Vec3A>;
440 #[inline(always)]
441 fn deref(&self) -> &Self::Target {
442 unsafe { &*(self as *const Self as *const Self::Target) }
443 }
444}
445
446impl DerefMut for Affine3A {
447 #[inline(always)]
448 fn deref_mut(&mut self) -> &mut Self::Target {
449 unsafe { &mut *(self as *mut Self as *mut Self::Target) }
450 }
451}
452
453impl PartialEq for Affine3A {
454 #[inline]
455 fn eq(&self, rhs: &Self) -> bool {
456 self.matrix3.eq(&rhs.matrix3) && self.translation.eq(&rhs.translation)
457 }
458}
459
460#[cfg(not(target_arch = "spirv"))]
461impl core::fmt::Debug for Affine3A {
462 fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
463 fmt.debug_struct(stringify!(Affine3A))
464 .field("matrix3", &self.matrix3)
465 .field("translation", &self.translation)
466 .finish()
467 }
468}
469
470#[cfg(not(target_arch = "spirv"))]
471impl core::fmt::Display for Affine3A {
472 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
473 write!(
474 f,
475 "[{}, {}, {}, {}]",
476 self.matrix3.x_axis, self.matrix3.y_axis, self.matrix3.z_axis, self.translation
477 )
478 }
479}
480
481impl<'a> core::iter::Product<&'a Self> for Affine3A {
482 fn product<I>(iter: I) -> Self
483 where
484 I: Iterator<Item = &'a Self>,
485 {
486 iter.fold(Self::IDENTITY, |a, &b| a * b)
487 }
488}
489
490impl Mul for Affine3A {
491 type Output = Affine3A;
492
493 #[inline]
494 fn mul(self, rhs: Affine3A) -> Self::Output {
495 Self {
496 matrix3: self.matrix3 * rhs.matrix3,
497 translation: self.matrix3 * rhs.translation + self.translation,
498 }
499 }
500}
501
502impl MulAssign for Affine3A {
503 #[inline]
504 fn mul_assign(&mut self, rhs: Affine3A) {
505 *self = self.mul(rhs);
506 }
507}
508
509impl From<Affine3A> for Mat4 {
510 #[inline]
511 fn from(m: Affine3A) -> Mat4 {
512 Mat4::from_cols(
513 m.matrix3.x_axis.extend(0.0),
514 m.matrix3.y_axis.extend(0.0),
515 m.matrix3.z_axis.extend(0.0),
516 m.translation.extend(1.0),
517 )
518 }
519}
520
521impl Mul<Mat4> for Affine3A {
522 type Output = Mat4;
523
524 #[inline]
525 fn mul(self, rhs: Mat4) -> Self::Output {
526 Mat4::from(self) * rhs
527 }
528}
529
530impl Mul<Affine3A> for Mat4 {
531 type Output = Mat4;
532
533 #[inline]
534 fn mul(self, rhs: Affine3A) -> Self::Output {
535 self * Mat4::from(rhs)
536 }
537}