2024-03-03 21:21:55 +00:00
|
|
|
use lyra_ecs::{query::Entities, relation::{ChildOf, RelationOriginComponent}, Bundle, Entity};
|
2024-04-27 04:52:47 +00:00
|
|
|
use lyra_reflect::Reflect;
|
2024-03-03 21:21:55 +00:00
|
|
|
|
2024-04-27 04:52:47 +00:00
|
|
|
use crate::{SceneGraph, lyra_engine};
|
2024-03-03 21:21:55 +00:00
|
|
|
|
2024-04-11 03:55:48 +00:00
|
|
|
/// A node inside of the Scene
|
2024-04-27 04:52:47 +00:00
|
|
|
#[derive(Clone, PartialEq, Eq, Reflect)]
|
2024-03-03 21:21:55 +00:00
|
|
|
pub struct SceneNode {
|
2024-04-27 04:52:47 +00:00
|
|
|
#[reflect(skip)]
|
2024-03-03 21:21:55 +00:00
|
|
|
parent: Option<Entity>,
|
2024-04-27 04:52:47 +00:00
|
|
|
#[reflect(skip)]
|
2024-03-03 21:21:55 +00:00
|
|
|
entity: Entity
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SceneNode {
|
|
|
|
pub fn new(parent: Option<Entity>, entity: Entity) -> Self {
|
|
|
|
Self {
|
|
|
|
parent,
|
|
|
|
entity,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// If this node has a parent, retrieves the parent node from the SceneGraph.
|
|
|
|
pub fn parent(&self, graph: &SceneGraph) -> Option<SceneNode> {
|
|
|
|
if let Some(parent) = self.parent {
|
|
|
|
let v = graph.world.view_one::<&RelationOriginComponent<ChildOf>>(parent);
|
|
|
|
|
|
|
|
let p_parent = if let Some(pp) = v.get() {
|
|
|
|
Some(pp.target())
|
|
|
|
} else { None };
|
|
|
|
|
|
|
|
Some(SceneNode::new(p_parent, parent))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn parent_entity(&self) -> Option<Entity> {
|
|
|
|
self.parent
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn children(&self, graph: &SceneGraph) -> Vec<SceneNode> {
|
|
|
|
let v = graph.world.view::<Entities>()
|
|
|
|
.relates_to::<ChildOf>(self.entity);
|
|
|
|
|
|
|
|
v.into_iter().map(|(e, _)| SceneNode::new(Some(self.entity), e)).collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn entity(&self) -> Entity {
|
|
|
|
self.entity
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Add a child node to this node.
|
|
|
|
///
|
|
|
|
/// The spawned entity backing the scene node will have a `ChildOf` relation targeting
|
|
|
|
/// the provided parent node, the `SceneNodeFlag` component is also added to the entity.
|
2024-04-11 03:45:25 +00:00
|
|
|
pub fn add_node<B: Bundle>(&self, graph: &mut SceneGraph, bundle: B) -> SceneNode {
|
|
|
|
graph.add_node_under(self, bundle)
|
2024-03-03 21:21:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2024-04-11 03:45:25 +00:00
|
|
|
use lyra_ecs::{query::{filter::{Has, Not}, Entities}, relation::{ChildOf, RelationOriginComponent}};
|
2024-03-03 21:21:55 +00:00
|
|
|
use lyra_math::{Transform, Vec3};
|
|
|
|
|
2024-04-11 03:45:25 +00:00
|
|
|
use crate::{tests::FakeMesh, WorldTransform, SceneGraph};
|
2024-03-03 21:21:55 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn node_world_transform() {
|
|
|
|
let mut scene = SceneGraph::new();
|
|
|
|
|
2024-04-11 03:45:25 +00:00
|
|
|
let a = scene.add_node((WorldTransform::default(), Transform::from_translation(Vec3::new(10.0, 10.0, 10.0)), FakeMesh));
|
2024-03-03 21:21:55 +00:00
|
|
|
assert!(a.parent(&scene).unwrap() == scene.root_node);
|
|
|
|
|
2024-04-11 03:45:25 +00:00
|
|
|
let b = a.add_node(&mut scene, (WorldTransform::default(), Transform::from_translation(Vec3::new(50.0, 50.0, 50.0)), FakeMesh));
|
2024-03-03 21:21:55 +00:00
|
|
|
assert!(b.parent(&scene).unwrap() == a);
|
|
|
|
|
2024-04-11 03:45:25 +00:00
|
|
|
// update global transforms
|
|
|
|
let view = scene.world.view::<(Entities, &mut WorldTransform, &Transform, Not<Has<RelationOriginComponent<ChildOf>>>)>();
|
|
|
|
crate::system_update_world_transforms(&scene.world, view).unwrap();
|
|
|
|
|
|
|
|
let tran = scene.world.view_one::<&WorldTransform>(b.entity).get().unwrap();
|
|
|
|
assert_eq!(**tran, Transform::from_translation(Vec3::new(60.0, 60.0, 60.0)));
|
2024-03-03 21:21:55 +00:00
|
|
|
}
|
|
|
|
}
|