VoxelEngine/src/objects/rigging.hpp

160 lines
3.6 KiB
C++

#pragma once
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/norm.hpp>
#include <memory>
#include <string>
#include <cmath>
#include <unordered_map>
#include <vector>
#include "typedefs.hpp"
#include "data/dv_fwd.hpp"
#include "util/Interpolation.hpp"
class Assets;
class ModelBatch;
namespace model {
struct Model;
}
namespace rigging {
struct Skeleton;
class SkeletonConfig;
struct Pose {
std::vector<glm::mat4> matrices;
Pose(size_t size) {
matrices.resize(size, glm::mat4(1.0f));
}
};
struct ModelReference {
std::string name;
model::Model* model;
bool updateFlag;
void refresh(const Assets& assets);
};
class Bone {
size_t index;
std::string name;
std::vector<std::unique_ptr<Bone>> bones;
glm::vec3 offset;
public:
ModelReference model;
Bone(
size_t index,
std::string name,
std::string model,
std::vector<std::unique_ptr<Bone>> bones,
const glm::vec3& offset
);
void setModel(const std::string& name);
const std::string& getName() const {
return name;
}
size_t getIndex() const {
return index;
}
glm::vec3 getOffset() const {
return offset;
}
const auto& getSubnodes() const {
return bones;
}
};
struct BoneFlags {
bool visible : 1;
};
struct Skeleton {
const SkeletonConfig* config;
Pose pose;
Pose calculated;
std::vector<BoneFlags> flags;
std::unordered_map<std::string, std::string> textures;
std::vector<ModelReference> modelOverrides;
bool visible;
glm::vec3 tint {1.0f, 1.0f, 1.0f};
util::VecInterpolation<3, float> interpolation {false};
Skeleton(const SkeletonConfig* config);
dv::value serialize(bool saveTextures, bool savePose) const;
void deserialize(const dv::value& root);
};
class SkeletonConfig {
std::string name;
std::unique_ptr<Bone> root;
std::unordered_map<std::string, size_t> indices;
/// Nodes and indices are ordered from root to bones.
/// Example:
/// 0 - root
/// 1 --- sub1
/// 2 ----- subsub1
/// 3 --- sub2
std::vector<Bone*> nodes;
size_t update(
size_t index, Skeleton& skeleton, Bone* node, const glm::mat4& matrix
) const;
public:
SkeletonConfig(
const std::string& name,
std::unique_ptr<Bone> root,
size_t nodesCount
);
void update(
Skeleton& skeleton,
const glm::mat3& rotation,
const glm::vec3& position,
const glm::vec3& scale
) const;
void render(
const Assets& assets,
ModelBatch& batch,
Skeleton& skeleton,
const glm::mat3& rotation,
const glm::vec3& position,
const glm::vec3& scale
) const;
Skeleton instance() const {
return Skeleton(this);
}
Bone* find(std::string_view str) const;
static std::unique_ptr<SkeletonConfig> parse(
std::string_view src, std::string_view file, std::string_view name
);
const std::vector<Bone*>& getBones() const {
return nodes;
}
const std::string& getName() const {
return name;
}
Bone* getRoot() const {
return root.get();
}
};
};