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

108 lines
2.8 KiB
Rust

use utilities::prelude::cgmath;
use utilities::prelude::cgmath::prelude::{One, SquareMatrix};
use anyhow::Result;
use gltf;
use std::collections::HashMap;
use std::{cmp::Ordering, sync::Mutex};
#[derive(Debug)]
pub struct Skin {
pub index: usize,
pub root_joint_id: usize,
inverse_global_transform: Mutex<cgmath::Matrix4<f32>>,
inverse_bind_matrices: HashMap<usize, cgmath::Matrix4<f32>>,
joints: Vec<usize>,
}
impl Skin {
pub fn new(
gltf_skin: &gltf::Skin<'_>,
node_index: usize,
buffers: &Vec<gltf::buffer::Data>,
) -> Result<Skin> {
let reader = gltf_skin.reader(|buffer| Some(&buffers[buffer.index()]));
let ibms: Vec<cgmath::Matrix4<f32>> = match reader.read_inverse_bind_matrices() {
Some(ibms) => ibms.map(|ibm| ibm.into()).collect(),
None => {
return Err(anyhow::Error::msg(
"Gltf: Skin does not contain a inverse bind matrix",
))
}
};
let mut ibm_map = HashMap::new();
let mut nodes = Vec::new();
for (index, node) in gltf_skin.joints().enumerate() {
ibm_map.insert(node.index(), ibms[index]);
nodes.push(node.index());
}
let root_joint_id = match gltf_skin.skeleton() {
Some(node) => node.index(),
None => node_index,
};
Ok(Skin {
index: gltf_skin.index(),
root_joint_id,
inverse_global_transform: Mutex::new(cgmath::Matrix4::one()),
inverse_bind_matrices: ibm_map,
joints: nodes,
})
}
pub fn ibm(&self, node_id: usize) -> Option<&cgmath::Matrix4<f32>> {
self.inverse_bind_matrices.get(&node_id)
}
pub fn joints(&self) -> &Vec<usize> {
&self.joints
}
pub fn set_global_transform(&self, global_transform: cgmath::Matrix4<f32>) -> Result<()> {
if let Some(inverse) = global_transform.invert() {
*self.inverse_global_transform.lock().map_err(|_| {
anyhow::Error::msg("Gltf: Failed locking inverse_global_transform of Skin")
})? = inverse;
}
Ok(())
}
pub fn inverse_global_transform(&self) -> Result<cgmath::Matrix4<f32>> {
Ok(self
.inverse_global_transform
.lock()
.map_err(|_| {
anyhow::Error::msg("Gltf: Failed locking inverse_global_transform of Skin")
})?
.clone())
}
}
impl Ord for Skin {
fn cmp(&self, other: &Self) -> Ordering {
self.index.cmp(&other.index)
}
}
impl PartialOrd for Skin {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for Skin {
fn eq(&self, other: &Self) -> bool {
self.index == other.index
}
}
impl Eq for Skin {}