1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
use shiv::{
    hierarchy::{Children, Parent},
    query::{Changed, Query, With, Without},
    schedule::SystemLabel,
    world::Entity,
};

use crate::{GlobalTransform, Transform};

pub fn transform_system(
    mut root_query: Query<
        (
            Entity,
            Option<(&Children, Changed<Children>)>,
            &Transform,
            Changed<Transform>,
            &mut GlobalTransform,
        ),
        Without<Parent>,
    >,
    mut transform_query: Query<(
        &Transform,
        Changed<Transform>,
        &mut GlobalTransform,
        &Parent,
    )>,
    children_query: Query<(&Children, Changed<Children>), (With<Parent>, With<GlobalTransform>)>,
) {
    for (entity, children, transform, transform_changed, mut global_transform) in &mut root_query {
        let mut changed = transform_changed;
        if transform_changed {
            *global_transform = transform.into();
        }

        if let Some((children, children_changed)) = children {
            changed |= children_changed;
            for &child in children.iter() {
                propagate_recursive(
                    child,
                    entity,
                    changed,
                    *global_transform,
                    &mut transform_query,
                    &children_query,
                );
            }
        }
    }
}

#[inline]
fn propagate_recursive(
    entity: Entity,
    expected_parent: Entity,
    mut changed: bool,
    parent: GlobalTransform,
    transform_query: &mut Query<(
        &Transform,
        Changed<Transform>,
        &mut GlobalTransform,
        &Parent,
    )>,
    children_query: &Query<(&Children, Changed<Children>), (With<Parent>, With<GlobalTransform>)>,
) -> Option<()> {
    let (&transform, transform_changed, mut global_transform, child_parent) =
        transform_query.get_mut(entity)?;

    assert_eq!(
        child_parent.entity(),
        expected_parent,
        "Malformed hierarchy"
    );

    changed |= transform_changed;
    if changed {
        *global_transform = parent * transform;
    }

    let global_transform = global_transform.clone();

    let (children, children_changed) = children_query.get(entity)?;
    changed |= children_changed;

    for &child in children.iter() {
        propagate_recursive(
            child,
            entity,
            changed,
            global_transform,
            transform_query,
            children_query,
        );
    }

    Some(())
}

#[derive(SystemLabel)]
pub struct TransformSystem;