1use crate::skeleton::{Attachment, Bone, ParentTransform, Skeleton, Slot};
2use bevy_math::{Affine3A, Quat, Vec2};
3use bevy_utils::HashMap;
4use tracing::{trace, warn};
5
6#[derive(Debug, Clone, Default)]
12pub struct DetachedSkeletonState {
13 bones: HashMap<usize, BoneState>,
14 pub slots: Vec<(usize, usize, BoneState, usize, usize)>,
15}
16
17impl DetachedSkeletonState {
18 pub fn new() -> Self {
19 Self::default()
20 }
21
22 pub fn bones<'a>(&'a self, skeleton: &'a Skeleton) -> Vec<(&'a Bone, &'a BoneState)> {
23 self.bones
24 .iter()
25 .map(|(id, state)| (&skeleton.bones[*id], state))
26 .collect()
27 }
28
29 pub fn pose(&mut self, skeleton: &Skeleton) {
30 if skeleton.bones.len() == 0 {
31 warn!("No bones in skeleton.");
32 return;
33 };
34
35 self.pose_bone(skeleton, 0, BoneState::default());
36
37 self.slots.clear();
40 for (slot_idx, slot) in skeleton.slots.iter().enumerate() {
41 let bone = &skeleton.bones[slot.bone];
42 let bone_state = match self.bones.get(&slot.bone) {
43 Some(b) => b.clone(),
44 None => {
45 warn!("Slot bone not found in bones.");
46 continue;
47 }
48 };
49 let skin = &skeleton.skins[0]; let skin_slot = &skin.slots.iter().find(|s| s.slot == slot_idx).unwrap();
51 let slot_attachment_name = match slot.attachment.as_ref() {
52 Some(s) => s,
53 None => {
54 warn!("Slot attachment name not set. Assumed no attachment for set up pose.");
55 continue;
56 }
57 };
58
59 let slot_attachment = skin_slot
60 .attachments
61 .iter()
62 .find(|attachment| &attachment.attachment_name == slot_attachment_name);
63
64 if let Some(attachment) = slot_attachment {
65 self.slots.push((
66 slot_idx,
67 slot.bone,
68 bone_state,
69 slot_idx,
70 todo!(), ));
72 } else {
73 warn!("Slot attachment not found in skin.");
74 continue;
75 }
76
77 dbg!(self.slots.len());
78 }
79 }
80
81 fn pose_bone(&mut self, skeleton: &Skeleton, bone_idx: usize, parent_state: BoneState) {
82 let bone = &skeleton.bones[bone_idx];
83 let (affinity, rotation) = match bone.transform {
84 ParentTransform::Normal => (
85 Affine3A::from_scale_rotation_translation(
86 bone.scale.extend(1.),
87 Quat::from_rotation_z(bone.rotation.to_radians()),
88 bone.position.extend(0.),
89 ),
90 bone.rotation.to_radians(),
91 ),
92 _ => {
93 warn!(
95 "Unhandled transform: {:?} in bone: {}",
96 bone.transform, bone.name
97 );
98 return;
99 }
100 };
101 let bone_state = BoneState {
102 affinity: parent_state.affinity * affinity,
103 rotation: parent_state.rotation + rotation,
104 };
105
106 self.bones.insert(bone_idx, bone_state.clone());
107 trace!("Bone: {} {:?}", bone_idx, bone.name);
108
109 if let Some(children) = skeleton.bones_tree.get(&bone_idx) {
110 for child_idx in children {
111 self.pose_bone(skeleton, *child_idx, bone_state);
112 }
113 }
114 }
115}
116
117#[derive(Debug, Clone)]
118pub struct SkeletonState<'a> {
119 skeleton: &'a Skeleton,
120
121 internal: DetachedSkeletonState,
122}
123
124impl<'a> SkeletonState<'a> {
125 pub fn new(skeleton: &'a Skeleton) -> Self {
126 Self {
127 skeleton,
128 internal: DetachedSkeletonState::default(),
129 }
130 }
131
132 pub fn pose(&mut self) {
133 self.internal.pose(self.skeleton)
134 }
135
136 pub fn bones(&'a self) -> Vec<(&'a Bone, &'a BoneState)> {
137 self.internal.bones(self.skeleton)
138 }
139}
140
141#[derive(Debug, Clone, Copy, Default)]
142pub struct BoneState {
143 pub affinity: Affine3A,
144
145 pub rotation: f32,
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153 use crate::BinaryParser;
154 use test_log::test;
155
156 #[test]
157 fn spineboy() {
158 let b = include_bytes!("../../assets/spineboy-pro-4.1/spineboy-pro.skel");
159 let skeleton = BinaryParser::parse(b).unwrap();
160 let mut state = SkeletonState::new(&skeleton);
161 state.pose();
162 }
163}