Skip to content

Commit 358f2b8

Browse files
committed
add Transform2d to propagation
1 parent 505b495 commit 358f2b8

File tree

6 files changed

+112
-46
lines changed

6 files changed

+112
-46
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
mod global_transform;
22
mod transform_2d;
33
mod transform_3d;
4+
mod tree_changed;
45

56
pub use global_transform::*;
67
pub use transform_2d::*;
78
pub use transform_3d::*;
9+
pub(crate) use tree_changed::TransformTreeChanged;

crates/bevy_transform/src/components/transform_2d.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,30 @@
1+
use super::{GlobalTransform, TransformTreeChanged};
2+
use bevy_math::{Affine2, Affine3A, Dir2, Isometry2d, Mat3, Quat, Rot2, Vec2, Vec3};
13
use core::ops::Mul;
24

3-
use bevy_math::{Affine2, Affine3A, Dir2, Isometry2d, Mat3, Quat, Rot2, Vec2, Vec3};
5+
#[cfg(feature = "bevy-support")]
6+
use bevy_ecs::component::Component;
47

5-
use super::GlobalTransform;
8+
#[cfg(feature = "bevy_reflect")]
9+
use {bevy_ecs::reflect::ReflectComponent, bevy_reflect::prelude::*};
610

711
/// TODO
12+
#[derive(Debug, PartialEq, Clone, Copy)]
13+
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
14+
#[cfg_attr(
15+
feature = "bevy-support",
16+
derive(Component),
17+
require(GlobalTransform, TransformTreeChanged)
18+
)]
19+
#[cfg_attr(
20+
feature = "bevy_reflect",
21+
derive(Reflect),
22+
reflect(Component, Default, PartialEq, Debug, Clone)
23+
)]
24+
#[cfg_attr(
25+
all(feature = "bevy_reflect", feature = "serialize"),
26+
reflect(Serialize, Deserialize)
27+
)]
828
pub struct Transform2d {
929
/// TODO
1030
pub translation: Vec2,

crates/bevy_transform/src/components/transform_3d.rs

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::GlobalTransform;
1+
use super::{GlobalTransform, TransformTreeChanged};
22
use bevy_math::{Affine3A, Dir3, Isometry3d, Mat3, Mat4, Quat, Vec3};
33
use core::ops::Mul;
44

@@ -650,20 +650,3 @@ impl Mul<Vec3> for Transform3d {
650650
self.transform_point(value)
651651
}
652652
}
653-
654-
/// An optimization for transform propagation. This ZST marker component uses change detection to
655-
/// mark all entities of the hierarchy as "dirty" if any of their descendants have a changed
656-
/// `Transform3d`. If this component is *not* marked `is_changed()`, propagation will halt.
657-
#[derive(Clone, Copy, Default, PartialEq, Debug)]
658-
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
659-
#[cfg_attr(feature = "bevy-support", derive(Component))]
660-
#[cfg_attr(
661-
feature = "bevy_reflect",
662-
derive(Reflect),
663-
reflect(Component, Default, PartialEq, Debug)
664-
)]
665-
#[cfg_attr(
666-
all(feature = "bevy_reflect", feature = "serialize"),
667-
reflect(Serialize, Deserialize)
668-
)]
669-
pub struct TransformTreeChanged;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#[cfg(feature = "bevy-support")]
2+
use bevy_ecs::component::Component;
3+
4+
#[cfg(feature = "bevy_reflect")]
5+
use {bevy_ecs::reflect::ReflectComponent, bevy_reflect::prelude::*};
6+
7+
/// An optimization for transform propagation. This ZST marker component uses change detection to
8+
/// mark all entities of the hierarchy as "dirty" if any of their descendants have a changed
9+
/// `Transform3d`. If this component is *not* marked `is_changed()`, propagation will halt.
10+
#[derive(Clone, Copy, Default, PartialEq, Debug)]
11+
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
12+
#[cfg_attr(feature = "bevy-support", derive(Component))]
13+
#[cfg_attr(
14+
feature = "bevy_reflect",
15+
derive(Reflect),
16+
reflect(Component, Default, PartialEq, Debug)
17+
)]
18+
#[cfg_attr(
19+
all(feature = "bevy_reflect", feature = "serialize"),
20+
reflect(Serialize, Deserialize)
21+
)]
22+
pub struct TransformTreeChanged;

crates/bevy_transform/src/plugins.rs

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use crate::systems::{mark_dirty_trees, propagate_parent_transforms, sync_simple_
22
use bevy_app::{App, Plugin, PostStartup, PostUpdate};
33
use bevy_ecs::schedule::{IntoScheduleConfigs, SystemSet};
44

5+
use crate::components::{GlobalTransform, Transform2d, Transform3d, TransformTreeChanged};
6+
57
/// Set enum for the systems relating to transform propagation
68
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
79
pub enum TransformSystems {
@@ -20,31 +22,40 @@ pub struct TransformPlugin;
2022
impl Plugin for TransformPlugin {
2123
fn build(&self, app: &mut App) {
2224
#[cfg(feature = "bevy_reflect")]
23-
app.register_type::<crate::components::Transform3d>()
24-
.register_type::<crate::components::TransformTreeChanged>()
25-
.register_type::<crate::components::GlobalTransform>();
25+
app.register_type::<Transform3d>()
26+
.register_type::<TransformTreeChanged>()
27+
.register_type::<GlobalTransform>();
2628

2729
app
2830
// add transform systems to startup so the first update is "correct"
31+
.add_systems(
32+
PostStartup,
33+
(mark_dirty_trees, propagate_parent_transforms)
34+
.chain()
35+
.in_set(TransformSystems::Propagate),
36+
)
2937
.add_systems(
3038
PostStartup,
3139
(
32-
mark_dirty_trees,
33-
propagate_parent_transforms,
34-
sync_simple_transforms,
40+
sync_simple_transforms::<Transform3d>,
41+
sync_simple_transforms::<Transform2d>,
3542
)
43+
.after(propagate_parent_transforms)
44+
.in_set(TransformSystems::Propagate),
45+
)
46+
.add_systems(
47+
PostUpdate,
48+
(mark_dirty_trees, propagate_parent_transforms)
3649
.chain()
3750
.in_set(TransformSystems::Propagate),
3851
)
3952
.add_systems(
4053
PostUpdate,
4154
(
42-
mark_dirty_trees,
43-
propagate_parent_transforms,
44-
// TODO: Adjust the internal parallel queries to make this system more efficiently share and fill CPU time.
45-
sync_simple_transforms,
55+
sync_simple_transforms::<Transform3d>,
56+
sync_simple_transforms::<Transform2d>,
4657
)
47-
.chain()
58+
.after(propagate_parent_transforms)
4859
.in_set(TransformSystems::Propagate),
4960
);
5061
}

crates/bevy_transform/src/systems.rs

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::components::{GlobalTransform, Transform3d, TransformTreeChanged};
1+
use crate::components::{GlobalTransform, Transform2d, Transform3d, TransformTreeChanged};
22
use bevy_ecs::prelude::*;
33
#[cfg(feature = "std")]
44
pub use parallel::propagate_parent_transforms;
@@ -9,33 +9,35 @@ pub use serial::propagate_parent_transforms;
99
///
1010
/// Third party plugins should ensure that this is used in concert with
1111
/// [`propagate_parent_transforms`] and [`mark_dirty_trees`].
12-
pub fn sync_simple_transforms(
12+
pub fn sync_simple_transforms<T>(
1313
mut query: ParamSet<(
1414
Query<
15-
(&Transform3d, &mut GlobalTransform),
15+
(&T, &mut GlobalTransform),
1616
(
17-
Or<(Changed<Transform3d>, Added<GlobalTransform>)>,
17+
Or<(Changed<T>, Added<GlobalTransform>)>,
1818
Without<ChildOf>,
1919
Without<Children>,
2020
),
2121
>,
22-
Query<(Ref<Transform3d>, &mut GlobalTransform), (Without<ChildOf>, Without<Children>)>,
22+
Query<(Ref<T>, &mut GlobalTransform), (Without<ChildOf>, Without<Children>)>,
2323
)>,
2424
mut orphaned: RemovedComponents<ChildOf>,
25-
) {
25+
) where
26+
T: Copy + Clone + Component + Into<GlobalTransform>,
27+
{
2628
// Update changed entities.
2729
query
2830
.p0()
2931
.par_iter_mut()
3032
.for_each(|(transform, mut global_transform)| {
31-
*global_transform = GlobalTransform::from(*transform);
33+
*global_transform = (*transform).into();
3234
});
3335
// Update orphaned entities.
3436
let mut query = query.p1();
3537
let mut iter = query.iter_many_mut(orphaned.read());
3638
while let Some((transform, mut global_transform)) = iter.fetch_next() {
3739
if !transform.is_changed() && !global_transform.is_added() {
38-
*global_transform = GlobalTransform::from(*transform);
40+
*global_transform = (*transform).into();
3941
}
4042
}
4143
}
@@ -48,6 +50,7 @@ pub fn mark_dirty_trees(
4850
Entity,
4951
Or<(
5052
Changed<Transform3d>,
53+
Changed<Transform2d>,
5154
Changed<ChildOf>,
5255
Added<GlobalTransform>,
5356
)>,
@@ -107,7 +110,11 @@ mod serial {
107110
>,
108111
mut orphaned: RemovedComponents<ChildOf>,
109112
transform_query: Query<
110-
(Ref<Transform3d>, &mut GlobalTransform, Option<&Children>),
113+
(
114+
AnyOf<(Ref<Transform3d>, Ref<Transform2d>)>,
115+
&mut GlobalTransform,
116+
Option<&Children>,
117+
),
111118
With<ChildOf>,
112119
>,
113120
child_query: Query<(Entity, Ref<ChildOf>), With<GlobalTransform>>,
@@ -120,7 +127,7 @@ mod serial {
120127
|(entity, children, transform, mut global_transform)| {
121128
let changed = transform.is_changed() || global_transform.is_added() || orphaned_entities.binary_search(&entity).is_ok();
122129
if changed {
123-
*global_transform = GlobalTransform::from(*transform);
130+
*global_transform = local_to_global(transform);
124131
}
125132

126133
for (child, child_of) in child_query.iter_many(children) {
@@ -175,7 +182,11 @@ mod serial {
175182
unsafe fn propagate_recursive(
176183
parent: &GlobalTransform,
177184
transform_query: &Query<
178-
(Ref<Transform3d>, &mut GlobalTransform, Option<&Children>),
185+
(
186+
AnyOf<(Ref<Transform3d>, Ref<Transform2d>)>,
187+
&mut GlobalTransform,
188+
Option<&Children>,
189+
),
179190
With<ChildOf>,
180191
>,
181192
child_query: &Query<(Entity, Ref<ChildOf>), With<GlobalTransform>>,
@@ -252,6 +263,7 @@ mod serial {
252263
/// the serial version.
253264
#[cfg(feature = "std")]
254265
mod parallel {
266+
use super::local_to_global;
255267
use crate::prelude::*;
256268
// TODO: this implementation could be used in no_std if there are equivalents of these.
257269
use alloc::{sync::Arc, vec::Vec};
@@ -273,7 +285,12 @@ mod parallel {
273285
pub fn propagate_parent_transforms(
274286
mut queue: Local<WorkQueue>,
275287
mut roots: Query<
276-
(Entity, Ref<Transform3d>, &mut GlobalTransform, &Children),
288+
(
289+
Entity,
290+
AnyOf<(Ref<Transform3d>, Ref<Transform2d>)>,
291+
&mut GlobalTransform,
292+
&Children,
293+
),
277294
(Without<ChildOf>, Changed<TransformTreeChanged>),
278295
>,
279296
nodes: NodeQuery,
@@ -282,7 +299,7 @@ mod parallel {
282299
roots.par_iter_mut().for_each_init(
283300
|| queue.local_queue.borrow_local_mut(),
284301
|outbox, (parent, transform, mut parent_transform, children)| {
285-
*parent_transform = GlobalTransform::from(*transform);
302+
*parent_transform = local_to_global(transform);
286303

287304
// SAFETY: the parent entities passed into this function are taken from iterating
288305
// over the root entity query. Queries iterate over disjoint entities, preventing
@@ -460,7 +477,8 @@ mod parallel {
460477

461478
// Transform prop is expensive - this helps avoid updating entire subtrees if
462479
// the GlobalTransform is unchanged, at the cost of an added equality check.
463-
global_transform.set_if_neq(p_global_transform.mul_transform(*transform));
480+
let child_global = local_to_global(transform);
481+
global_transform.set_if_neq(*p_global_transform * child_global);
464482

465483
children.map(|children| {
466484
// Only continue propagation if the entity has children.
@@ -499,7 +517,7 @@ mod parallel {
499517
(
500518
Entity,
501519
(
502-
Ref<'static, Transform3d>,
520+
AnyOf<(Ref<'static, Transform3d>, Ref<'static, Transform2d>)>,
503521
Mut<'static, GlobalTransform>,
504522
Ref<'static, TransformTreeChanged>,
505523
),
@@ -557,6 +575,16 @@ mod parallel {
557575
}
558576
}
559577

578+
fn local_to_global(
579+
any_of: (Option<Ref<'_, Transform3d>>, Option<Ref<'_, Transform2d>>),
580+
) -> GlobalTransform {
581+
match any_of {
582+
(Some(transform_3d), _) => GlobalTransform::from(*transform_3d),
583+
(_, Some(transform_2d)) => GlobalTransform::from(*transform_2d),
584+
_ => unreachable!(),
585+
}
586+
}
587+
560588
#[cfg(test)]
561589
mod test {
562590
use alloc::{vec, vec::Vec};

0 commit comments

Comments
 (0)