1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
//a Imports
use indent_display::{IndentedDisplay, IndentedOptions, Indenter};

use crate::hierarchy;
use crate::{BonePose, Mat4, Skeleton};

//a SkeletonPose
//tp SkeletonPose
/// A pose structure for a complete [Skeleton]
///
/// This includes a set of [Mat4] matrix transformations for
/// mesh-space to animated-model-space
pub struct SkeletonPose<'a> {
    /// The Skeleton the pose corresponds to
    skeleton: &'a Skeleton,
    /// A pose for every [crate::Bone] in the [Skeleton]
    poses: Vec<BonePose<'a>>,
    /// A mesh-to-animated-model-space matrix transformation for each
    /// bone
    data: Vec<Mat4>,
    /// A monotonic counter to allow updating of the matrices once per
    /// animation tick
    last_updated: usize,
}

//ip SkeletonPose
impl<'a> SkeletonPose<'a> {
    //fp new
    /// Create a new [SkeletonPose] for a [Skeleton]
    ///
    /// The [Skeleton] must have been resolved
    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,
        }
    }

    //fp derive_animation
    /// Derive the animation for the current poses of the [SkeletonPose]
    ///
    /// This traverses the hierarchy as required
    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;
                    }
                }
            }
        }
    }

    //fp update
    /// Update the animation matrices if required - depending on the
    /// last updated tick
    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();
            }
        }
    }
}

//ip IndentedDisplay for SkeletonPose
impl<'a, 'b, Opt: IndentedOptions<'a>> IndentedDisplay<'a, Opt> for SkeletonPose<'b> {
    //mp fmt
    /// Display for humans with indent
    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(())
    }
}

/*
       pass
   #f hier_debug
   def hier_debug(self, hier:Hierarchy) -> Hierarchy:
       hier.add(f"SkeletonPose {self.skeleton.roots} {self.max_index} {self.last_updated} {self.data}")
       hier.push()
       self.skeleton.hier_debug(hier)
       for pose in self.poses:
           pose.hier_debug(hier)
           pass
       hier.pop()
       return hier
   #f All done
   pass
*/

/*
#c AnimatedBonePose
class AnimatedBonePose:
    def __init__(self, poses:List[BonePose]) -> None:
        self.poses = poses
        self.animatable = Bezier2(Transformation())
        self.animatable.set_target( t1=1.,
                                    c0=Transformation( quaternion=Glm.quat.setAxisAngle(Glm.quat.create(), Glm.vec3.fromValues(1.,0.,0.), 0.3)),
                                    c1=Transformation( quaternion=Glm.quat.setAxisAngle(Glm.quat.create(), Glm.vec3.fromValues(1.,0.,0.), 0.3)),
                                    tgt=Transformation(quaternion=Glm.quat.setAxisAngle(Glm.quat.create(), Glm.vec3.fromValues(1.,0.,0.), 0.3)),
                                    callback=self.animation_callback )
        pass
    def interpolate_to_time(self, t:float) -> None:
        z = self.animatable.interpolate_to_time(t)
        # print(t, z)
        self.poses[1].transformation_reset()
        self.poses[1].transform(z)
        pass
    def animation_callback(self, t:float) -> None:
        t_sec = math.floor(t)
        t_int = int(t_sec)
        tgt = 1.0
        if (t_int&1): tgt=-1.
        self.animatable.set_target( t1=t_sec+1.,
                                    c0=Transformation(quaternion=Glm.quat.setAxisAngle(Glm.quat.create(), Glm.vec3.fromValues(1.,0.,0.), 0.3)),
                                    c1=Transformation(quaternion=Glm.quat.setAxisAngle(Glm.quat.create(), Glm.vec3.fromValues(0.,1.,0.), 0.5)),
                                    tgt=Transformation(quaternion=Glm.quat.setAxisAngle(Glm.quat.create(), Glm.vec3.fromValues(1.,0.,0.), tgt*0.3)),
                                    callback=self.animation_callback )
        pass
    pass

*/