lyra-engine/crates/lyra-scene/src/node.rs

87 lines
2.9 KiB
Rust

use lyra_ecs::{query::Entities, relation::{ChildOf, RelationOriginComponent}, Bundle, Entity};
use lyra_reflect::Reflect;
use crate::{SceneGraph, lyra_engine};
/// A node inside of the Scene
#[derive(Clone, PartialEq, Eq, Reflect)]
pub struct SceneNode {
#[reflect(skip)]
parent: Option<Entity>,
#[reflect(skip)]
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.
pub fn add_node<B: Bundle>(&self, graph: &mut SceneGraph, bundle: B) -> SceneNode {
graph.add_node_under(self, bundle)
}
}
#[cfg(test)]
mod tests {
use lyra_ecs::{query::{filter::{Has, Not}, Entities}, relation::{ChildOf, RelationOriginComponent}};
use lyra_math::{Transform, Vec3};
use lyra_resource::ResHandle;
use crate::{tests::FakeMesh, WorldTransform, SceneGraph};
#[test]
fn node_world_transform() {
let mut scene = SceneGraph::new();
let a = scene.add_node((WorldTransform::default(), Transform::from_translation(Vec3::new(10.0, 10.0, 10.0)), FakeMesh));
assert!(a.parent(&scene).unwrap() == scene.root_node);
let b = a.add_node(&mut scene, (WorldTransform::default(), Transform::from_translation(Vec3::new(50.0, 50.0, 50.0)), FakeMesh));
assert!(b.parent(&scene).unwrap() == a);
// update global transforms
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();
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)));
}
}