1use shiv::{
2 hierarchy::{Children, Parent},
3 query::{Changed, Query, With, Without},
4 schedule::SystemLabel,
5 world::Entity,
6};
7
8use crate::{GlobalTransform, Transform};
9
10pub fn transform_system(
11 mut root_query: Query<
12 (
13 Entity,
14 Option<(&Children, Changed<Children>)>,
15 &Transform,
16 Changed<Transform>,
17 &mut GlobalTransform,
18 ),
19 Without<Parent>,
20 >,
21 mut transform_query: Query<(
22 &Transform,
23 Changed<Transform>,
24 &mut GlobalTransform,
25 &Parent,
26 )>,
27 children_query: Query<(&Children, Changed<Children>), (With<Parent>, With<GlobalTransform>)>,
28) {
29 for (entity, children, transform, transform_changed, mut global_transform) in &mut root_query {
30 let mut changed = transform_changed;
31 if transform_changed {
32 *global_transform = transform.into();
33 }
34
35 if let Some((children, children_changed)) = children {
36 changed |= children_changed;
37 for &child in children.iter() {
38 propagate_recursive(
39 child,
40 entity,
41 changed,
42 *global_transform,
43 &mut transform_query,
44 &children_query,
45 );
46 }
47 }
48 }
49}
50
51#[inline]
52fn propagate_recursive(
53 entity: Entity,
54 expected_parent: Entity,
55 mut changed: bool,
56 parent: GlobalTransform,
57 transform_query: &mut Query<(
58 &Transform,
59 Changed<Transform>,
60 &mut GlobalTransform,
61 &Parent,
62 )>,
63 children_query: &Query<(&Children, Changed<Children>), (With<Parent>, With<GlobalTransform>)>,
64) -> Option<()> {
65 let (&transform, transform_changed, mut global_transform, child_parent) =
66 transform_query.get_mut(entity)?;
67
68 assert_eq!(
69 child_parent.entity(),
70 expected_parent,
71 "Malformed hierarchy"
72 );
73
74 changed |= transform_changed;
75 if changed {
76 *global_transform = parent * transform;
77 }
78
79 let global_transform = global_transform.clone();
80
81 let (children, children_changed) = children_query.get(entity)?;
82 changed |= children_changed;
83
84 for &child in children.iter() {
85 propagate_recursive(
86 child,
87 entity,
88 changed,
89 global_transform,
90 transform_query,
91 children_query,
92 );
93 }
94
95 Some(())
96}
97
98#[derive(SystemLabel)]
99pub struct TransformSystem;