From aa6840a27b3e313e9f9b0c4067355dfb25b717b2 Mon Sep 17 00:00:00 2001 From: Kayh Date: Thu, 9 Nov 2023 18:14:40 -0500 Subject: [PATCH] set up basic graph --- Cargo.lock | 1 + README.md | 2 + core/Cargo.toml | 1 + core/examples/read.rs | 12 ++--- core/src/graph.rs | 36 +++++++++++++++ core/src/lib.rs | 100 +++++++++++++++++++++++++++++++++++++++++- 6 files changed, 143 insertions(+), 9 deletions(-) create mode 100644 core/src/graph.rs diff --git a/Cargo.lock b/Cargo.lock index 0e7a53c..7bbe68c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1863,6 +1863,7 @@ name = "gltf_kun" version = "0.0.0" dependencies = [ "gltf", + "petgraph", ] [[package]] diff --git a/README.md b/README.md index 1b83b66..8993c98 100644 --- a/README.md +++ b/README.md @@ -6,3 +6,5 @@ [![Documentation](https://docs.rs/gltf_kun/badge.svg)](https://docs.rs/gltf_kun) Extensible library for building [glTF](https://github.com/KhronosGroup/glTF) toolchains. + +Builds upon the lower level [`gltf`](https://github.com/gltf-rs/gltf) crate to create a traversable graph of the glTF document. diff --git a/core/Cargo.toml b/core/Cargo.toml index 1776240..7a74e3e 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -24,3 +24,4 @@ gltf = { version = "1.3.0", features = [ "KHR_materials_specular", "KHR_materials_emissive_strength", ] } +petgraph = "0.6.4" diff --git a/core/examples/read.rs b/core/examples/read.rs index 6b26cf6..2893f24 100644 --- a/core/examples/read.rs +++ b/core/examples/read.rs @@ -1,16 +1,12 @@ -use std::{fs, io}; - const CARGO_MANIFEST_DIR: &str = env!("CARGO_MANIFEST_DIR"); const ASSETS_DIR: &str = "../assets"; - const MODEL: &str = "TriangleWithoutIndices/TriangleWithoutIndices.gltf"; fn main() { let path = format!("{}/{}/{}", CARGO_MANIFEST_DIR, ASSETS_DIR, MODEL); + let gltf = gltf_kun::import(&path).unwrap(); - let file = fs::File::open(path).unwrap(); - let reader = io::BufReader::new(file); - let gltf = gltf_kun::Gltf::from_reader(reader).unwrap(); - - println!("{:#?}", gltf); + gltf.nodes().iter().for_each(|node| { + println!("{:#?}", node.data()); + }); } diff --git a/core/src/graph.rs b/core/src/graph.rs new file mode 100644 index 0000000..3cd91f4 --- /dev/null +++ b/core/src/graph.rs @@ -0,0 +1,36 @@ +pub struct AssetData { + pub version: String, + pub generator: Option, + pub extensions_used: Vec, + pub extensions_required: Vec, +} + +pub struct MeshData { + pub name: Option, +} + +#[derive(Debug)] +pub struct NodeData { + pub name: Option, + pub translation: [f32; 3], + pub rotation: [f32; 4], + pub scale: [f32; 3], +} + +pub struct SceneData { + pub name: Option, +} + +pub enum GraphNode { + Asset(AssetData), + Mesh(MeshData), + Node(NodeData), + Scene(SceneData), +} + +pub enum GraphEdge { + Parent, + Child, +} + +pub type GltfGraph = petgraph::graph::DiGraph; diff --git a/core/src/lib.rs b/core/src/lib.rs index e23f481..6c9f4fb 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -1 +1,99 @@ -pub use gltf::*; +use std::collections::HashMap; +use std::sync::Arc; + +mod graph; + +use graph::*; +use petgraph::graph::NodeIndex; +use petgraph::visit::EdgeRef; + +pub struct Node { + graph: Arc, + index: NodeIndex, +} + +impl Node { + pub fn data(&self) -> &NodeData { + match &self.graph[self.index] { + GraphNode::Node(node) => node, + _ => panic!("Node is not a NodeData"), + } + } + + pub fn children(&self) -> Vec { + self.graph + .edges(self.index) + .filter_map(|edge| { + let index = match edge.weight() { + GraphEdge::Child => edge.target(), + _ => return None, + }; + + Some(Node { + graph: self.graph.clone(), + index, + }) + }) + .collect() + } +} + +pub struct Gltf { + graph: Arc, +} + +impl Gltf { + /// Create a new Gltf from json + pub fn from_json(json: &gltf::json::Root) -> Self { + let mut graph = GltfGraph::new(); + let mut nodes = HashMap::new(); + + json.nodes.iter().enumerate().for_each(|(i, node)| { + let graph_node = graph.add_node(GraphNode::Node(NodeData { + name: node.name.clone(), + translation: node.translation.unwrap_or([0.0, 0.0, 0.0]), + rotation: node.rotation.unwrap_or_default().0, + scale: node.scale.unwrap_or([1.0, 1.0, 1.0]), + })); + + nodes.insert(i, graph_node); + }); + + json.nodes.iter().enumerate().for_each(|(i, node)| { + let graph_node = nodes.get(&i).unwrap(); + + if let Some(children) = &node.children { + children.iter().for_each(|child| { + let child_graph_node = nodes.get(&child.value()).unwrap(); + + graph.add_edge(*graph_node, *child_graph_node, GraphEdge::Child); + graph.add_edge(*child_graph_node, *graph_node, GraphEdge::Parent); + }); + } + }); + + Gltf { + graph: Arc::new(graph), + } + } + + /// Get all glTF nodes + pub fn nodes(&self) -> Vec { + self.graph + .node_indices() + .filter_map(|index| match self.graph[index] { + GraphNode::Node(_) => Some(Node { + graph: self.graph.clone(), + index, + }), + _ => None, + }) + .collect() + } +} + +/// Import a glTF from the file system +pub fn import(path: &str) -> Result { + let (doc, _, _) = gltf::import(path)?; + Ok(Gltf::from_json(&doc.into_json())) +}