use std::io::Error;
use crate::avatar::Avatar;
use benthic_default_asset_converter::generated::DEFAULT_SKELETON;
use benthic_protocol::skeleton::{Joint, JointName, Skeleton, Transform};
use glam::{Mat4, Vec4};
use indexmap::IndexMap;
use metaverse_messages::http::mesh::Skin;
use uuid::Uuid;
pub fn update_global_avatar_skeleton(avatar: &mut Avatar, skeleton: &Skeleton) {
for joint in skeleton.joints.values() {
avatar.used_joints.insert(joint.name);
if let Some(global_joint) = avatar.skeleton.joints.get_mut(&joint.name) {
for transform in &joint.global_transforms {
set_rank(global_joint, transform, |j| &mut j.global_transforms);
}
for local_transform in &joint.local_transforms {
set_rank(global_joint, local_transform, |j| &mut j.local_transforms);
}
}
}
}
pub fn create_skeleton(object_name: String, id: Uuid, skin: &Skin) -> Result<Skeleton, Error> {
let default_skeleton = DEFAULT_SKELETON.clone();
let mut joints = IndexMap::new();
for (i, name) in skin.joint_names.iter().enumerate() {
let default_joints = default_skeleton.joints.get(name).unwrap().clone();
let mut default_transform = default_joints.global_transforms[0].transform;
default_transform.w_axis = Vec4::new(0.0, 0.0, 0.0, 1.0);
let transform_matrix = Mat4::from_rotation_translation(
default_transform.to_scale_rotation_translation().1,
skin.inverse_bind_matrices[i].inverse().w_axis.truncate(),
);
let transform = Transform {
name: object_name.clone(),
id,
transform: transform_matrix,
rank: 1,
};
let joint = Joint {
name: *name,
parent: default_joints.parent,
children: default_joints.children.into_iter().collect(),
global_transforms: vec![transform.clone()],
local_transforms: vec![],
};
joints.insert(*name, joint.clone());
}
let root_joints: Vec<JointName> = joints
.values()
.filter(|joint| joint.parent.is_none())
.map(|joint| joint.name)
.collect();
let last_transforms: IndexMap<JointName, Mat4> = joints
.iter()
.map(|(name, joint)| (*name, joint.global_transforms.last().unwrap().transform))
.collect();
for (_, joint) in joints.iter_mut() {
if let Some(parent_name) = &joint.parent {
let parent = last_transforms
.get(parent_name)
.or_else(|| {
Some(
&default_skeleton
.joints
.get(parent_name)
.unwrap()
.global_transforms[0]
.transform,
)
})
.unwrap();
let child = last_transforms.get(&joint.name).unwrap();
let local_matrix = parent.inverse() * child;
let local_transform = Transform {
name: object_name.clone(),
id,
transform: local_matrix,
rank: 1,
};
joint.local_transforms.push(local_transform);
} else {
let child = last_transforms.get(&joint.name).unwrap();
let local_transform = Transform {
name: object_name.clone(),
id,
transform: *child,
rank: 1,
};
joint.local_transforms.push(local_transform);
}
}
Ok(Skeleton {
root: root_joints,
joints,
})
}
fn set_rank<F>(joint: &mut Joint, transform: &Transform, mut get_vec: F)
where
F: FnMut(&mut Joint) -> &mut Vec<Transform>,
{
let transforms = get_vec(joint);
let mut matched_rank0 = false;
for t in transforms.iter_mut().skip(1) {
if t.transform.abs_diff_eq(transform.transform, 1e-4) {
t.rank += 1;
transforms.sort_by_key(|a| a.rank);
return;
}
}
if let Some(first) = transforms.first()
&& first.transform.abs_diff_eq(transform.transform, 1e-4)
{
matched_rank0 = true;
}
if matched_rank0
|| !transforms
.iter()
.any(|t| t.transform.abs_diff_eq(transform.transform, 1e-4))
{
let mut new_t = transform.clone();
if matched_rank0 {
new_t.rank = 1;
}
transforms.push(new_t);
transforms.sort_by_key(|a| a.rank);
}
}