Skip to main content

shiv_transform/
component.rs

1use std::ops::{Mul, MulAssign};
2
3use glam::{Affine3A, Mat3, Mat3A, Mat4, Quat, Vec3, Vec3A};
4use shiv::{bundle::Bundle, world::Component};
5
6#[derive(Clone, Copy, Debug, Default, Bundle)]
7pub struct TransformBundle {
8    pub transform: Transform,
9    pub global_transform: GlobalTransform,
10}
11
12/// The local transform of an entity.
13///
14/// This is the transform relative to the [`Parent`].
15/// If there is no [`Parent`], this it is relative to the origin.
16#[repr(C)]
17#[derive(Component, Clone, Copy, Debug, PartialEq)]
18pub struct Transform {
19    pub translation: Vec3,
20    pub rotation: Quat,
21    pub scale: Vec3,
22}
23
24impl Default for Transform {
25    #[inline]
26    fn default() -> Self {
27        Self::IDENTITY
28    }
29}
30
31impl Transform {
32    pub const IDENTITY: Self = Self {
33        translation: Vec3::ZERO,
34        rotation: Quat::IDENTITY,
35        scale: Vec3::ONE,
36    };
37
38    #[inline]
39    pub const fn from_xyz(x: f32, y: f32, z: f32) -> Self {
40        Self {
41            translation: Vec3::new(x, y, z),
42            rotation: Quat::IDENTITY,
43            scale: Vec3::ONE,
44        }
45    }
46
47    #[inline]
48    pub const fn from_translation(translation: Vec3) -> Self {
49        Self {
50            translation,
51            ..Self::IDENTITY
52        }
53    }
54
55    #[inline]
56    pub const fn from_rotation(rotation: Quat) -> Self {
57        Self {
58            rotation,
59            ..Self::IDENTITY
60        }
61    }
62
63    #[inline]
64    pub const fn from_scale(scale: Vec3) -> Self {
65        Self {
66            scale,
67            ..Self::IDENTITY
68        }
69    }
70
71    #[inline]
72    pub const fn with_xyz(mut self, x: f32, y: f32, z: f32) -> Self {
73        self.translation = Vec3::new(x, y, z);
74        self
75    }
76
77    #[inline]
78    pub const fn with_translation(mut self, translation: Vec3) -> Self {
79        self.translation = translation;
80        self
81    }
82
83    #[inline]
84    pub const fn with_rotation(mut self, rotation: Quat) -> Self {
85        self.rotation = rotation;
86        self
87    }
88
89    #[inline]
90    pub const fn with_scale(mut self, scale: Vec3) -> Self {
91        self.scale = scale;
92        self
93    }
94
95    #[inline]
96    pub fn local_x(&self) -> Vec3 {
97        self.rotation * Vec3::X
98    }
99
100    #[inline]
101    pub fn local_y(&self) -> Vec3 {
102        self.rotation * Vec3::Y
103    }
104
105    #[inline]
106    pub fn local_z(&self) -> Vec3 {
107        self.rotation * Vec3::Z
108    }
109
110    #[inline]
111    pub fn left(&self) -> Vec3 {
112        -self.local_x()
113    }
114
115    #[inline]
116    pub fn right(&self) -> Vec3 {
117        self.local_x()
118    }
119
120    #[inline]
121    pub fn up(&self) -> Vec3 {
122        self.local_y()
123    }
124
125    #[inline]
126    pub fn down(&self) -> Vec3 {
127        -self.local_y()
128    }
129
130    #[inline]
131    pub fn forward(&self) -> Vec3 {
132        -self.local_z()
133    }
134
135    #[inline]
136    pub fn back(&self) -> Vec3 {
137        self.local_z()
138    }
139
140    #[inline]
141    pub fn translate(&mut self, translation: Vec3) {
142        self.translation += translation;
143    }
144
145    #[inline]
146    pub fn scale(&mut self, scale: Vec3) {
147        self.scale *= scale;
148    }
149
150    #[inline]
151    pub fn rotate(&mut self, rotation: Quat) {
152        self.rotation *= rotation;
153    }
154
155    #[inline]
156    pub fn rotate_x(&mut self, angle: f32) {
157        self.rotate(Quat::from_rotation_x(angle));
158    }
159
160    #[inline]
161    pub fn rotate_y(&mut self, angle: f32) {
162        self.rotate(Quat::from_rotation_y(angle));
163    }
164
165    #[inline]
166    pub fn rotate_z(&mut self, angle: f32) {
167        self.rotate(Quat::from_rotation_z(angle));
168    }
169
170    #[inline]
171    pub fn look_at(&mut self, forward: Vec3, up: Vec3) {
172        let right = up.cross(forward).normalize();
173        let up = forward.cross(right).normalize();
174
175        self.rotation = Quat::from_mat3(&Mat3::from_cols(right, up, forward));
176    }
177
178    #[inline]
179    pub fn looking_at(mut self, forward: Vec3, up: Vec3) -> Self {
180        self.look_at(forward, up);
181        self
182    }
183
184    /// Computes the matrix representation of this transform.
185    #[inline]
186    pub fn compute_matrix(&self) -> Mat4 {
187        Mat4::from_scale_rotation_translation(self.scale, self.rotation, self.translation)
188    }
189
190    /// Computes the inverse of this transform.
191    #[inline]
192    pub fn invserse(&self) -> Self {
193        let inv_scale = self.scale.recip();
194        let inv_rotation = self.rotation.conjugate();
195
196        let mut inv_translation = -self.translation;
197        inv_translation = inv_rotation.mul_vec3(inv_translation);
198        inv_translation *= inv_scale;
199
200        Self {
201            translation: inv_translation,
202            rotation: inv_rotation,
203            scale: inv_scale,
204        }
205    }
206}
207
208impl Mul<Vec3> for Transform {
209    type Output = Vec3;
210
211    #[inline]
212    fn mul(self, rhs: Vec3) -> Self::Output {
213        let mut position = self.scale * rhs;
214        position = self.rotation * position;
215        position + self.translation
216    }
217}
218
219impl Mul for Transform {
220    type Output = Transform;
221
222    #[inline]
223    fn mul(self, rhs: Transform) -> Self::Output {
224        let mut translation = self.scale * rhs.translation;
225        translation = self.rotation * translation;
226        translation += self.translation;
227
228        Self {
229            translation,
230            rotation: self.rotation * rhs.rotation,
231            scale: self.scale * rhs.scale,
232        }
233    }
234}
235
236impl MulAssign for Transform {
237    #[inline]
238    fn mul_assign(&mut self, rhs: Transform) {
239        *self = *self * rhs;
240    }
241}
242
243/// A global transform representing an affine transformation.
244///
245/// This is the transform relative to the origin.
246#[repr(C)]
247#[derive(Component, Clone, Copy, Debug, PartialEq)]
248pub struct GlobalTransform {
249    pub translation: Vec3,
250    pub matrix: Mat3,
251}
252
253impl Default for GlobalTransform {
254    #[inline]
255    fn default() -> Self {
256        Self::IDENTITY
257    }
258}
259
260impl GlobalTransform {
261    pub const IDENTITY: Self = Self {
262        translation: Vec3::ZERO,
263        matrix: Mat3::IDENTITY,
264    };
265
266    #[inline]
267    pub const fn from_xyz(x: f32, y: f32, z: f32) -> Self {
268        Self {
269            translation: Vec3::new(x, y, z),
270            ..Self::IDENTITY
271        }
272    }
273
274    #[inline]
275    pub const fn from_translation(translation: Vec3) -> Self {
276        Self {
277            translation,
278            ..Self::IDENTITY
279        }
280    }
281
282    #[inline]
283    pub fn from_rotation(rotation: Quat) -> Self {
284        Self {
285            matrix: Mat3::from_quat(rotation),
286            ..Self::IDENTITY
287        }
288    }
289
290    #[inline]
291    pub fn from_scale(scale: Vec3) -> Self {
292        Self {
293            matrix: Mat3::from_diagonal(scale),
294            ..Self::IDENTITY
295        }
296    }
297
298    #[inline]
299    pub const fn from_matrix(matrix: Mat3) -> Self {
300        Self {
301            matrix,
302            ..Self::IDENTITY
303        }
304    }
305
306    #[inline]
307    pub const fn to_affine(self) -> Affine3A {
308        Affine3A {
309            translation: Vec3A::from_array(self.translation.to_array()),
310            matrix3: Mat3A::from_cols_array(&self.matrix.to_cols_array()),
311        }
312    }
313
314    #[inline]
315    pub fn local_x(&self) -> Vec3 {
316        Vec3::normalize(self.matrix * Vec3::X)
317    }
318
319    #[inline]
320    pub fn local_y(&self) -> Vec3 {
321        Vec3::normalize(self.matrix * Vec3::Y)
322    }
323
324    #[inline]
325    pub fn local_z(&self) -> Vec3 {
326        Vec3::normalize(self.matrix * Vec3::Z)
327    }
328
329    #[inline]
330    pub fn left(&self) -> Vec3 {
331        -self.local_x()
332    }
333
334    #[inline]
335    pub fn right(&self) -> Vec3 {
336        self.local_x()
337    }
338
339    #[inline]
340    pub fn up(&self) -> Vec3 {
341        self.local_y()
342    }
343
344    #[inline]
345    pub fn down(&self) -> Vec3 {
346        -self.local_y()
347    }
348
349    #[inline]
350    pub fn forward(&self) -> Vec3 {
351        -self.local_z()
352    }
353
354    #[inline]
355    pub fn back(&self) -> Vec3 {
356        self.local_z()
357    }
358
359    #[inline]
360    pub fn compute_matrix(&self) -> Mat4 {
361        let translation = Mat4::from_translation(self.translation);
362        let rotation_scale = Mat4::from_mat3(self.matrix);
363        translation * rotation_scale
364    }
365}
366
367impl From<Transform> for GlobalTransform {
368    #[inline]
369    fn from(value: Transform) -> Self {
370        Self {
371            translation: value.translation,
372            matrix: Mat3::from_quat(value.rotation) * Mat3::from_diagonal(value.scale),
373        }
374    }
375}
376
377impl From<&Transform> for GlobalTransform {
378    #[inline]
379    fn from(value: &Transform) -> Self {
380        Self {
381            translation: value.translation,
382            matrix: Mat3::from_quat(value.rotation) * Mat3::from_diagonal(value.scale),
383        }
384    }
385}
386
387impl Mul<Vec3> for GlobalTransform {
388    type Output = Vec3;
389
390    #[inline]
391    fn mul(self, rhs: Vec3) -> Self::Output {
392        self.matrix.mul_vec3(rhs) + self.translation
393    }
394}
395
396impl Mul<Transform> for GlobalTransform {
397    type Output = GlobalTransform;
398
399    #[inline]
400    fn mul(self, rhs: Transform) -> Self::Output {
401        self * GlobalTransform::from(rhs)
402    }
403}
404
405impl Mul for GlobalTransform {
406    type Output = GlobalTransform;
407
408    #[inline]
409    fn mul(self, rhs: GlobalTransform) -> Self::Output {
410        Self {
411            translation: self * rhs.translation,
412            matrix: self.matrix * rhs.matrix,
413        }
414    }
415}
416
417impl MulAssign for GlobalTransform {
418    #[inline]
419    fn mul_assign(&mut self, rhs: GlobalTransform) {
420        *self = *self * rhs;
421    }
422}