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

101 lines
3.1 KiB
Rust

use lyra_ecs::{query::Entities, relation::{ChildOf, RelationOriginComponent}, Bundle, Entity};
use lyra_math::Transform;
use crate::SceneGraph;
#[derive(Clone, PartialEq, Eq)]
pub struct SceneNode {
//world: WorldLock,
parent: Option<Entity>,
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, local_transform: Transform, bundle: B) -> SceneNode {
graph.add_node_under(self, local_transform, bundle)
}
pub fn local_transform(&self, graph: &SceneGraph) -> Transform {
let v = graph.world.view_one::<&Transform>(self.entity);
let t = v.get().expect("Somehow the SceneNode is missing its Transform!");
t.clone()
}
/// Retrieves the world transform of the Node.
///
/// This traverses up the SceneGraph from this node.
pub fn world_transform(&self, graph: &SceneGraph) -> Transform {
match self.parent(graph) {
Some(parent) => {
let pt = parent.world_transform(graph);
pt + self.local_transform(graph)
},
None => {
self.local_transform(graph)
}
}
}
}
#[cfg(test)]
mod tests {
use lyra_math::{Transform, Vec3};
use crate::{tests::FakeMesh, SceneGraph};
#[test]
fn node_world_transform() {
let mut scene = SceneGraph::new();
let a = scene.add_node(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, Transform::from_translation(Vec3::new(50.0, 50.0, 50.0)), FakeMesh);
assert!(b.parent(&scene).unwrap() == a);
let wrld_tran = b.world_transform(&scene);
assert_eq!(wrld_tran, Transform::from_translation(Vec3::new(60.0, 60.0, 60.0)));
}
}