gizmo_engine/systems/
transform.rs1pub struct TransformSyncSystem;
2
3impl gizmo_core::system::System for TransformSyncSystem {
4 fn access_info(&self) -> gizmo_core::system::AccessInfo {
5 let mut info = gizmo_core::system::AccessInfo::new();
6 info.is_exclusive = true;
9 info
10 }
11
12 fn run(&mut self, world: &gizmo_core::world::World, _dt: f32) {
13 if let Some(mut transforms) = unsafe {
16 world.query_unchecked::<gizmo_core::query::Mut<gizmo_physics_core::Transform>>()
17 } {
18 for (_, mut trans) in transforms.iter_mut() {
19 trans.update_local_matrix();
20 }
21 }
22 }
23}
24
25pub struct TransformPropagateSystem;
26
27impl gizmo_core::system::System for TransformPropagateSystem {
28 fn access_info(&self) -> gizmo_core::system::AccessInfo {
29 let mut info = gizmo_core::system::AccessInfo::new();
30 info.is_exclusive = true; info
32 }
33
34 fn run(&mut self, world: &gizmo_core::world::World, _dt: f32) {
35 let root_query = unsafe {
38 world.query_unchecked::<(
39 &gizmo_physics_core::Transform,
40 gizmo_core::query::Mut<gizmo_physics_core::components::GlobalTransform>,
41 gizmo_core::query::Without<gizmo_core::component::Parent>,
42 )>()
43 };
44
45 let mut queue = Vec::new();
46 let mut visited: std::collections::HashSet<u32> = std::collections::HashSet::new();
52
53 if let Some(mut roots) = root_query {
54 let mut children_query = world.query::<&gizmo_core::component::Children>();
55 for (id, (local, mut global, _)) in roots.iter_mut() {
56 global.matrix = local.local_matrix;
57 visited.insert(id);
58 if let Some(children_q) = &mut children_query {
59 if let Some(children) = children_q.get(id) {
60 for &child_id in &children.0 {
61 if visited.insert(child_id) {
62 queue.push((global.matrix, child_id));
63 }
64 }
65 }
66 }
67 }
68 }
69
70 let mut local_query = world.query::<&gizmo_physics_core::Transform>();
72 let mut global_query = unsafe {
74 world.query_unchecked::<gizmo_core::query::Mut<gizmo_physics_core::components::GlobalTransform>>()
75 };
76 let mut children_query = world.query::<&gizmo_core::component::Children>();
77
78 let mut head = 0;
79 while head < queue.len() {
80 let (parent_matrix, current_id) = queue[head];
81 head += 1;
82
83 if let (Some(lq), Some(gq)) = (&mut local_query, &mut global_query) {
84 if let (Some(local), Some(mut global)) = (lq.get(current_id), gq.get_mut(current_id)) {
85 global.matrix = parent_matrix * local.local_matrix;
86
87 if let Some(cq) = &mut children_query {
88 if let Some(children) = cq.get(current_id) {
89 for &child_id in &children.0 {
90 if visited.insert(child_id) {
91 queue.push((global.matrix, child_id));
92 }
93 }
94 }
95 }
96 }
97 }
98 }
99 }
100}
101
102pub struct BoneAttachmentSystem;
103
104impl gizmo_core::system::System for BoneAttachmentSystem {
105 fn access_info(&self) -> gizmo_core::system::AccessInfo {
106 let mut info = gizmo_core::system::AccessInfo::new();
107 info.is_exclusive = true;
108 info
109 }
110
111 fn run(&mut self, world: &gizmo_core::world::World, _dt: f32) {
112 if let Some(query) = world.query::<&gizmo_renderer::components::BoneAttachment>() {
113 let mut skeletons = world.query::<&gizmo_renderer::components::Skeleton>();
114 let mut transforms = unsafe {
116 world.query_unchecked::<gizmo_core::query::Mut<gizmo_physics_core::Transform>>()
117 };
118
119 for (id, attachment) in query.iter() {
120 if let Some(sq) = &mut skeletons {
121 if let Some(skeleton) = sq.get(attachment.target_entity.id()) {
122 if let Some(global_matrix) = skeleton.global_poses.get(attachment.bone_index) {
123 if let Some(tq) = &mut transforms {
124 if let Some(mut trans) = tq.get_mut(id) {
125 let final_mat = *global_matrix * attachment.offset;
126 let (t, r, s) = gizmo_renderer::decompose_mat4(final_mat);
127 trans.position = t;
128 trans.rotation = r;
129 trans.scale = s;
130 trans.update_local_matrix();
131 }
132 }
133 }
134 }
135 }
136 }
137 }
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144 use gizmo_core::component::Children;
145 use gizmo_core::system::System;
146 use gizmo_core::world::World;
147 use gizmo_physics_core::components::GlobalTransform;
148 use gizmo_physics_core::Transform;
149
150 #[test]
151 fn transform_propagate_terminates_on_children_cycle() {
152 let mut world = World::new();
153 let a = world.spawn();
154 let b = world.spawn();
155 world.add_component(a, Transform::default());
156 world.add_component(a, GlobalTransform::default());
157 world.add_component(b, Transform::default());
158 world.add_component(b, GlobalTransform::default());
159 world.add_component(a, Children(vec![b.id()]));
163 world.add_component(b, Children(vec![a.id()]));
164
165 let mut sys = TransformPropagateSystem;
166 sys.run(&world, 0.0);
167 }
168}