1use crate::{DMat3, DMat4, DQuat, DVec3};
4use core::ops::{Deref, DerefMut, Mul, MulAssign};
5
6#[derive(Copy, Clone)]
8#[repr(C)]
9pub struct DAffine3 {
10 pub matrix3: DMat3,
11 pub translation: DVec3,
12}
13
14impl DAffine3 {
15 pub const ZERO: Self = Self {
20 matrix3: DMat3::ZERO,
21 translation: DVec3::ZERO,
22 };
23
24 pub const IDENTITY: Self = Self {
28 matrix3: DMat3::IDENTITY,
29 translation: DVec3::ZERO,
30 };
31
32 pub const NAN: Self = Self {
34 matrix3: DMat3::NAN,
35 translation: DVec3::NAN,
36 };
37
38 #[inline(always)]
40 pub const fn from_cols(x_axis: DVec3, y_axis: DVec3, z_axis: DVec3, w_axis: DVec3) -> Self {
41 Self {
42 matrix3: DMat3::from_cols(x_axis, y_axis, z_axis),
43 translation: w_axis,
44 }
45 }
46
47 #[inline]
49 pub fn from_cols_array(m: &[f64; 12]) -> Self {
50 Self {
51 matrix3: DMat3::from_cols_slice(&m[0..9]),
52 translation: DVec3::from_slice(&m[9..12]),
53 }
54 }
55
56 #[inline]
58 pub fn to_cols_array(&self) -> [f64; 12] {
59 let x = &self.matrix3.x_axis;
60 let y = &self.matrix3.y_axis;
61 let z = &self.matrix3.z_axis;
62 let w = &self.translation;
63 [x.x, x.y, x.z, y.x, y.y, y.z, z.x, z.y, z.z, w.x, w.y, w.z]
64 }
65
66 #[inline]
71 pub fn from_cols_array_2d(m: &[[f64; 3]; 4]) -> Self {
72 Self {
73 matrix3: DMat3::from_cols(m[0].into(), m[1].into(), m[2].into()),
74 translation: m[3].into(),
75 }
76 }
77
78 #[inline]
82 pub fn to_cols_array_2d(&self) -> [[f64; 3]; 4] {
83 [
84 self.matrix3.x_axis.into(),
85 self.matrix3.y_axis.into(),
86 self.matrix3.z_axis.into(),
87 self.translation.into(),
88 ]
89 }
90
91 #[inline]
97 pub fn from_cols_slice(slice: &[f64]) -> Self {
98 Self {
99 matrix3: DMat3::from_cols_slice(&slice[0..9]),
100 translation: DVec3::from_slice(&slice[9..12]),
101 }
102 }
103
104 #[inline]
110 pub fn write_cols_to_slice(self, slice: &mut [f64]) {
111 self.matrix3.write_cols_to_slice(&mut slice[0..9]);
112 self.translation.write_to_slice(&mut slice[9..12]);
113 }
114
115 #[inline]
118 pub fn from_scale(scale: DVec3) -> Self {
119 Self {
120 matrix3: DMat3::from_diagonal(scale),
121 translation: DVec3::ZERO,
122 }
123 }
124 #[inline]
126 pub fn from_quat(rotation: DQuat) -> Self {
127 Self {
128 matrix3: DMat3::from_quat(rotation),
129 translation: DVec3::ZERO,
130 }
131 }
132
133 #[inline]
136 pub fn from_axis_angle(axis: DVec3, angle: f64) -> Self {
137 Self {
138 matrix3: DMat3::from_axis_angle(axis, angle),
139 translation: DVec3::ZERO,
140 }
141 }
142
143 #[inline]
146 pub fn from_rotation_x(angle: f64) -> Self {
147 Self {
148 matrix3: DMat3::from_rotation_x(angle),
149 translation: DVec3::ZERO,
150 }
151 }
152
153 #[inline]
156 pub fn from_rotation_y(angle: f64) -> Self {
157 Self {
158 matrix3: DMat3::from_rotation_y(angle),
159 translation: DVec3::ZERO,
160 }
161 }
162
163 #[inline]
166 pub fn from_rotation_z(angle: f64) -> Self {
167 Self {
168 matrix3: DMat3::from_rotation_z(angle),
169 translation: DVec3::ZERO,
170 }
171 }
172
173 #[inline]
175 pub fn from_translation(translation: DVec3) -> Self {
176 #[allow(clippy::useless_conversion)]
177 Self {
178 matrix3: DMat3::IDENTITY,
179 translation: translation.into(),
180 }
181 }
182
183 #[inline]
186 pub fn from_mat3(mat3: DMat3) -> Self {
187 #[allow(clippy::useless_conversion)]
188 Self {
189 matrix3: mat3.into(),
190 translation: DVec3::ZERO,
191 }
192 }
193
194 #[inline]
199 pub fn from_mat3_translation(mat3: DMat3, translation: DVec3) -> Self {
200 #[allow(clippy::useless_conversion)]
201 Self {
202 matrix3: mat3.into(),
203 translation: translation.into(),
204 }
205 }
206
207 #[inline]
213 pub fn from_scale_rotation_translation(
214 scale: DVec3,
215 rotation: DQuat,
216 translation: DVec3,
217 ) -> Self {
218 let rotation = DMat3::from_quat(rotation);
219 #[allow(clippy::useless_conversion)]
220 Self {
221 matrix3: DMat3::from_cols(
222 rotation.x_axis * scale.x,
223 rotation.y_axis * scale.y,
224 rotation.z_axis * scale.z,
225 ),
226 translation: translation.into(),
227 }
228 }
229
230 #[inline]
234 pub fn from_rotation_translation(rotation: DQuat, translation: DVec3) -> Self {
235 #[allow(clippy::useless_conversion)]
236 Self {
237 matrix3: DMat3::from_quat(rotation),
238 translation: translation.into(),
239 }
240 }
241
242 #[inline]
245 pub fn from_mat4(m: DMat4) -> Self {
246 Self {
247 matrix3: DMat3::from_cols(
248 DVec3::from_vec4(m.x_axis),
249 DVec3::from_vec4(m.y_axis),
250 DVec3::from_vec4(m.z_axis),
251 ),
252 translation: DVec3::from_vec4(m.w_axis),
253 }
254 }
255
256 #[inline]
266 pub fn to_scale_rotation_translation(&self) -> (DVec3, DQuat, DVec3) {
267 use crate::f64::math;
268 let det = self.matrix3.determinant();
269 glam_assert!(det != 0.0);
270
271 let scale = DVec3::new(
272 self.matrix3.x_axis.length() * math::signum(det),
273 self.matrix3.y_axis.length(),
274 self.matrix3.z_axis.length(),
275 );
276
277 glam_assert!(scale.cmpne(DVec3::ZERO).all());
278
279 let inv_scale = scale.recip();
280
281 #[allow(clippy::useless_conversion)]
282 let rotation = DQuat::from_mat3(&DMat3::from_cols(
283 (self.matrix3.x_axis * inv_scale.x).into(),
284 (self.matrix3.y_axis * inv_scale.y).into(),
285 (self.matrix3.z_axis * inv_scale.z).into(),
286 ));
287
288 #[allow(clippy::useless_conversion)]
289 (scale, rotation, self.translation.into())
290 }
291
292 #[inline]
297 pub fn look_to_lh(eye: DVec3, dir: DVec3, up: DVec3) -> Self {
298 Self::look_to_rh(eye, -dir, up)
299 }
300
301 #[inline]
306 pub fn look_to_rh(eye: DVec3, dir: DVec3, up: DVec3) -> Self {
307 let f = dir.normalize();
308 let s = f.cross(up).normalize();
309 let u = s.cross(f);
310
311 Self {
312 matrix3: DMat3::from_cols(
313 DVec3::new(s.x, u.x, -f.x),
314 DVec3::new(s.y, u.y, -f.y),
315 DVec3::new(s.z, u.z, -f.z),
316 ),
317 translation: DVec3::new(-eye.dot(s), -eye.dot(u), eye.dot(f)),
318 }
319 }
320
321 #[inline]
329 pub fn look_at_lh(eye: DVec3, center: DVec3, up: DVec3) -> Self {
330 glam_assert!(up.is_normalized());
331 Self::look_to_lh(eye, center - eye, up)
332 }
333
334 #[inline]
342 pub fn look_at_rh(eye: DVec3, center: DVec3, up: DVec3) -> Self {
343 glam_assert!(up.is_normalized());
344 Self::look_to_rh(eye, center - eye, up)
345 }
346
347 #[inline]
349 pub fn transform_point3(&self, rhs: DVec3) -> DVec3 {
350 #[allow(clippy::useless_conversion)]
351 ((self.matrix3.x_axis * rhs.x)
352 + (self.matrix3.y_axis * rhs.y)
353 + (self.matrix3.z_axis * rhs.z)
354 + self.translation)
355 .into()
356 }
357
358 #[inline]
363 pub fn transform_vector3(&self, rhs: DVec3) -> DVec3 {
364 #[allow(clippy::useless_conversion)]
365 ((self.matrix3.x_axis * rhs.x)
366 + (self.matrix3.y_axis * rhs.y)
367 + (self.matrix3.z_axis * rhs.z))
368 .into()
369 }
370
371 #[inline]
376 pub fn is_finite(&self) -> bool {
377 self.matrix3.is_finite() && self.translation.is_finite()
378 }
379
380 #[inline]
382 pub fn is_nan(&self) -> bool {
383 self.matrix3.is_nan() || self.translation.is_nan()
384 }
385
386 #[inline]
396 pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f64) -> bool {
397 self.matrix3.abs_diff_eq(rhs.matrix3, max_abs_diff)
398 && self.translation.abs_diff_eq(rhs.translation, max_abs_diff)
399 }
400
401 #[must_use]
405 #[inline]
406 pub fn inverse(&self) -> Self {
407 let matrix3 = self.matrix3.inverse();
408 let translation = -(matrix3 * self.translation);
410
411 Self {
412 matrix3,
413 translation,
414 }
415 }
416}
417
418impl Default for DAffine3 {
419 #[inline(always)]
420 fn default() -> Self {
421 Self::IDENTITY
422 }
423}
424
425impl Deref for DAffine3 {
426 type Target = crate::deref::Cols4<DVec3>;
427 #[inline(always)]
428 fn deref(&self) -> &Self::Target {
429 unsafe { &*(self as *const Self as *const Self::Target) }
430 }
431}
432
433impl DerefMut for DAffine3 {
434 #[inline(always)]
435 fn deref_mut(&mut self) -> &mut Self::Target {
436 unsafe { &mut *(self as *mut Self as *mut Self::Target) }
437 }
438}
439
440impl PartialEq for DAffine3 {
441 #[inline]
442 fn eq(&self, rhs: &Self) -> bool {
443 self.matrix3.eq(&rhs.matrix3) && self.translation.eq(&rhs.translation)
444 }
445}
446
447#[cfg(not(target_arch = "spirv"))]
448impl core::fmt::Debug for DAffine3 {
449 fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
450 fmt.debug_struct(stringify!(DAffine3))
451 .field("matrix3", &self.matrix3)
452 .field("translation", &self.translation)
453 .finish()
454 }
455}
456
457#[cfg(not(target_arch = "spirv"))]
458impl core::fmt::Display for DAffine3 {
459 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
460 write!(
461 f,
462 "[{}, {}, {}, {}]",
463 self.matrix3.x_axis, self.matrix3.y_axis, self.matrix3.z_axis, self.translation
464 )
465 }
466}
467
468impl<'a> core::iter::Product<&'a Self> for DAffine3 {
469 fn product<I>(iter: I) -> Self
470 where
471 I: Iterator<Item = &'a Self>,
472 {
473 iter.fold(Self::IDENTITY, |a, &b| a * b)
474 }
475}
476
477impl Mul for DAffine3 {
478 type Output = DAffine3;
479
480 #[inline]
481 fn mul(self, rhs: DAffine3) -> Self::Output {
482 Self {
483 matrix3: self.matrix3 * rhs.matrix3,
484 translation: self.matrix3 * rhs.translation + self.translation,
485 }
486 }
487}
488
489impl MulAssign for DAffine3 {
490 #[inline]
491 fn mul_assign(&mut self, rhs: DAffine3) {
492 *self = self.mul(rhs);
493 }
494}
495
496impl From<DAffine3> for DMat4 {
497 #[inline]
498 fn from(m: DAffine3) -> DMat4 {
499 DMat4::from_cols(
500 m.matrix3.x_axis.extend(0.0),
501 m.matrix3.y_axis.extend(0.0),
502 m.matrix3.z_axis.extend(0.0),
503 m.translation.extend(1.0),
504 )
505 }
506}
507
508impl Mul<DMat4> for DAffine3 {
509 type Output = DMat4;
510
511 #[inline]
512 fn mul(self, rhs: DMat4) -> Self::Output {
513 DMat4::from(self) * rhs
514 }
515}
516
517impl Mul<DAffine3> for DMat4 {
518 type Output = DMat4;
519
520 #[inline]
521 fn mul(self, rhs: DAffine3) -> Self::Output {
522 self * DMat4::from(rhs)
523 }
524}