1use indent_display::{IndentedDisplay, IndentedOptions, Indenter, NullOptions};
3
4use crate::hierarchy;
5use crate::Bone;
6use crate::Mat4;
7use crate::Transformation;
8
9#[derive(Debug)]
16pub struct Skeleton {
17 pub skeleton: hierarchy::Hierarchy<Bone>,
19 pub roots: Vec<(usize, hierarchy::Recipe)>,
21 pub temp_mat4s: Vec<Mat4>,
23 pub max_index: usize,
25}
26
27impl Default for Skeleton {
29 fn default() -> Self {
30 Self::new()
31 }
32}
33
34impl Skeleton {
36 pub fn new() -> Self {
39 let skeleton = hierarchy::Hierarchy::new();
40 let roots = Vec::new();
41 let temp_mat4s = Vec::new();
42 Self {
43 skeleton,
44 roots,
45 temp_mat4s,
46 max_index: 0,
47 }
48 }
49
50 pub fn add_bone(&mut self, transformation: Transformation, matrix_index: usize) -> usize {
57 self.roots.clear();
58 let bone = Bone::new(transformation, matrix_index);
59 self.skeleton.add_node(bone)
60 }
61
62 pub fn relate(&mut self, parent: usize, child: usize) {
65 self.skeleton.relate(parent, child);
66 }
67
68 fn find_max_matrix_index(&mut self) {
71 let mut max_index = 0;
72 for b in self.skeleton.borrow_elements() {
73 if b.data.matrix_index >= max_index {
74 max_index = b.data.matrix_index + 1
75 }
76 }
77 self.max_index = max_index;
78 }
79
80 pub fn resolve(&mut self) {
87 if self.roots.is_empty() {
88 self.skeleton.find_roots();
89 for r in self.skeleton.borrow_roots() {
90 self.roots
91 .push((*r, hierarchy::Recipe::of_ops(self.skeleton.enum_from(*r))));
92 }
93 let mut max_depth = 0;
94 for (_, recipe) in &self.roots {
95 max_depth = if recipe.depth() > max_depth {
96 recipe.depth()
97 } else {
98 max_depth
99 };
100 }
101 self.temp_mat4s = Vec::new();
102 for _ in 0..max_depth {
103 self.temp_mat4s.push([0.; 16]);
104 }
105 self.find_max_matrix_index();
106 }
107 }
108
109 pub fn rewrite_indices(&mut self) {
115 self.resolve();
116 if self.max_index < self.skeleton.len() {
117 let mut bone_count = 0;
118 let (_, bones) = self.skeleton.borrow_mut();
119 for (_, recipe) in &self.roots {
120 for op in recipe.borrow_ops() {
121 if let hierarchy::NodeEnumOp::Push(n, _) = op {
122 bones[*n].data.matrix_index = bone_count;
123 bone_count += 1;
124 }
125 }
126 }
127 self.max_index = bone_count;
128 }
129 }
130
131 pub fn derive_matrices(&mut self) {
137 assert!(
138 !self.roots.is_empty(),
139 "Resolve MUST have been invoked prior to derive_matrices"
140 );
141 let (_, bones) = self.skeleton.borrow_mut();
142 let mut mat_depth = 0;
143 for (_, recipe) in &self.roots {
144 for op in recipe.borrow_ops() {
145 match op {
146 hierarchy::NodeEnumOp::Push(n, _) => {
147 if mat_depth == 0 {
148 self.temp_mat4s[mat_depth] = *bones[*n]
149 .data
150 .derive_matrices(true, &self.temp_mat4s[mat_depth]);
151 } else {
152 self.temp_mat4s[mat_depth] = *bones[*n]
153 .data
154 .derive_matrices(false, &self.temp_mat4s[mat_depth - 1]);
155 }
156 mat_depth += 1;
157 }
158 _ => {
159 mat_depth -= 1;
160 }
161 }
162 }
163 }
164 }
165
166 pub fn iter_roots(&self) -> impl Iterator<Item = usize> + '_ {
169 self.roots.iter().map(|(n, _)| *n)
170 }
171
172 }
174
175impl<'a, Opt: IndentedOptions<'a>> IndentedDisplay<'a, Opt> for Skeleton {
177 fn indent(&self, f: &mut Indenter<'a, Opt>) -> std::fmt::Result {
180 self.skeleton.indent(f)
181 }
182}
183
184impl std::fmt::Display for Skeleton {
186 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
189 let mut v = Vec::<u8>::new();
190 let mut ind = Indenter::new(&mut v, " ", &NullOptions {});
191 self.indent(&mut ind)?;
192 drop(ind);
193 write!(f, "{}", &String::from_utf8(v).unwrap())
194 }
195}