VoxelEngine/src/objects/rigging.hpp
2024-08-10 01:57:59 +03:00

143 lines
3.1 KiB
C++

#pragma once
#include <glm/glm.hpp>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include "typedefs.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,
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};
Skeleton(const SkeletonConfig* config);
};
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, glm::mat4 matrix
) const;
public:
SkeletonConfig(
const std::string& name,
std::unique_ptr<Bone> root,
size_t nodesCount
);
void update(Skeleton& skeleton, glm::mat4 matrix) const;
void render(
Assets* assets,
ModelBatch& batch,
Skeleton& skeleton,
const glm::mat4& matrix
) 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();
}
};
};