use indent_display::{IndentedDisplay, IndentedOptions, Indenter};
use crate::hierarchy;
use crate::{BonePose, Mat4, Skeleton};
pub struct SkeletonPose<'a> {
skeleton: &'a Skeleton,
poses: Vec<BonePose<'a>>,
data: Vec<Mat4>,
last_updated: usize,
}
impl<'a> SkeletonPose<'a> {
pub fn new(skeleton: &'a Skeleton) -> Self {
let mut poses = Vec::new();
for b in skeleton.skeleton.borrow_elements().iter() {
poses.push(BonePose::new(&b.data));
}
let mut data = Vec::new();
for _ in 0..skeleton.max_index {
data.push([0.; 16]);
}
let last_updated = 0;
Self {
skeleton,
poses,
data,
last_updated,
}
}
pub fn derive_animation(&mut self) {
let mut mat_depth = 0;
for (_, recipe) in &self.skeleton.roots {
for op in recipe.borrow_ops() {
match op {
hierarchy::NodeEnumOp::Push(n, _) => {
if mat_depth == 0 {
self.data[mat_depth] =
*self.poses[*n].derive_animation(true, &self.data[mat_depth]);
} else {
self.data[mat_depth + 1] =
*self.poses[*n].derive_animation(false, &self.data[mat_depth]);
}
mat_depth += 1;
}
_ => {
mat_depth -= 1;
}
}
}
}
}
pub fn update(&mut self, tick: usize) {
if tick != self.last_updated {
self.last_updated = tick;
self.derive_animation();
let bones = self.skeleton.skeleton.borrow_elements();
for (i, bone) in bones.iter().enumerate().take(self.poses.len()) {
let matrix_index = bone.data.matrix_index;
self.data[matrix_index] = *self.poses[i].borrow_animated_mtm();
}
}
}
}
impl<'a, 'b, Opt: IndentedOptions<'a>> IndentedDisplay<'a, Opt> for SkeletonPose<'b> {
fn indent(&self, f: &mut Indenter<'a, Opt>) -> std::fmt::Result {
for (_, recipe) in &self.skeleton.roots {
let mut sub = f.sub();
for op in recipe.borrow_ops() {
match op {
hierarchy::NodeEnumOp::Push(_n, _) => {
sub = sub.sub();
}
_ => {
sub = sub.pop();
}
}
}
}
Ok(())
}
}