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
//a Imports
use geo_nd::matrix;

use crate::Bone;
use crate::{Mat4, Transformation};

//a BonePose
//tp BonePose
/// A pose of a [Bone], referring to it so that many poses can use the
/// same [Bone].
///
/// A [BonePose] has a current [Transformation] which indicates how it
/// is posed; the [Bone] contains mapping matrices for going from
/// bone-parent space to bone space, and for going from mesh space to
/// bone space
pub struct BonePose<'a> {
    /// The bone this corresponds to (within its hierarchy)
    bone: &'a Bone,
    /// transformation relative to bone rest
    transformation: Transformation,
    /// posed-bone-to-parent Mat4 derived from transformation
    pbtp: Mat4,
    /// Matrix mapping bone-space to mesh-space
    animated_btm: Mat4,
    /// Matrix mapping mesh-space to mesh-space
    animated_mtm: Mat4,
}

//ip BonePose
impl<'a> BonePose<'a> {
    //fp new
    /// Create a new pose of a bone
    pub fn new(bone: &'a Bone) -> Self {
        let transformation = *bone.borrow_transformation();
        let pbtp = [0.; 16];
        let animated_btm = [0.; 16];
        let animated_mtm = [0.; 16];
        Self {
            bone,
            transformation,
            pbtp,
            animated_btm,
            animated_mtm,
        }
    }

    //mp transformation_reset
    /// Reset the pose transformation to that of the bone in the skeleton
    pub fn transformation_reset(&mut self) {
        self.transformation = *self.bone.borrow_transformation();
    }

    //mp set_transformation
    /// Set a new pose transformation for the posed bone
    pub fn set_transformation(&mut self, transform: Transformation) {
        self.transformation = transform;
        self.pbtp = self.transformation.mat4();
    }

    //mp derive_animation
    /// Derive the animation matrices given a parent
    /// animated-posed-bone-to-mesh matrix
    ///
    /// If there is no parent (is_root true) then the animated
    /// bone-to-mesh is just the posed-bone-to-parent transformation
    ///
    /// If there is a parent then its pose transformation must be
    /// preapplied to this; when this animated_btm is applied to a
    /// vector (in this local bone space) one must first generate the vector
    /// in the parent-bone space (by applying pbtp) and then apply
    /// parent pbtm to generate model space
    ///
    /// Vectors in the model mesh space can be multiplied by the
    /// *bone*s mtb matrix to get a vector in this local bone space,
    /// to which the animated_btm can be applied to get a model space
    /// vector. Hence multiplying animated_btm and bone.mtb together.
    pub fn derive_animation(&mut self, is_root: bool, parent_animated_pbtm: &Mat4) -> &Mat4 {
        if is_root {
            self.animated_btm = self.pbtp;
        } else {
            self.animated_btm = matrix::multiply4(parent_animated_pbtm, &self.pbtp);
        }
        self.animated_mtm = matrix::multiply4(&self.animated_btm, &self.bone.mtb);
        &self.animated_btm
    }

    //mp borrow_animated_mtm
    /// Borrow the animated mesh-to-model-space matrix
    ///
    /// This assumes it has been derived
    #[inline]
    pub fn borrow_animated_mtm(&self) -> &Mat4 {
        &self.animated_mtm
    }

    //zz All done
}

//ip Display for BonePose
impl<'a> std::fmt::Display for BonePose<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        writeln!(f, "Pose")?;
        write!(f, "  {}", self.bone)?;
        write!(f, "  {}", self.transformation)?;
        write!(f, "  {:?}", self.pbtp)?;
        write!(f, "  anim_btm: {:?}", self.animated_btm)?;
        write!(f, "  anim_mtm: {:?}", self.animated_mtm)?;
        Ok(())
    }
}

//ip DefaultIndentedDisplay for BonePose
impl<'a> indent_display::DefaultIndentedDisplay for BonePose<'a> {}