pub struct TransformSyncSystem;
impl gizmo_core::system::System for TransformSyncSystem {
fn access_info(&self) -> gizmo_core::system::AccessInfo {
let mut info = gizmo_core::system::AccessInfo::new();
info.is_exclusive = true;
info
}
fn run(&mut self, world: &gizmo_core::world::World, _dt: f32) {
if let Some(mut transforms) = unsafe {
world.query_unchecked::<gizmo_core::query::Mut<gizmo_physics_core::Transform>>()
} {
for (_, mut trans) in transforms.iter_mut() {
trans.update_local_matrix();
}
}
}
}
pub struct TransformPropagateSystem;
impl gizmo_core::system::System for TransformPropagateSystem {
fn access_info(&self) -> gizmo_core::system::AccessInfo {
let mut info = gizmo_core::system::AccessInfo::new();
info.is_exclusive = true; info
}
fn run(&mut self, world: &gizmo_core::world::World, _dt: f32) {
let root_query = unsafe {
world.query_unchecked::<(
&gizmo_physics_core::Transform,
gizmo_core::query::Mut<gizmo_physics_core::components::GlobalTransform>,
gizmo_core::query::Without<gizmo_core::component::Parent>,
)>()
};
let mut queue = Vec::new();
let mut visited: std::collections::HashSet<u32> = std::collections::HashSet::new();
if let Some(mut roots) = root_query {
let mut children_query = world.query::<&gizmo_core::component::Children>();
for (id, (local, mut global, _)) in roots.iter_mut() {
global.matrix = local.local_matrix;
visited.insert(id);
if let Some(children_q) = &mut children_query {
if let Some(children) = children_q.get(id) {
for &child_id in &children.0 {
if visited.insert(child_id) {
queue.push((global.matrix, child_id));
}
}
}
}
}
}
let mut local_query = world.query::<&gizmo_physics_core::Transform>();
let mut global_query = unsafe {
world.query_unchecked::<gizmo_core::query::Mut<gizmo_physics_core::components::GlobalTransform>>()
};
let mut children_query = world.query::<&gizmo_core::component::Children>();
let mut head = 0;
while head < queue.len() {
let (parent_matrix, current_id) = queue[head];
head += 1;
if let (Some(lq), Some(gq)) = (&mut local_query, &mut global_query) {
if let (Some(local), Some(mut global)) = (lq.get(current_id), gq.get_mut(current_id)) {
global.matrix = parent_matrix * local.local_matrix;
if let Some(cq) = &mut children_query {
if let Some(children) = cq.get(current_id) {
for &child_id in &children.0 {
if visited.insert(child_id) {
queue.push((global.matrix, child_id));
}
}
}
}
}
}
}
}
}
pub struct BoneAttachmentSystem;
impl gizmo_core::system::System for BoneAttachmentSystem {
fn access_info(&self) -> gizmo_core::system::AccessInfo {
let mut info = gizmo_core::system::AccessInfo::new();
info.is_exclusive = true;
info
}
fn run(&mut self, world: &gizmo_core::world::World, _dt: f32) {
if let Some(query) = world.query::<&gizmo_renderer::components::BoneAttachment>() {
let mut skeletons = world.query::<&gizmo_renderer::components::Skeleton>();
let mut transforms = unsafe {
world.query_unchecked::<gizmo_core::query::Mut<gizmo_physics_core::Transform>>()
};
for (id, attachment) in query.iter() {
if let Some(sq) = &mut skeletons {
if let Some(skeleton) = sq.get(attachment.target_entity.id()) {
if let Some(global_matrix) = skeleton.global_poses.get(attachment.bone_index) {
if let Some(tq) = &mut transforms {
if let Some(mut trans) = tq.get_mut(id) {
let final_mat = *global_matrix * attachment.offset;
let (t, r, s) = gizmo_renderer::decompose_mat4(final_mat);
trans.position = t;
trans.rotation = r;
trans.scale = s;
trans.update_local_matrix();
}
}
}
}
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use gizmo_core::component::Children;
use gizmo_core::system::System;
use gizmo_core::world::World;
use gizmo_physics_core::components::GlobalTransform;
use gizmo_physics_core::Transform;
#[test]
fn transform_propagate_terminates_on_children_cycle() {
let mut world = World::new();
let a = world.spawn();
let b = world.spawn();
world.add_component(a, Transform::default());
world.add_component(a, GlobalTransform::default());
world.add_component(b, Transform::default());
world.add_component(b, GlobalTransform::default());
world.add_component(a, Children(vec![b.id()]));
world.add_component(b, Children(vec![a.id()]));
let mut sys = TransformPropagateSystem;
sys.run(&world, 0.0);
}
}