Make system_update_world_transforms also update world transforms for SceneGraphs
CI / build (push) Failing after 2m53s
Details
CI / build (push) Failing after 2m53s
Details
Before this couldn't be done since lyra-scene could not depend on lyra-resource, it would have caused a cyclic dependency. The last commit, where I created lyra-gltf from code inside lyra-resource, made this possible
This commit is contained in:
parent
5542467d7e
commit
4816b7333e
|
@ -90,7 +90,7 @@ impl<T: Component> AsQuery for Changed<T> {
|
||||||
type Query = Self;
|
type Query = Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: Component> Filter for Changed<T> { }
|
impl<T: Component> Filter for Changed<T> { }
|
||||||
|
|
||||||
impl<T: Component> AsFilter for Changed<T> {
|
impl<T: Component> AsFilter for Changed<T> {
|
||||||
type Filter = Self;
|
type Filter = Self;
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use crate::{query::{AsQuery, Query}, Archetype, Component, DynTypeId, World};
|
use crate::{query::{AsFilter, AsQuery, Filter, Query}, Archetype, Component, DynTypeId, World};
|
||||||
|
|
||||||
|
use super::StaticFetcher;
|
||||||
|
|
||||||
/// A filter query that fetches when the entity has the component `C`.
|
/// A filter query that fetches when the entity has the component `C`.
|
||||||
///
|
///
|
||||||
|
@ -20,9 +22,8 @@ impl<C: Component> Clone for Has<C> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Component> Query for Has<C> {
|
impl<C: Component> Query for Has<C> {
|
||||||
type Item<'a> = ();
|
type Item<'a> = bool;
|
||||||
|
type Fetch<'a> = StaticFetcher<bool>;
|
||||||
type Fetch<'a> = ();
|
|
||||||
|
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Has {
|
Has {
|
||||||
|
@ -35,10 +36,17 @@ impl<C: Component> Query for Has<C> {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn fetch<'a>(&self, _world: &'a World, _: &'a Archetype, _: crate::Tick) -> Self::Fetch<'a> {
|
unsafe fn fetch<'a>(&self, _world: &'a World, _: &'a Archetype, _: crate::Tick) -> Self::Fetch<'a> {
|
||||||
()
|
// if fetch is called, it means that 'can_visit_archetype' returned true
|
||||||
|
StaticFetcher::new(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Component> AsQuery for Has<C> {
|
impl<C: Component> AsQuery for Has<C> {
|
||||||
type Query = Self;
|
type Query = Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<C: Component> Filter for Has<C> { }
|
||||||
|
|
||||||
|
impl<C: Component> AsFilter for Has<C> {
|
||||||
|
type Filter = Self;
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
mod has;
|
mod has;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
pub use has::*;
|
pub use has::*;
|
||||||
|
|
||||||
mod or;
|
mod or;
|
||||||
|
@ -9,3 +11,34 @@ pub use not::*;
|
||||||
|
|
||||||
mod changed;
|
mod changed;
|
||||||
pub use changed::*;
|
pub use changed::*;
|
||||||
|
|
||||||
|
use super::Fetch;
|
||||||
|
|
||||||
|
/// A fetcher that just returns a provided value
|
||||||
|
pub struct StaticFetcher<T: Clone> {
|
||||||
|
value: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Clone> StaticFetcher<T> {
|
||||||
|
pub fn new(value: T) -> Self {
|
||||||
|
Self {
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<'a, T> Fetch<'a> for StaticFetcher<T>
|
||||||
|
where
|
||||||
|
T: Clone + 'a,
|
||||||
|
{
|
||||||
|
type Item = T;
|
||||||
|
|
||||||
|
fn dangling() -> Self {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn get_item(&mut self, _: crate::world::ArchetypeEntityId) -> Self::Item {
|
||||||
|
self.value.clone()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
use crate::{query::{AsQuery, Query}, Archetype, World};
|
use crate::{query::{AsFilter, AsQuery, Filter, Query}, Archetype, World};
|
||||||
|
|
||||||
|
use super::StaticFetcher;
|
||||||
|
|
||||||
/// A filter query that fetches the inverse of `Q`.
|
/// A filter query that fetches the inverse of `Q`.
|
||||||
///
|
///
|
||||||
|
@ -20,9 +22,8 @@ pub struct Not<Q: Query> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Q: Query> Query for Not<Q> {
|
impl<Q: Query> Query for Not<Q> {
|
||||||
type Item<'a> = ();
|
type Item<'a> = bool;
|
||||||
|
type Fetch<'a> = StaticFetcher<bool>;
|
||||||
type Fetch<'a> = ();
|
|
||||||
|
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Not {
|
Not {
|
||||||
|
@ -35,10 +36,17 @@ impl<Q: Query> Query for Not<Q> {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn fetch<'a>(&self, _world: &'a World, _: &'a Archetype, _: crate::Tick) -> Self::Fetch<'a> {
|
unsafe fn fetch<'a>(&self, _world: &'a World, _: &'a Archetype, _: crate::Tick) -> Self::Fetch<'a> {
|
||||||
()
|
// if fetch is called, it means that 'can_visit_archetype' returned true
|
||||||
|
StaticFetcher::new(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Q: Query> AsQuery for Not<Q> {
|
impl<Q: Query> AsQuery for Not<Q> {
|
||||||
type Query = Self;
|
type Query = Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<Q: Query> Filter for Not<Q> { }
|
||||||
|
|
||||||
|
impl<Q: Query> AsFilter for Not<Q> {
|
||||||
|
type Filter = Self;
|
||||||
|
}
|
|
@ -1,9 +1,8 @@
|
||||||
use lyra_ecs::{
|
use lyra_ecs::{
|
||||||
query::{
|
query::{
|
||||||
filter::{Has, Not, Or},
|
filter::Or,
|
||||||
Entities, TickOf,
|
Entities,
|
||||||
},
|
},
|
||||||
relation::{ChildOf, RelationOriginComponent},
|
|
||||||
Component, Entity,
|
Component, Entity,
|
||||||
};
|
};
|
||||||
use lyra_game_derive::RenderGraphLabel;
|
use lyra_game_derive::RenderGraphLabel;
|
||||||
|
@ -64,7 +63,6 @@ fn update_transforms(
|
||||||
buffers: &mut TransformBuffers,
|
buffers: &mut TransformBuffers,
|
||||||
parent_transform: Transform,
|
parent_transform: Transform,
|
||||||
) {
|
) {
|
||||||
let current_tick = world.current_tick();
|
|
||||||
let mut component_queue = vec![];
|
let mut component_queue = vec![];
|
||||||
|
|
||||||
let view = world.view_iter::<(
|
let view = world.view_iter::<(
|
||||||
|
@ -72,7 +70,7 @@ fn update_transforms(
|
||||||
Or<&WorldTransform, &Transform>,
|
Or<&WorldTransform, &Transform>,
|
||||||
Option<&mut InterpTransform>,
|
Option<&mut InterpTransform>,
|
||||||
Option<&TransformIndex>,
|
Option<&TransformIndex>,
|
||||||
Option<(&ResHandle<SceneGraph>, TickOf<ResHandle<SceneGraph>>)>,
|
Option<&ResHandle<SceneGraph>>,
|
||||||
)>();
|
)>();
|
||||||
|
|
||||||
for (entity, transform, interp_tran, transform_index, scene_graph) in view {
|
for (entity, transform, interp_tran, transform_index, scene_graph) in view {
|
||||||
|
@ -141,20 +139,8 @@ fn update_transforms(
|
||||||
glam::Mat3::from_quat(transform.rotation),
|
glam::Mat3::from_quat(transform.rotation),
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some((scene, scene_tick)) = scene_graph {
|
if let Some(scene) = scene_graph {
|
||||||
if let Some(mut scene) = scene.data_mut() {
|
if let Some(mut scene) = scene.data_mut() {
|
||||||
if *scene_tick + 1 >= *current_tick {
|
|
||||||
// Must manually call the world transform update system for scenes
|
|
||||||
// TODO: Separate gltf from lyra-resource so lyra-scene can depend on resource to
|
|
||||||
// query for scenes in the system.
|
|
||||||
let view = scene.world().view::<(
|
|
||||||
Entities,
|
|
||||||
&mut WorldTransform,
|
|
||||||
&Transform,
|
|
||||||
Not<Has<RelationOriginComponent<ChildOf>>>,
|
|
||||||
)>();
|
|
||||||
lyra_scene::system_update_world_transforms(scene.world(), view).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
update_transforms(
|
update_transforms(
|
||||||
device,
|
device,
|
||||||
|
|
|
@ -169,6 +169,7 @@ pub(crate) fn world_add_child_node<B: Bundle>(world: &mut World, parent: &SceneN
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use lyra_ecs::{query::{filter::{Has, Not}, Entities}, relation::{ChildOf, RelationOriginComponent}, Component};
|
use lyra_ecs::{query::{filter::{Has, Not}, Entities}, relation::{ChildOf, RelationOriginComponent}, Component};
|
||||||
use lyra_math::{Transform, Vec3};
|
use lyra_math::{Transform, Vec3};
|
||||||
|
use lyra_resource::ResHandle;
|
||||||
|
|
||||||
use crate::{lyra_engine, WorldTransform, SceneGraph};
|
use crate::{lyra_engine, WorldTransform, SceneGraph};
|
||||||
|
|
||||||
|
@ -205,7 +206,7 @@ pub mod tests {
|
||||||
let b = a.add_node(&mut scene, (WorldTransform::default(), Transform::from_translation(v2s[1]), FakeMesh));
|
let b = a.add_node(&mut scene, (WorldTransform::default(), Transform::from_translation(v2s[1]), FakeMesh));
|
||||||
assert!(b.parent(&scene).unwrap() == a);
|
assert!(b.parent(&scene).unwrap() == a);
|
||||||
|
|
||||||
let view = scene.world.view::<(Entities, &mut WorldTransform, &Transform, Not<Has<RelationOriginComponent<ChildOf>>>)>();
|
let view = scene.world.filtered_view::<(Entities, &mut WorldTransform, &Transform, Option<&ResHandle<SceneGraph>>), Not<Has<RelationOriginComponent<ChildOf>>>>();
|
||||||
crate::system_update_world_transforms(&scene.world, view).unwrap();
|
crate::system_update_world_transforms(&scene.world, view).unwrap();
|
||||||
|
|
||||||
let mut idx = 0;
|
let mut idx = 0;
|
||||||
|
|
|
@ -63,6 +63,7 @@ impl SceneNode {
|
||||||
mod tests {
|
mod tests {
|
||||||
use lyra_ecs::{query::{filter::{Has, Not}, Entities}, relation::{ChildOf, RelationOriginComponent}};
|
use lyra_ecs::{query::{filter::{Has, Not}, Entities}, relation::{ChildOf, RelationOriginComponent}};
|
||||||
use lyra_math::{Transform, Vec3};
|
use lyra_math::{Transform, Vec3};
|
||||||
|
use lyra_resource::ResHandle;
|
||||||
|
|
||||||
use crate::{tests::FakeMesh, WorldTransform, SceneGraph};
|
use crate::{tests::FakeMesh, WorldTransform, SceneGraph};
|
||||||
|
|
||||||
|
@ -77,7 +78,7 @@ mod tests {
|
||||||
assert!(b.parent(&scene).unwrap() == a);
|
assert!(b.parent(&scene).unwrap() == a);
|
||||||
|
|
||||||
// update global transforms
|
// update global transforms
|
||||||
let view = scene.world.view::<(Entities, &mut WorldTransform, &Transform, Not<Has<RelationOriginComponent<ChildOf>>>)>();
|
let view = scene.world.filtered_view::<(Entities, &mut WorldTransform, &Transform, Option<&ResHandle<SceneGraph>>), Not<Has<RelationOriginComponent<ChildOf>>>>();
|
||||||
crate::system_update_world_transforms(&scene.world, view).unwrap();
|
crate::system_update_world_transforms(&scene.world, view).unwrap();
|
||||||
|
|
||||||
let tran = scene.world.view_one::<&WorldTransform>(b.entity).get().unwrap();
|
let tran = scene.world.view_one::<&WorldTransform>(b.entity).get().unwrap();
|
||||||
|
|
|
@ -3,7 +3,8 @@ use std::ops::Deref;
|
||||||
use lyra_ecs::{query::{filter::{Has, Not}, Entities, View}, relation::{ChildOf, RelationOriginComponent}, Component, Entity, World};
|
use lyra_ecs::{query::{filter::{Has, Not}, Entities, View}, relation::{ChildOf, RelationOriginComponent}, Component, Entity, World};
|
||||||
use lyra_math::Transform;
|
use lyra_math::Transform;
|
||||||
use lyra_reflect::Reflect;
|
use lyra_reflect::Reflect;
|
||||||
use crate::lyra_engine;
|
use lyra_resource::ResHandle;
|
||||||
|
use crate::{lyra_engine, SceneGraph};
|
||||||
|
|
||||||
/// The world transform of an entity.
|
/// The world transform of an entity.
|
||||||
///
|
///
|
||||||
|
@ -34,42 +35,63 @@ impl From<Transform> for WorldTransform {
|
||||||
/// For entities without parents, this will update world transform to match local transform.
|
/// For entities without parents, this will update world transform to match local transform.
|
||||||
/// For any children entities, their [`WorldTransform`]s will be updated to reflect the changes
|
/// For any children entities, their [`WorldTransform`]s will be updated to reflect the changes
|
||||||
/// of its parent entity.
|
/// of its parent entity.
|
||||||
pub fn system_update_world_transforms(world: &World, view: View<(Entities, &mut WorldTransform, &Transform, Not<Has<RelationOriginComponent<ChildOf>>>)>) -> anyhow::Result<()> {
|
pub fn system_update_world_transforms(world: &World, view: View<(Entities, &mut WorldTransform, &Transform, Option<&ResHandle<SceneGraph>>), Not<Has<RelationOriginComponent<ChildOf>>>>) -> anyhow::Result<()> {
|
||||||
for (en, mut world_tran, tran, _) in view.into_iter() {
|
for (en, mut world_tran, tran, scene) in view.into_iter() {
|
||||||
world_tran.0 = *tran;
|
world_tran.0 = *tran;
|
||||||
recurse_update_trans(world, &world_tran, en);
|
recurse_update_trans(world, &world_tran, en)?;
|
||||||
|
|
||||||
|
// if there was a scene, update it as well
|
||||||
|
if let Some(scene) = scene {
|
||||||
|
if let Some(scene) = scene.data_ref() {
|
||||||
|
let sworld = &scene.world;
|
||||||
|
let view = sworld.filtered_view::<(Entities, &mut WorldTransform, &Transform, Option<&ResHandle<SceneGraph>>), Not<Has<RelationOriginComponent<ChildOf>>>>();
|
||||||
|
system_update_world_transforms(&scene.world, view)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recurse_update_trans(world: &World, parent_transform: &WorldTransform, entity: Entity) {
|
fn recurse_update_trans(world: &World, parent_transform: &WorldTransform, entity: Entity) -> anyhow::Result<()> {
|
||||||
// store entities and their world transform to process outside of the view.
|
// store entities and their world transform to process outside of the view.
|
||||||
// it must be done after to avoid attempts of multiple mutable borrows to the archetype column
|
// it must be done after to avoid attempts of multiple mutable borrows to the archetype column
|
||||||
// with WorldTransform.
|
// with WorldTransform.
|
||||||
let mut next_entities = vec![];
|
let mut next_entities = vec![];
|
||||||
|
|
||||||
for ((en, mut world_tran, tran), _) in
|
for ((en, mut world_tran, tran, scene), _) in
|
||||||
world.view::<(Entities, &mut WorldTransform, &Transform)>()
|
world.view::<(Entities, &mut WorldTransform, &Transform, Option<&ResHandle<SceneGraph>>)>()
|
||||||
.relates_to::<ChildOf>(entity)
|
.relates_to::<ChildOf>(entity)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
{
|
{
|
||||||
world_tran.0 = *tran;
|
world_tran.0 = *tran;
|
||||||
world_tran.0.translation = parent_transform.0.translation + tran.translation;
|
world_tran.0.translation = parent_transform.0.translation + tran.translation;
|
||||||
next_entities.push((en, world_tran.0.clone()));
|
next_entities.push((en, world_tran.0.clone()));
|
||||||
|
|
||||||
|
// if there was a scene, update it as well
|
||||||
|
if let Some(scene) = scene {
|
||||||
|
if let Some(scene) = scene.data_ref() {
|
||||||
|
let sworld = &scene.world;
|
||||||
|
let view = sworld.filtered_view::<(Entities, &mut WorldTransform, &Transform, Option<&ResHandle<SceneGraph>>), Not<Has<RelationOriginComponent<ChildOf>>>>();
|
||||||
|
system_update_world_transforms(&scene.world, view)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (en, pos) in next_entities.into_iter() {
|
for (en, pos) in next_entities.into_iter() {
|
||||||
recurse_update_trans(world, &WorldTransform(pos), en);
|
recurse_update_trans(world, &WorldTransform(pos), en)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use lyra_ecs::{query::{filter::{Has, Not}, Entities}, relation::{ChildOf, RelationOriginComponent}, World};
|
use lyra_ecs::{query::{filter::{Has, Not}, Entities}, relation::{ChildOf, RelationOriginComponent}, World};
|
||||||
use lyra_math::Transform;
|
use lyra_math::Transform;
|
||||||
|
use lyra_resource::ResHandle;
|
||||||
|
|
||||||
use crate::{system_update_world_transforms, WorldTransform};
|
use crate::{system_update_world_transforms, SceneGraph, WorldTransform};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_system() {
|
fn test_system() {
|
||||||
|
@ -79,7 +101,7 @@ mod tests {
|
||||||
let child = world.spawn((WorldTransform::default(), Transform::from_xyz(15.0, 15.0, 15.0)));
|
let child = world.spawn((WorldTransform::default(), Transform::from_xyz(15.0, 15.0, 15.0)));
|
||||||
world.add_relation(child, ChildOf, parent);
|
world.add_relation(child, ChildOf, parent);
|
||||||
|
|
||||||
let view = world.view::<(Entities, &mut WorldTransform, &Transform, Not<Has<RelationOriginComponent<ChildOf>>>)>();
|
let view = world.filtered_view::<(Entities, &mut WorldTransform, &Transform, Option<&ResHandle<SceneGraph>>), Not<Has<RelationOriginComponent<ChildOf>>>>();
|
||||||
system_update_world_transforms(&world, view).unwrap();
|
system_update_world_transforms(&world, view).unwrap();
|
||||||
|
|
||||||
let g = world.view_one::<&WorldTransform>(child).get().unwrap();
|
let g = world.view_one::<&WorldTransform>(child).get().unwrap();
|
||||||
|
@ -104,7 +126,7 @@ mod tests {
|
||||||
let second_child = world.spawn((WorldTransform::default(), Transform::from_xyz(5.0, 3.0, 8.0)));
|
let second_child = world.spawn((WorldTransform::default(), Transform::from_xyz(5.0, 3.0, 8.0)));
|
||||||
world.add_relation(second_child, ChildOf, parent);
|
world.add_relation(second_child, ChildOf, parent);
|
||||||
|
|
||||||
let view = world.view::<(Entities, &mut WorldTransform, &Transform, Not<Has<RelationOriginComponent<ChildOf>>>)>();
|
let view = world.filtered_view::<(Entities, &mut WorldTransform, &Transform, Option<&ResHandle<SceneGraph>>), Not<Has<RelationOriginComponent<ChildOf>>>>();
|
||||||
system_update_world_transforms(&world, view).unwrap();
|
system_update_world_transforms(&world, view).unwrap();
|
||||||
|
|
||||||
let mut base_offset = 25.0;
|
let mut base_offset = 25.0;
|
||||||
|
@ -137,7 +159,7 @@ mod tests {
|
||||||
let five_child = world.spawn((WorldTransform::default(), Transform::from_xyz(356.0, 54.0, 786.0)));
|
let five_child = world.spawn((WorldTransform::default(), Transform::from_xyz(356.0, 54.0, 786.0)));
|
||||||
world.add_relation(five_child, ChildOf, four_child);
|
world.add_relation(five_child, ChildOf, four_child);
|
||||||
|
|
||||||
let view = world.view::<(Entities, &mut WorldTransform, &Transform, Not<Has<RelationOriginComponent<ChildOf>>>)>();
|
let view = world.filtered_view::<(Entities, &mut WorldTransform, &Transform, Option<&ResHandle<SceneGraph>>), Not<Has<RelationOriginComponent<ChildOf>>>>();
|
||||||
system_update_world_transforms(&world, view).unwrap();
|
system_update_world_transforms(&world, view).unwrap();
|
||||||
|
|
||||||
let g = world.view_one::<&WorldTransform>(five_child).get().unwrap();
|
let g = world.view_one::<&WorldTransform>(five_child).get().unwrap();
|
||||||
|
@ -164,7 +186,7 @@ mod tests {
|
||||||
let five_child = world.spawn((WorldTransform::default(), Transform::from_xyz(356.0, 54.0, 786.0)));
|
let five_child = world.spawn((WorldTransform::default(), Transform::from_xyz(356.0, 54.0, 786.0)));
|
||||||
world.add_relation(five_child, ChildOf, sec_chi);
|
world.add_relation(five_child, ChildOf, sec_chi);
|
||||||
|
|
||||||
let view = world.view::<(Entities, &mut WorldTransform, &Transform, Not<Has<RelationOriginComponent<ChildOf>>>)>();
|
let view = world.filtered_view::<(Entities, &mut WorldTransform, &Transform, Option<&ResHandle<SceneGraph>>), Not<Has<RelationOriginComponent<ChildOf>>>>();
|
||||||
system_update_world_transforms(&world, view).unwrap();
|
system_update_world_transforms(&world, view).unwrap();
|
||||||
|
|
||||||
let g = world.view_one::<&WorldTransform>(five_child).get().unwrap();
|
let g = world.view_one::<&WorldTransform>(five_child).get().unwrap();
|
||||||
|
|
Loading…
Reference in New Issue