use super::{animation::GltfAnimation, mesh::Mesh, node::Node, skin::Skin}; use anyhow::Result; use assetpath::AssetPath; use gltf; use gltf::image::Data as ImageData; use utilities::prelude::cgmath; use utilities::prelude::cgmath::prelude::*; use std::collections::HashMap; use std::sync::Arc; #[derive(PartialEq, Eq, Clone, Debug)] pub enum RepeatType { Once, Twice, Count(u32), Infinite, } #[derive(Debug)] pub struct GltfAsset { pub meshes: Vec, pub animations: Vec>, pub image_data: Vec, } impl GltfAsset { pub fn new(path: &AssetPath) -> Result { // import gltf file with the help of the gltf crate let (gltf, buffers, images) = gltf::import(&path.full_path())?; // check the scene count if gltf.scenes().len() != 1 { todo!("only one scene supported"); } let gltf_scene = gltf.scenes().nth(0).unwrap(); let scene_nodes: Vec = gltf_scene.nodes().map(|g_node| g_node.index()).collect(); let scene_root_node = { // take first node for now scene_nodes[0] }; let mut nodes = HashMap::new(); let mut meshes = Vec::with_capacity(gltf.meshes().len()); let mut skins = Vec::with_capacity(gltf.skins().len()); // iterate over all nodes for gltf_node in gltf.nodes() { // check if there is a skin attached to this node let skin_index: Option = match gltf_node.skin() { Some(gltf_skin) => { // make sure skin is pushed only once if skins .iter() .find(|skin: &&Skin| skin.index == gltf_skin.index()) .is_none() { skins.push(Skin::new(&gltf_skin, scene_root_node, &buffers)?); } Some(gltf_skin.index()) } None => None, }; // check if that node has a mesh let mesh_index: Option = match gltf_node.mesh() { Some(gltf_mesh) => { let mesh = Mesh::new( gltf_mesh, &buffers, match skin_index { Some(ref index) => Some(&skins[*index]), None => None, }, gltf_node.index(), ); let index = mesh.index; meshes.push(mesh); Some(index) } None => None, }; let node = Node::new(gltf_node, mesh_index, skin_index)?; nodes.insert(node.index, node); } meshes.sort(); skins.sort(); // sanity check if cfg!(debug_assertions) { for (i, skin) in skins.iter().enumerate() { assert!(i == skin.index) } for (i, mesh) in meshes.iter().enumerate() { assert!(i == mesh.index) } } Self::apply_scene_transforms(scene_nodes, &nodes, &mut meshes, &mut skins)?; // create animations let mut animations: Vec> = Vec::new(); let arc_skins = Arc::new(skins); let arc_nodes = Arc::new(nodes); for gltf_animation in gltf.animations() { match GltfAnimation::new( &gltf_animation, &buffers, arc_skins.clone(), arc_nodes.clone(), ) { Ok(ani) => { animations.push(Arc::new(ani)); } Err(msg) => println!("{}", msg), } } Ok(GltfAsset { meshes, animations, image_data: images, }) } fn apply_scene_transforms( scene_nodes: Vec, nodes: &HashMap, meshes: &mut Vec, skins: &mut Vec, ) -> Result<()> { let root_transform = cgmath::Matrix4::identity(); for node_id in &scene_nodes { if let Some(node) = nodes.get(node_id) { node.update_transform(nodes, &root_transform, meshes, skins)?; } } Ok(()) } }