mod3d_base/
skeleton_pose.rs

1//a Imports
2use indent_display::{IndentedDisplay, IndentedOptions, Indenter};
3
4use crate::hierarchy;
5use crate::{BonePose, Mat4, Skeleton};
6
7//a SkeletonPose
8//tp SkeletonPose
9/// A pose structure for a complete [Skeleton]
10///
11/// This includes a set of [Mat4] matrix transformations for
12/// mesh-space to animated-model-space
13pub struct SkeletonPose<'a> {
14    /// The Skeleton the pose corresponds to
15    skeleton: &'a Skeleton,
16    /// A pose for every [crate::Bone] in the [Skeleton]
17    poses: Vec<BonePose<'a>>,
18    /// A mesh-to-animated-model-space matrix transformation for each
19    /// bone
20    data: Vec<Mat4>,
21    /// A monotonic counter to allow updating of the matrices once per
22    /// animation tick
23    last_updated: usize,
24}
25
26//ip SkeletonPose
27impl<'a> SkeletonPose<'a> {
28    //fp new
29    /// Create a new [SkeletonPose] for a [Skeleton]
30    ///
31    /// The [Skeleton] must have been resolved
32    pub fn new(skeleton: &'a Skeleton) -> Self {
33        let mut poses = Vec::new();
34        for b in skeleton.skeleton.borrow_elements().iter() {
35            poses.push(BonePose::new(&b.data));
36        }
37        let mut data = Vec::new();
38        for _ in 0..skeleton.max_index {
39            data.push([0.; 16]);
40        }
41        let last_updated = 0;
42        Self {
43            skeleton,
44            poses,
45            data,
46            last_updated,
47        }
48    }
49
50    //fp derive_animation
51    /// Derive the animation for the current poses of the [SkeletonPose]
52    ///
53    /// This traverses the hierarchy as required
54    pub fn derive_animation(&mut self) {
55        let mut mat_depth = 0;
56        for (_, recipe) in &self.skeleton.roots {
57            for op in recipe.borrow_ops() {
58                match op {
59                    hierarchy::NodeEnumOp::Push(n, _) => {
60                        if mat_depth == 0 {
61                            self.data[mat_depth] =
62                                *self.poses[*n].derive_animation(true, &self.data[mat_depth]);
63                        } else {
64                            self.data[mat_depth + 1] =
65                                *self.poses[*n].derive_animation(false, &self.data[mat_depth]);
66                        }
67                        mat_depth += 1;
68                    }
69                    _ => {
70                        mat_depth -= 1;
71                    }
72                }
73            }
74        }
75    }
76
77    //fp update
78    /// Update the animation matrices if required - depending on the
79    /// last updated tick
80    pub fn update(&mut self, tick: usize) {
81        if tick != self.last_updated {
82            self.last_updated = tick;
83            self.derive_animation();
84            let bones = self.skeleton.skeleton.borrow_elements();
85            for (i, bone) in bones.iter().enumerate().take(self.poses.len()) {
86                let matrix_index = bone.data.matrix_index;
87                self.data[matrix_index] = *self.poses[i].borrow_animated_mtm();
88            }
89        }
90    }
91}
92
93//ip IndentedDisplay for SkeletonPose
94impl<'a, 'b, Opt: IndentedOptions<'a>> IndentedDisplay<'a, Opt> for SkeletonPose<'b> {
95    //mp fmt
96    /// Display for humans with indent
97    fn indent(&self, f: &mut Indenter<'a, Opt>) -> std::fmt::Result {
98        for (_, recipe) in &self.skeleton.roots {
99            let mut sub = f.sub();
100            for op in recipe.borrow_ops() {
101                match op {
102                    hierarchy::NodeEnumOp::Push(_n, _) => {
103                        sub = sub.sub();
104                    }
105                    _ => {
106                        sub = sub.pop();
107                    }
108                }
109            }
110        }
111        Ok(())
112    }
113}
114
115/*
116       pass
117   #f hier_debug
118   def hier_debug(self, hier:Hierarchy) -> Hierarchy:
119       hier.add(f"SkeletonPose {self.skeleton.roots} {self.max_index} {self.last_updated} {self.data}")
120       hier.push()
121       self.skeleton.hier_debug(hier)
122       for pose in self.poses:
123           pose.hier_debug(hier)
124           pass
125       hier.pop()
126       return hier
127   #f All done
128   pass
129*/
130
131/*
132#c AnimatedBonePose
133class AnimatedBonePose:
134    def __init__(self, poses:List[BonePose]) -> None:
135        self.poses = poses
136        self.animatable = Bezier2(Transformation())
137        self.animatable.set_target( t1=1.,
138                                    c0=Transformation( quaternion=Glm.quat.setAxisAngle(Glm.quat.create(), Glm.vec3.fromValues(1.,0.,0.), 0.3)),
139                                    c1=Transformation( quaternion=Glm.quat.setAxisAngle(Glm.quat.create(), Glm.vec3.fromValues(1.,0.,0.), 0.3)),
140                                    tgt=Transformation(quaternion=Glm.quat.setAxisAngle(Glm.quat.create(), Glm.vec3.fromValues(1.,0.,0.), 0.3)),
141                                    callback=self.animation_callback )
142        pass
143    def interpolate_to_time(self, t:float) -> None:
144        z = self.animatable.interpolate_to_time(t)
145        # print(t, z)
146        self.poses[1].transformation_reset()
147        self.poses[1].transform(z)
148        pass
149    def animation_callback(self, t:float) -> None:
150        t_sec = math.floor(t)
151        t_int = int(t_sec)
152        tgt = 1.0
153        if (t_int&1): tgt=-1.
154        self.animatable.set_target( t1=t_sec+1.,
155                                    c0=Transformation(quaternion=Glm.quat.setAxisAngle(Glm.quat.create(), Glm.vec3.fromValues(1.,0.,0.), 0.3)),
156                                    c1=Transformation(quaternion=Glm.quat.setAxisAngle(Glm.quat.create(), Glm.vec3.fromValues(0.,1.,0.), 0.5)),
157                                    tgt=Transformation(quaternion=Glm.quat.setAxisAngle(Glm.quat.create(), Glm.vec3.fromValues(1.,0.,0.), tgt*0.3)),
158                                    callback=self.animation_callback )
159        pass
160    pass
161
162*/