gltf_kun 0.0.6

Graph-based glTF processing library.
Documentation
use petgraph::{graph::NodeIndex, visit::EdgeRef};

use crate::graph::{Edge, Graph, GraphNode, Property, Weight};

use super::{node::Node, GltfEdge, GltfWeight};

#[derive(Debug, PartialEq, Eq)]
pub enum SceneEdge {
    Node,
}

#[derive(Debug, Default)]
pub struct SceneWeight {
    pub name: Option<String>,
    pub extras: gltf::json::Extras,
}

impl<'a> TryFrom<&'a Weight> for &'a SceneWeight {
    type Error = ();
    fn try_from(value: &'a Weight) -> Result<Self, Self::Error> {
        match value {
            Weight::Gltf(GltfWeight::Scene(weight)) => Ok(weight),
            _ => Err(()),
        }
    }
}

impl<'a> TryFrom<&'a mut Weight> for &'a mut SceneWeight {
    type Error = ();
    fn try_from(value: &'a mut Weight) -> Result<Self, Self::Error> {
        match value {
            Weight::Gltf(GltfWeight::Scene(weight)) => Ok(weight),
            _ => Err(()),
        }
    }
}

#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Scene(pub NodeIndex);

impl From<NodeIndex> for Scene {
    fn from(index: NodeIndex) -> Self {
        Self(index)
    }
}

impl From<Scene> for NodeIndex {
    fn from(scene: Scene) -> Self {
        scene.0
    }
}

impl GraphNode<SceneWeight> for Scene {}
impl Property for Scene {}

impl Scene {
    pub fn new(graph: &mut Graph) -> Self {
        let index = graph.add_node(Weight::Gltf(GltfWeight::Scene(SceneWeight::default())));
        Self(index)
    }

    pub fn nodes(&self, graph: &Graph) -> Vec<Node> {
        let mut vec = graph
            .edges_directed(self.0, petgraph::Direction::Outgoing)
            .filter_map(|edge| {
                if let Edge::Gltf(GltfEdge::Scene(SceneEdge::Node)) = edge.weight() {
                    Some(Node(edge.target()))
                } else {
                    None
                }
            })
            .collect::<Vec<_>>();

        vec.sort();

        vec
    }
    pub fn add_node(&self, graph: &mut Graph, node: &Node) {
        graph.add_edge(self.0, node.0, Edge::Gltf(GltfEdge::Scene(SceneEdge::Node)));
    }
    pub fn remove_node(&self, graph: &mut Graph, node: &Node) {
        let edge = graph
            .edges_directed(self.0, petgraph::Direction::Outgoing)
            .find(|edge| edge.target() == node.0)
            .expect("Child not found");

        graph.remove_edge(edge.id());
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_nodes() {
        let mut graph = Graph::default();
        let scene = Scene::new(&mut graph);

        let node = Node::new(&mut graph);
        scene.add_node(&mut graph, &node);

        let nodes = scene.nodes(&graph);
        assert_eq!(nodes.len(), 1);
        assert_eq!(nodes[0], node);

        scene.remove_node(&mut graph, &node);
        assert_eq!(scene.nodes(&graph).len(), 0);
    }
}