logo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
use super::*;
use crate::{Affine3A, Mat3};

/// Transform3 struct.
///
/// Represents a 3-dimensional transform decomposed into scale, rotation, translation
#[derive(Copy, Clone, Debug)]
pub struct Transform3 {
    translation: Vec3,
    rotation: Quat,
    scale: Vec3,
}

impl Transform3 {
    /// Creates a `Transform3` from scale, rotation, translation
    pub fn from_scale_rotation_translation(scale: Vec3, rotation: Quat, translation: Vec3) -> Self {
        Self {
            translation,
            rotation,
            scale,
        }
    }

    /// Decomposes an `Affine3A` into a `Transform3`
    pub fn from_affine3(t: &Affine3A) -> Self {
        let (scale, rotation, translation) = t.to_scale_rotation_translation();
        Self {
            translation,
            rotation,
            scale,
        }
    }

    /// Creates a `Transform3` from an `EntityTransform`
    pub fn from_entity_transform(t: &EntityTransform) -> Self {
        Self {
            translation: t.translation.into(),
            rotation: Quat::from_array(t.rotation),
            scale: t.scale.into(),
        }
    }
}

/// Transform component.
///
/// Use to move and rotate entities (without physics).
pub struct Transform {
    id: Entity,
}

impl std::fmt::Debug for Transform {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Transform")
            .field("entity", &self.id.name())
            .field("scale", &self.scale().get())
            .field("rotation", &self.rotation().get())
            .field("position", &self.position().get())
            .finish_non_exhaustive()
    }
}

impl Transform {
    impl_world_accessor!(
        /// Returns a `ValueAccessor` for the local position of the entity.
        ///
        /// Used to set/get/animate the position.
        /// Moves the entity to this position.
        /// If physics (non-kinematic) are enabled, it's recommended to use forces instead of
        /// explicitly moving the entity.
        Transform,
        Position,
        Vec3,
        position,
        ValueAccessorReadWriteAnimate
    );

    impl_world_accessor!(
        /// Returns a `ValueAccessor` for the local rotation of the entity.
        ///
        /// Used to set/get/animate the rotation (in quaternion format).
        ///
        /// If physics (non-kinematic) are enabled, it's recommended to use forces/torques instead of
        /// explicitly rotating the entity.
        Transform,
        Rotation,
        Quat,
        rotation,
        ValueAccessorReadWriteAnimate
    );

    impl_world_accessor!(
        /// Returns a `ValueAccessor` for the local scale of the entity.
        ///
        /// Used to set/get/animate the scale. Scale animation is not recommended for entities
        /// with physics enabled.
        ///
        /// NOTE: scale values must be greater than (0, 0, 0)
        Transform,
        Scale,
        Vec3,
        scale,
        ValueAccessorReadWriteAnimate
    );

    impl_world_accessor!(
        /// Sets/gets the parent of the entity in the transform hierarchy.
        ///
        /// Does not work for dynamic physics. If you change an object to use dynamic physics,
        /// the parent will be removed. Works for kinematic physics objects though.
        Transform,
        ParentId,
        Entity,
        parent,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// Returns a `ValueAccessor` for the world position of the entity.
        ///
        /// Used to get the current world position.
        Transform,
        WorldPosition,
        Vec3,
        world_position,
        ValueAccessorReadWriteAnimate
    );

    impl_world_accessor!(
        /// Returns a `ValueAccessor` for the world rotation of the entity.
        ///
        /// Used to get the current rotation (in quaternion format).
        Transform,
        WorldRotation,
        Quat,
        world_rotation,
        ValueAccessorReadWriteAnimate
    );

    impl_world_accessor!(
        /// Returns a `ValueAccessor` for the world scale of the entity.
        ///
        /// Used to get the scale.
        /// Will be the scale of the last frame.
        Transform,
        WorldScale,
        Vec3,
        world_scale,
        ValueAccessorReadWriteAnimate
    );

    /// Returns the entity-to-parent transform as an [`Affine3A`].
    pub fn entity_to_parent(&self) -> Affine3A {
        let scale = self.scale().get();
        let rotation = self.rotation().get();
        let translation = self.position().get();
        Affine3A::from_scale_rotation_translation(scale, rotation, translation)
    }

    /// Set the entity-to-parent transform.
    pub fn set_entity_to_parent(&self, entity_to_parent: &Affine3A) {
        let (scale, rotation, translation) = entity_to_parent.to_scale_rotation_translation();
        self.scale().set(scale);
        self.rotation().set(rotation);
        self.position().set(translation);
    }

    /// Returns the parent-to-entity transform as an [`Affine3A`].
    pub fn parent_to_entity(&self) -> Affine3A {
        self.entity_to_parent().inverse()
    }

    /// Set the parent-to-entity transform from an [`Affine3A`].
    pub fn set_parent_to_entity(&self, parent_to_entity: &Affine3A) {
        self.set_entity_to_parent(&parent_to_entity.inverse());
    }

    /// Returns the entity-to-world transform as a decomposed [`Transform3`] (translation, rotation, scale).
    pub fn entity_to_world_decomposed(&self) -> Transform3 {
        let mut t = vec![];
        World::get_entity_world_transforms(&[self.id], &mut t);
        Transform3::from_entity_transform(&t[0])
    }

    /// Sets the entity-to-world transform from a decomposed [`Transform3`] (translation, rotation, scale).
    pub fn set_entity_to_world_decomposed(&self, entity_to_world: &Transform3) {
        let t = EntityTransform {
            translation: entity_to_world.translation.to_array(),
            rotation: entity_to_world.rotation.into(),
            scale: entity_to_world.scale.to_array(),
        };

        World::set_entity_world_transforms(&[self.id], &[t]);
    }

    /// Returns the entity-to-world transform as an [`Affine3A`].
    pub fn entity_to_world(&self) -> Affine3A {
        let mut t = vec![];
        World::get_entity_world_transforms_affine3(&[self.id], &mut t);
        Affine3A::from_mat3_translation(
            Mat3::from_cols_array(&t[0].rotation_scale),
            t[0].translation.into(),
        )
    }

    /// Set the entity-to-world transform from an [`Affine3A`]
    pub fn set_entity_to_world(&self, entity_to_world: &Affine3A) {
        let t = EntityTransformAffine3 {
            rotation_scale: entity_to_world.matrix3.to_cols_array(),
            translation: entity_to_world.translation.to_array(),
        };

        World::set_entity_world_transforms_affine3(&[self.id], &[t]);
    }

    /// Returns the world-to-entity transform as an [`Affine3A`].
    pub fn world_to_entity(&self) -> Affine3A {
        self.entity_to_world().inverse()
    }

    /// Set the world-to-entity transform.
    pub fn set_world_to_entity(&self, world_to_entity: &Affine3A) {
        self.set_entity_to_world(&world_to_entity.inverse());
    }
}

impl_world_component!(Transform);