155 lines
4.4 KiB
Rust
155 lines
4.4 KiB
Rust
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<Mesh>,
|
|
pub animations: Vec<Arc<GltfAnimation>>,
|
|
pub image_data: Vec<ImageData>,
|
|
}
|
|
|
|
impl GltfAsset {
|
|
pub fn new(path: &AssetPath) -> Result<GltfAsset> {
|
|
// 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<usize> = 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<usize> = 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<usize> = 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<Arc<GltfAnimation>> = 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<usize>,
|
|
nodes: &HashMap<usize, Node>,
|
|
meshes: &mut Vec<Mesh>,
|
|
skins: &mut Vec<Skin>,
|
|
) -> 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(())
|
|
}
|
|
}
|