Skip to main content

mittens_engine/engine/ecs/component/
bone_rest_pose.rs

1use crate::engine::ecs::ComponentId;
2use crate::engine::ecs::component::Component;
3
4/// Immutable snapshot of a bone's local TRS at GLTF load time.
5///
6/// Animation, IK, and post-load systems all overwrite `TransformComponent`
7/// during the tick, so by the time `AvatarControlSystem::try_init_splices`
8/// runs the bone's `TransformComponent` no longer holds the authored bind
9/// pose.  This component is attached as a child of each GLTF-spawned bone
10/// `TransformComponent` so consumers can look up the *true* rest local
11/// translation / rotation / scale without depending on tick ordering.
12///
13/// Created once by `GLTFSystem` during node spawn and never written again.
14///
15/// Lookup pattern:
16/// ```ignore
17/// let rest = world
18///     .children_of(bone_tc_id)
19///     .iter()
20///     .find_map(|&c| world.get_component_by_id_as::<BoneRestPoseComponent>(c));
21/// ```
22#[derive(Debug, Clone, Copy)]
23pub struct BoneRestPoseComponent {
24    pub translation: [f32; 3],
25    pub rotation: [f32; 4],
26    pub scale: [f32; 3],
27
28    component: Option<ComponentId>,
29}
30
31impl BoneRestPoseComponent {
32    pub fn new(translation: [f32; 3], rotation: [f32; 4], scale: [f32; 3]) -> Self {
33        Self {
34            translation,
35            rotation,
36            scale,
37            component: None,
38        }
39    }
40}
41
42impl Component for BoneRestPoseComponent {
43    fn name(&self) -> &'static str {
44        "bone_rest_pose"
45    }
46
47    fn set_id(&mut self, id: ComponentId) {
48        self.component = Some(id);
49    }
50
51    fn as_any(&self) -> &dyn std::any::Any {
52        self
53    }
54
55    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
56        self
57    }
58
59    fn to_mms_ast(
60        &self,
61        _world: &crate::engine::ecs::World,
62    ) -> crate::scripting::ast::ComponentExpression {
63        use crate::engine::ecs::component::ce_helpers::*;
64        ce("BoneRestPose").with_call(
65            "translation",
66            vec![
67                num(self.translation[0] as f64),
68                num(self.translation[1] as f64),
69                num(self.translation[2] as f64),
70            ],
71        )
72    }
73}