101 lines
3.1 KiB
Rust
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)));
|
||
|
}
|
||
|
}
|