engine/gltf-loader/src/gltfasset.rs
2024-08-23 13:22:09 +02:00

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(())
}
}