use std::str::FromStr;
use glam::Mat4;
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use strum_macros::{Display, EnumString};
use uuid::Uuid;
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Skeleton {
pub joints: IndexMap<JointName, Joint>,
pub root: Vec<JointName>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Joint {
pub name: JointName,
pub global_transforms: Vec<Transform>,
pub local_transforms: Vec<Transform>,
pub children: Vec<JointName>,
pub parent: Option<JointName>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Transform {
pub name: String,
pub id: Uuid,
pub transform: Mat4,
pub rank: usize,
}
#[allow(missing_docs)]
#[repr(u16)]
#[derive(
EnumString,
Display,
Debug,
Hash,
PartialEq,
Eq,
Clone,
Default,
Copy,
Serialize,
Deserialize,
Ord,
PartialOrd,
)]
pub enum JointName {
#[strum(serialize = "BUTT")]
Butt,
#[strum(serialize = "PELVIS")]
PelvisLegacy,
#[default]
#[strum(serialize = "mPelvis")]
Pelvis,
#[strum(serialize = "mSpine1")]
Spine1,
#[strum(serialize = "mSpine2")]
Spine2,
#[strum(serialize = "mSpine3")]
Spine3,
#[strum(serialize = "mSpine4")]
Spine4,
#[strum(serialize = "LOWER_BACK")]
LowerBack,
#[strum(serialize = "BELLY")]
Belly,
#[strum(serialize = "UPPER_BACK")]
UpperBack,
#[strum(serialize = "CHEST")]
ChestLegacy,
#[strum(serialize = "mChest")]
Chest,
#[strum(serialize = "mTorso")]
Torso,
#[strum(serialize = "mGroin")]
Groin,
#[strum(serialize = "LEFT_HANDLE")]
HandleLeft,
#[strum(serialize = "RIGHT_HANDLE")]
HandleRight,
#[strum(serialize = "NECK")]
NeckLegacy,
#[strum(serialize = "HEAD")]
HeadLegacy,
#[strum(serialize = "mNeck")]
Neck,
#[strum(serialize = "mHead")]
Head,
#[strum(serialize = "mSkull")]
Skull,
#[strum(serialize = "mFaceRoot")]
FaceRoot,
#[strum(serialize = "mFaceForeheadCenter")]
FaceForeheadCenter,
#[strum(serialize = "mFaceForeheadLeft")]
FaceForeheadLeft,
#[strum(serialize = "mFaceForeheadRight")]
FaceForeheadRight,
#[strum(serialize = "mFaceEyebrowOuterLeft")]
FaceEyebrowOuterLeft,
#[strum(serialize = "mFaceEyebrowCenterLeft")]
FaceEyebrowCenterLeft,
#[strum(serialize = "mFaceEyebrowInnerLeft")]
FaceEyebrowInnerLeft,
#[strum(serialize = "mFaceEyebrowOuterRight")]
FaceEyebrowOuterRight,
#[strum(serialize = "mFaceEyebrowCenterRight")]
FaceEyebrowCenterRight,
#[strum(serialize = "mFaceEyebrowInnerRight")]
FaceEyebrowInnerRight,
#[strum(serialize = "mFaceEyecornerInnerLeft")]
FaceEyecornerInnerLeft,
#[strum(serialize = "mFaceEyecornerInnerRight")]
FaceEyecornerInnerRight,
#[strum(serialize = "mFaceEyeLidUpperLeft")]
FaceEyeLidUpperLeft,
#[strum(serialize = "mFaceEyeLidLowerLeft")]
FaceEyeLidLowerLeft,
#[strum(serialize = "mFaceEyeLidUpperRight")]
FaceEyeLidUpperRight,
#[strum(serialize = "mFaceEyeLidLowerRight")]
FaceEyeLidLowerRight,
#[strum(serialize = "mFaceCheekUpperLeft")]
FaceCheekUpperLeft,
#[strum(serialize = "mFaceCheekLowerLeft")]
FaceCheekLowerLeft,
#[strum(serialize = "mFaceCheekUpperRight")]
FaceCheekUpperRight,
#[strum(serialize = "mFaceCheekLowerRight")]
FaceCheekLowerRight,
#[strum(serialize = "mFaceNoseBridge")]
FaceNoseBridge,
#[strum(serialize = "mFaceNoseCenter")]
FaceNoseCenter,
#[strum(serialize = "mFaceNoseBase")]
FaceNoseBase,
#[strum(serialize = "mFaceNoseLeft")]
FaceNoseLeft,
#[strum(serialize = "mFaceNoseRight")]
FaceNoseRight,
#[strum(serialize = "mFaceLipUpperCenter")]
FaceLipUpperCenter,
#[strum(serialize = "mFaceLipUpperLeft")]
FaceLipUpperLeft,
#[strum(serialize = "mFaceLipCornerLeft")]
FaceLipCornerLeft,
#[strum(serialize = "mFaceLipUpperRight")]
FaceLipUpperRight,
#[strum(serialize = "mFaceLipCornerRight")]
FaceLipCornerRight,
#[strum(serialize = "mFaceLipLowerCenter")]
FaceLipLowerCenter,
#[strum(serialize = "mFaceLipLowerLeft")]
FaceLipLowerLeft,
#[strum(serialize = "mFaceLipLowerRight")]
FaceLipLowerRight,
#[strum(serialize = "mFaceTongueBase")]
FaceTongueBase,
#[strum(serialize = "mFaceTongueTip")]
FaceTongueTip,
#[strum(serialize = "mFaceTeethUpper")]
FaceTeethUpper,
#[strum(serialize = "mFaceTeethLower")]
FaceTeethLower,
#[strum(serialize = "mFaceJaw")]
FaceJaw,
#[strum(serialize = "mFaceJawShaper")]
FaceJawShaper,
#[strum(serialize = "mFaceChin")]
FaceChin,
#[strum(serialize = "mFaceEar1Left")]
FaceEar1Left,
#[strum(serialize = "mFaceEar2Left")]
FaceEar2Left,
#[strum(serialize = "mFaceEar1Right")]
FaceEar1Right,
#[strum(serialize = "mFaceEar2Right")]
FaceEar2Right,
#[strum(serialize = "mFaceEyeAltLeft")]
FaceEyeAltLeft,
#[strum(serialize = "mFaceEyeAltRight")]
FaceEyeAltRight,
#[strum(serialize = "mEyeLeft")]
EyeLeft,
#[strum(serialize = "mEyeRight")]
EyeRight,
#[strum(serialize = "L_CLAVICLE")]
ClavicleLeft,
#[strum(serialize = "R_CLAVICLE")]
ClavicleRight,
#[strum(serialize = "SHOULDER_LEFT")]
ShoulderLeftLegacy,
#[strum(serialize = "SHOULDER_RIGHT")]
ShoulderRightLegacy,
#[strum(serialize = "mShoulderLeft")]
ShoulderLeft,
#[strum(serialize = "mShoulderRight")]
ShoulderRight,
#[strum(serialize = "mCollarLeft")]
CollarLeft,
#[strum(serialize = "mCollarRight")]
CollarRight,
#[strum(serialize = "LEFT_PEC")]
PecLeft,
#[strum(serialize = "RIGHT_PEC")]
PecRight,
#[strum(serialize = "L_UPPER_ARM")]
UpperArmLeft,
#[strum(serialize = "L_LOWER_ARM")]
LowerArmLeft,
#[strum(serialize = "R_UPPER_ARM")]
UpperArmRight,
#[strum(serialize = "R_LOWER_ARM")]
LowerArmRight,
#[strum(serialize = "mArmLeft")]
ArmLeft,
#[strum(serialize = "mArmRight")]
ArmRight,
#[strum(serialize = "mElbowLeft")]
ElbowLeft,
#[strum(serialize = "mElbowRight")]
ElbowRight,
#[strum(serialize = "mForearmLeft")]
ForearmLeft,
#[strum(serialize = "mForearmRight")]
ForearmRight,
#[strum(serialize = "mWristLeft")]
WristLeft,
#[strum(serialize = "mWristRight")]
WristRight,
#[strum(serialize = "mWingsRoot")]
WingsRoot,
#[strum(serialize = "mWing1Left")]
Wing1Left,
#[strum(serialize = "mWing2Left")]
Wing2Left,
#[strum(serialize = "mWing3Left")]
Wing3Left,
#[strum(serialize = "mWing4Left")]
Wing4Left,
#[strum(serialize = "mWing4FanLeft")]
Wing4FanLeft,
#[strum(serialize = "mWing1Right")]
Wing1Right,
#[strum(serialize = "mWing2Right")]
Wing2Right,
#[strum(serialize = "mWing3Right")]
Wing3Right,
#[strum(serialize = "mWing4Right")]
Wing4Right,
#[strum(serialize = "mWing4FanRight")]
Wing4FanRight,
#[strum(serialize = "L_HAND")]
HandLeftLegacy,
#[strum(serialize = "R_HAND")]
HandRightLegacy,
#[strum(serialize = "mHandLeft")]
HandLeft,
#[strum(serialize = "mHandRight")]
HandRight,
#[strum(serialize = "mHandIndex1Left")]
HandIndex1Left,
#[strum(serialize = "mHandIndex2Left")]
HandIndex2Left,
#[strum(serialize = "mHandIndex3Left")]
HandIndex3Left,
#[strum(serialize = "mHandMiddle1Left")]
HandMiddle1Left,
#[strum(serialize = "mHandMiddle2Left")]
HandMiddle2Left,
#[strum(serialize = "mHandMiddle3Left")]
HandMiddle3Left,
#[strum(serialize = "mHandRing1Left")]
HandRing1Left,
#[strum(serialize = "mHandRing2Left")]
HandRing2Left,
#[strum(serialize = "mHandRing3Left")]
HandRing3Left,
#[strum(serialize = "mHandPinky1Left")]
HandPinky1Left,
#[strum(serialize = "mHandPinky2Left")]
HandPinky2Left,
#[strum(serialize = "mHandPinky3Left")]
HandPinky3Left,
#[strum(serialize = "mHandIndex1Right")]
HandIndex1Right,
#[strum(serialize = "mHandIndex2Right")]
HandIndex2Right,
#[strum(serialize = "mHandIndex3Right")]
HandIndex3Right,
#[strum(serialize = "mHandMiddle1Right")]
HandMiddle1Right,
#[strum(serialize = "mHandMiddle2Right")]
HandMiddle2Right,
#[strum(serialize = "mHandMiddle3Right")]
HandMiddle3Right,
#[strum(serialize = "mHandRing1Right")]
HandRing1Right,
#[strum(serialize = "mHandRing2Right")]
HandRing2Right,
#[strum(serialize = "mHandRing3Right")]
HandRing3Right,
#[strum(serialize = "mHandPinky1Right")]
HandPinky1Right,
#[strum(serialize = "mHandPinky2Right")]
HandPinky2Right,
#[strum(serialize = "mHandPinky3Right")]
HandPinky3Right,
#[strum(serialize = "mHandThumb1Left")]
HandThumb1Left,
#[strum(serialize = "mHandThumb2Left")]
HandThumb2Left,
#[strum(serialize = "mHandThumb3Left")]
HandThumb3Left,
#[strum(serialize = "mHandThumb1Right")]
HandThumb1Right,
#[strum(serialize = "mHandThumb2Right")]
HandThumb2Right,
#[strum(serialize = "mHandThumb3Right")]
HandThumb3Right,
#[strum(serialize = "mTail1")]
Tail1,
#[strum(serialize = "mTail2")]
Tail2,
#[strum(serialize = "mTail3")]
Tail3,
#[strum(serialize = "mTail4")]
Tail4,
#[strum(serialize = "mTail5")]
Tail5,
#[strum(serialize = "mTail6")]
Tail6,
#[strum(serialize = "mHindLimbsRoot")]
HindLimbsRoot,
#[strum(serialize = "mHindLimb1Left")]
HindLimb1Left,
#[strum(serialize = "mHindLimb2Left")]
HindLimb2Left,
#[strum(serialize = "mHindLimb3Left")]
HindLimb3Left,
#[strum(serialize = "mHindLimb4Left")]
HindLimb4Left,
#[strum(serialize = "mHindLimb1Right")]
HindLimb1Right,
#[strum(serialize = "mHindLimb2Right")]
HindLimb2Right,
#[strum(serialize = "mHindLimb3Right")]
HindLimb3Right,
#[strum(serialize = "mHindLimb4Right")]
HindLimb4Right,
#[strum(serialize = "L_UPPER_LEG")]
UpperLegLeft,
#[strum(serialize = "L_LOWER_LEG")]
LowerLegLeft,
#[strum(serialize = "R_UPPER_LEG")]
UpperLegRight,
#[strum(serialize = "R_LOWER_LEG")]
LowerLegRight,
#[strum(serialize = "HIP_LEFT")]
HipLeftLegacy,
#[strum(serialize = "HIP_RIGHT")]
HipRightLegacy,
#[strum(serialize = "mHipLeft")]
HipLeft,
#[strum(serialize = "mHipRight")]
HipRight,
#[strum(serialize = "mThighLeft")]
ThighLeft,
#[strum(serialize = "mThighRight")]
ThighRight,
#[strum(serialize = "mKneeLeft")]
KneeLeft,
#[strum(serialize = "mKneeRight")]
KneeRight,
#[strum(serialize = "mShinLeft")]
ShinLeft,
#[strum(serialize = "mShinRight")]
ShinRight,
#[strum(serialize = "KNEE_LEFT")]
UpperKneeLeft,
#[strum(serialize = "KNEE_RIGHT")]
UpperKneeRight,
#[strum(serialize = "ANKLE_LEFT")]
AnkleLeftLegacy,
#[strum(serialize = "ANKLE_RIGHT")]
AnkleRightLegacy,
#[strum(serialize = "mAnkleLeft")]
AnkleLeft,
#[strum(serialize = "mAnkleRight")]
AnkleRight,
#[strum(serialize = "L_FOOT")]
FootLeftLegacy,
#[strum(serialize = "R_FOOT")]
FootRightLegacy2,
#[strum(serialize = "FOOT_LEFT")]
FootLeftLegacy2,
#[strum(serialize = "FOOT_RIGHT")]
FootRightLegacy,
#[strum(serialize = "mFootLeft")]
FootLeft,
#[strum(serialize = "mFootRight")]
FootRight,
#[strum(serialize = "mHeelLeft")]
HeelLeft,
#[strum(serialize = "mHeelRight")]
HeelRight,
#[strum(serialize = "mToeLeft")]
ToeLeft,
#[strum(serialize = "mToeRight")]
ToeRight,
}
use once_cell::sync::Lazy;
use std::collections::HashMap;
static BVH_JOINT_ALIASES: Lazy<HashMap<&'static str, JointName>> = Lazy::new(|| {
let mut m = HashMap::new();
m.insert("hip", JointName::Pelvis);
m.insert("abdomen", JointName::Torso);
m.insert("chest", JointName::Chest);
m.insert("neck", JointName::Neck);
m.insert("head", JointName::Head);
m.insert("lCollar", JointName::CollarLeft);
m.insert("lShldr", JointName::ShoulderLeft);
m.insert("lForeArm", JointName::ElbowLeft);
m.insert("lHand", JointName::HandLeft);
m.insert("rCollar", JointName::CollarRight);
m.insert("rShldr", JointName::ShoulderRight);
m.insert("rForeArm", JointName::ElbowRight);
m.insert("rHand", JointName::HandRight);
m.insert("lThigh", JointName::HipLeft);
m.insert("lShin", JointName::KneeLeft);
m.insert("lFoot", JointName::FootLeft);
m.insert("rThigh", JointName::HipRight);
m.insert("rShin", JointName::KneeRight);
m.insert("rFoot", JointName::FootRight);
m
});
static UNITY_JOINT_ALIASES: Lazy<HashMap<&'static str, JointName>> = Lazy::new(|| {
let mut m = HashMap::new();
m.insert("Hips", JointName::PelvisLegacy);
m.insert("hip", JointName::PelvisLegacy);
m.insert("Spine", JointName::LowerBack);
m.insert("Spine1", JointName::Spine1);
m.insert("Spine2", JointName::Spine2);
m.insert("Spine3", JointName::Spine3);
m.insert("Chest", JointName::Chest);
m.insert("UpperChest", JointName::UpperBack);
m.insert("Abdomen", JointName::LowerBack);
m.insert("Pelvis", JointName::Pelvis);
m.insert("Neck", JointName::Neck);
m.insert("Head", JointName::Head);
m.insert("LeftShoulder", JointName::ShoulderLeft);
m.insert("LeftUpperArm", JointName::UpperArmLeft);
m.insert("LeftLowerArm", JointName::LowerArmLeft);
m.insert("LeftHand", JointName::HandLeft);
m.insert("LeftForeArm", JointName::ForearmLeft);
m.insert("lCollar", JointName::CollarLeft);
m.insert("lShldr", JointName::ShoulderLeft);
m.insert("lForeArm", JointName::ForearmLeft);
m.insert("lHand", JointName::HandLeft);
m.insert("RightShoulder", JointName::ShoulderRight);
m.insert("RightUpperArm", JointName::UpperArmRight);
m.insert("RightLowerArm", JointName::LowerArmRight);
m.insert("RightHand", JointName::HandRight);
m.insert("rCollar", JointName::CollarRight);
m.insert("rShldr", JointName::ShoulderRight);
m.insert("rForeArm", JointName::ForearmRight);
m.insert("rHand", JointName::HandRight);
m.insert("LeftUpperLeg", JointName::ThighLeft);
m.insert("LeftLowerLeg", JointName::ShinLeft);
m.insert("LeftFoot", JointName::FootLeft);
m.insert("lThigh", JointName::ThighLeft);
m.insert("lShin", JointName::ShinLeft);
m.insert("lFoot", JointName::FootLeft);
m.insert("RightUpperLeg", JointName::ThighRight);
m.insert("RightLowerLeg", JointName::ShinRight);
m.insert("RightFoot", JointName::FootRight);
m.insert("rThigh", JointName::ThighRight);
m.insert("rShin", JointName::ShinRight);
m.insert("rFoot", JointName::FootRight);
m.insert("LeftHandThumb1", JointName::HandThumb1Left);
m.insert("LeftHandThumb2", JointName::HandThumb2Left);
m.insert("LeftHandThumb3", JointName::HandThumb3Left);
m.insert("RightHandThumb1", JointName::HandThumb1Right);
m.insert("RightHandThumb2", JointName::HandThumb2Right);
m.insert("RightHandThumb3", JointName::HandThumb3Right);
m
});
static QUATERNIUS_JOINT_ALIASES: Lazy<HashMap<&'static str, JointName>> = Lazy::new(|| {
let mut m = HashMap::new();
m.insert("pelvis", JointName::Pelvis);
m.insert("spine_01", JointName::Torso);
m.insert("spine_02", JointName::Spine2);
m.insert("spine_03", JointName::Chest);
m.insert("neck_01", JointName::Head);
m.insert("Head", JointName::Skull);
m.insert("upperarm_l", JointName::ShoulderLeft);
m.insert("lowerarm_l", JointName::ElbowLeft);
m.insert("hand_l", JointName::WristLeft);
m.insert("clavicle_l", JointName::CollarLeft);
m.insert("upperarm_r", JointName::ShoulderRight);
m.insert("lowerarm_r", JointName::ElbowRight);
m.insert("hand_r", JointName::WristRight);
m.insert("clavicle_r", JointName::CollarRight);
m.insert("thigh_l", JointName::HipLeft);
m.insert("calf_l", JointName::KneeLeft);
m.insert("foot_l", JointName::FootLeft);
m.insert("thigh_r", JointName::HipRight);
m.insert("calf_r", JointName::KneeRight);
m.insert("foot_r", JointName::FootRight);
m.insert("thumb_01_l", JointName::HandThumb1Left);
m.insert("thumb_02_l", JointName::HandThumb2Left);
m.insert("thumb_03_l", JointName::HandThumb3Left);
m.insert("index_01_l", JointName::HandIndex1Left);
m.insert("index_02_l", JointName::HandIndex2Left);
m.insert("index_03_l", JointName::HandIndex3Left);
m.insert("middle_01_l", JointName::HandMiddle1Left);
m.insert("middle_02_l", JointName::HandMiddle2Left);
m.insert("middle_03_l", JointName::HandMiddle3Left);
m.insert("ring_01_l", JointName::HandRing1Left);
m.insert("ring_02_l", JointName::HandRing2Left);
m.insert("ring_03_l", JointName::HandRing3Left);
m.insert("pinky_01_l", JointName::HandPinky1Left);
m.insert("pinky_02_l", JointName::HandPinky2Left);
m.insert("pinky_03_l", JointName::HandPinky3Left);
m.insert("thumb_01_r", JointName::HandThumb1Right);
m.insert("thumb_02_r", JointName::HandThumb2Right);
m.insert("thumb_03_r", JointName::HandThumb3Right);
m.insert("index_01_r", JointName::HandIndex1Right);
m.insert("index_02_r", JointName::HandIndex2Right);
m.insert("index_03_r", JointName::HandIndex3Right);
m.insert("middle_01_r", JointName::HandMiddle1Right);
m.insert("middle_02_r", JointName::HandMiddle2Right);
m.insert("middle_03_r", JointName::HandMiddle3Right);
m.insert("ring_01_r", JointName::HandRing1Right);
m.insert("ring_02_r", JointName::HandRing2Right);
m.insert("ring_03_r", JointName::HandRing3Right);
m.insert("pinky_01_r", JointName::HandPinky1Right);
m.insert("pinky_02_r", JointName::HandPinky2Right);
m.insert("pinky_03_r", JointName::HandPinky3Right);
m
});
impl JointName {
pub fn resolve_joint_name(s: &str) -> Option<JointName> {
QUATERNIUS_JOINT_ALIASES
.get(s)
.or_else(|| UNITY_JOINT_ALIASES.get(s))
.or_else(|| BVH_JOINT_ALIASES.get(s))
.copied()
.or_else(|| JointName::from_str(s).ok())
}
pub fn from_str_non_bento(s: &str) -> Option<JointName> {
if let Some(j) = BVH_JOINT_ALIASES.get(s) {
return Some(*j);
}
if let Some(j) = UNITY_JOINT_ALIASES.get(s) {
return Some(*j);
}
JointName::from_str(s).ok()
}
}