skeleton.h 3.89 KB
Newer Older
TheNumbat's avatar
TheNumbat committed
1
2
3

#pragma once

TheNumbat's avatar
TheNumbat committed
4
#include <functional>
TheNumbat's avatar
TheNumbat committed
5
6
7
#include <set>
#include <unordered_map>
#include <unordered_set>
TheNumbat's avatar
TheNumbat committed
8
#include <vector>
TheNumbat's avatar
TheNumbat committed
9
10

#include "../geometry/spline.h"
TheNumbat's avatar
TheNumbat committed
11
#include "../lib/mathlib.h"
TheNumbat's avatar
TheNumbat committed
12
13
14
15
16
#include "../platform/gl.h"

class Joint {
public:
    Joint(unsigned int id) : _id(id) {}
TheNumbat's avatar
TheNumbat committed
17
18
19
20
21
    Joint(unsigned int id, Joint *parent, Vec3 extent) : _id(id), parent(parent), extent(extent) {}
    ~Joint() {
        for (Joint *j : children)
            delete j;
    }
TheNumbat's avatar
TheNumbat committed
22

TheNumbat's avatar
TheNumbat committed
23
24
    Joint(const Joint &src) = delete;
    Joint(Joint &&src) = default;
TheNumbat's avatar
TheNumbat committed
25

TheNumbat's avatar
TheNumbat committed
26
27
    void operator=(const Joint &src) = delete;
    Joint &operator=(Joint &&src) = default;
TheNumbat's avatar
TheNumbat committed
28
29

    unsigned int id() const { return _id; }
TheNumbat's avatar
TheNumbat committed
30

TheNumbat's avatar
TheNumbat committed
31
32
33
34
35
    // Checks if this joint is a root node
    bool is_root() const;

    // Euler angles representing the current joint rotation
    Vec3 pose;
TheNumbat's avatar
TheNumbat committed
36

TheNumbat's avatar
TheNumbat committed
37
    // The vector representing the direction and length of the bone.
TheNumbat's avatar
TheNumbat committed
38
    // This is specified in Joint space, and defines the origin of child bones.
TheNumbat's avatar
TheNumbat committed
39
    Vec3 extent = Vec3(0.0f, 1.0f, 0.0f);
TheNumbat's avatar
TheNumbat committed
40

TheNumbat's avatar
TheNumbat committed
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
    // The distance at which the joint segment should stop effecting vertices
    float radius = 0.25f;

private:
    // Builds the transformation matrix that takes a point in joint space to the mesh
    // space (in bind position). "Bind" position implies that the rotation of all joints
    // should be zero. Also note that this does not include the Skeleton's base_pos,
    // but it should include the transformations of the joint heirachy up to this point.
    Mat4 joint_to_bind() const;

    // Similarly, builds the transformation that takes a point in the space of this joint
    // into mesh space - taking into account the poses of the joint heirarchy. This also does
    // not include the Skeleton's base_pos.
    Mat4 joint_to_posed() const;

    // Pointer to parent joint in the joint heirarchy
TheNumbat's avatar
TheNumbat committed
57
    Joint *parent = nullptr;
TheNumbat's avatar
TheNumbat committed
58
59

    // Set of child joints - owned by this joint (could be shared_ptr and everything else weak_ptr)
TheNumbat's avatar
TheNumbat committed
60
    std::unordered_set<Joint *> children;
TheNumbat's avatar
TheNumbat committed
61

TheNumbat's avatar
TheNumbat committed
62
    void for_joints(std::function<void(Joint *)> func);
TheNumbat's avatar
TheNumbat committed
63
64
65
66
67
68
69
70
71
72
73
74
75
76

    unsigned int _id = 0;
    Spline<Quat> anim;

    friend class Skeleton;
    friend class Scene;
};

class Skeleton {
public:
    Skeleton();
    Skeleton(unsigned int obj_id);
    ~Skeleton();

TheNumbat's avatar
TheNumbat committed
77
78
    Skeleton(const Skeleton &src) = delete;
    Skeleton(Skeleton &&src) = default;
TheNumbat's avatar
TheNumbat committed
79

TheNumbat's avatar
TheNumbat committed
80
81
    void operator=(const Skeleton &src) = delete;
    Skeleton &operator=(Skeleton &&src) = default;
TheNumbat's avatar
TheNumbat committed
82

TheNumbat's avatar
TheNumbat committed
83
    Vec3 &base();
TheNumbat's avatar
TheNumbat committed
84
85
86
    bool has_bones() const;
    unsigned int n_bones();

TheNumbat's avatar
TheNumbat committed
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
    Joint *parent(Joint *j);
    Joint *get_joint(unsigned int id);
    void erase(Joint *j);
    void restore(Joint *j);
    Vec3 end_of(Joint *j);
    Vec3 base_of(Joint *j);
    Vec3 posed_end_of(Joint *j);
    Vec3 posed_base_of(Joint *j);

    void for_joints(std::function<void(Joint *)> func);

    Mat4 joint_to_bind(const Joint *j) const;
    Mat4 joint_to_posed(const Joint *j) const;

    Joint *add_root(Vec3 extent);
    Joint *add_child(Joint *j, Vec3 extent);
TheNumbat's avatar
TheNumbat committed
103
    bool is_root_id(unsigned int id);
TheNumbat's avatar
TheNumbat committed
104

TheNumbat's avatar
TheNumbat committed
105
    bool set_time(float time);
TheNumbat's avatar
TheNumbat committed
106
107
108
109
110
111
112
    void render(const Mat4 &view, Joint *select, bool root, bool posed, unsigned int offset = 0);
    void outline(const Mat4 &view, Joint *select, bool root, bool posed, BBox &box,
                 unsigned int offset = 0);
    void find_joints(const GL::Mesh &src,
                     std::unordered_map<unsigned int, std::vector<Joint *>> &map);
    void skin(const GL::Mesh &input, GL::Mesh &output,
              const std::unordered_map<unsigned int, std::vector<Joint *>> &map);
TheNumbat's avatar
TheNumbat committed
113
114
115
116
117
118
119
120

    void set(float t);
    void crop(float t);
    void erase(float t);
    bool has_keyframes();
    std::set<float> keys();
    std::unordered_map<unsigned int, Vec3> now();
    std::unordered_map<unsigned int, Vec3> at(float t);
TheNumbat's avatar
TheNumbat committed
121
    void set(float t, const std::unordered_map<unsigned int, Vec3> &data);
TheNumbat's avatar
TheNumbat committed
122
123
124
125

private:
    Vec3 base_pos;
    unsigned int root_id, next_id;
TheNumbat's avatar
TheNumbat committed
126
    std::unordered_set<Joint *> roots, erased;
TheNumbat's avatar
TheNumbat committed
127
128
    friend class Scene;
};