Skip to main content

shiv_transform/
system.rs

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;