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 {}