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
use super::*;
use crate::Conformal3;
/// 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
        Transform,
        ScaleUniform,
        f32,
        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,
        WorldScaleUniform,
        f32,
        world_scale,
        ValueAccessorReadWriteAnimate
    );

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

    /// Set the entity-to-parent transform.
    pub fn set_entity_to_parent(&self, entity_to_parent: &Conformal3) {
        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 a [`Conformal3`].
    pub fn parent_to_entity(&self) -> Conformal3 {
        self.entity_to_parent().inverse()
    }

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

    /// Returns the entity-to-world transform as a decomposed [`Conformal3`] (translation, rotation, uniform scale).
    pub fn entity_to_world(&self) -> Conformal3 {
        let mut t = vec![];
        World::get_entity_world_transforms(&[self.id], &mut t);
        Conformal3::from_scale_rotation_translation(
            t[0].translation_and_scale[3],
            Quat::from_array(t[0].rotation),
            Vec3::from_slice(&t[0].translation_and_scale[0..3]),
        )
    }

    /// Sets the entity-to-world transform from a [`Conformal3`] (translation, rotation, uniform scale).
    pub fn set_entity_to_world(&self, entity_to_world: &Conformal3) {
        let t = EntityTransformConformal3 {
            translation_and_scale: entity_to_world.translation_and_scale().to_array(),
            rotation: entity_to_world.rotation().into(),
        };

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

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

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

impl_world_component!(Transform);