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>, inverse_bind_matrices: HashMap>, joints: Vec, } impl Skin { pub fn new( gltf_skin: &gltf::Skin<'_>, node_index: usize, buffers: &Vec, ) -> Result { let reader = gltf_skin.reader(|buffer| Some(&buffers[buffer.index()])); let ibms: Vec> = 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> { self.inverse_bind_matrices.get(&node_id) } pub fn joints(&self) -> &Vec { &self.joints } pub fn set_global_transform(&self, global_transform: cgmath::Matrix4) -> 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> { 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 { Some(self.cmp(other)) } } impl PartialEq for Skin { fn eq(&self, other: &Self) -> bool { self.index == other.index } } impl Eq for Skin {}