#include "Skeleton.hpp"
#include "Debug.hpp"
#include "DynamicMesh.hpp"
#include "SkeletonBone.hpp"
#include <wren/skeleton.h>
#include <string>
namespace wren {
Skeleton::~Skeleton() {
for (SkeletonBone *bone : mBones)
Node::deleteNode(bone);
}
void Skeleton::addMesh(DynamicMesh *mesh) {
mMeshes.push_back(mesh);
mVertexBones[mesh].assign(mesh->coords().size(), std::vector<size_t>());
mesh->setSkeleton(this);
}
void Skeleton::attachVertexToBone(DynamicMesh *mesh, unsigned int vertex, SkeletonBone *bone, float weight) {
for (size_t i = 0; i < mBones.size(); ++i) {
if (mBones[i] == bone) {
mVertexBones[mesh][vertex].push_back(i);
bone->setVertexWeight(mesh, vertex, weight);
return;
}
}
}
glm::mat4 Skeleton::vertexMatrix(DynamicMesh *mesh, unsigned int vertexIndex) {
glm::mat4 m(0.0f);
for (unsigned int boneIndex : mVertexBones[mesh][vertexIndex]) {
SkeletonBone *bone = mBones[boneIndex];
const float weight = bone->vertexWeight(mesh, vertexIndex);
m += weight * bone->finalTransform();
}
return m;
}
glm::mat4 Skeleton::matrix() const {
if (parent())
return parent()->matrix();
else
return glm::mat4(1.0f);
}
void Skeleton::updateOffset() {
if (parent()) {
for (DynamicMesh *mesh : mMeshes)
mesh->updateSkeletonOffset(mOffsetMatrix * parent()->relativeMatrix());
}
}
SkeletonBone *Skeleton::getBoneByName(const char *name) {
for (SkeletonBone *bone : mBones) {
if (std::string(name) == bone->name())
return bone;
}
return NULL;
}
void Skeleton::normalizeWeights() {
for (DynamicMesh *mesh : mMeshes) {
for (size_t i = 0; i < mesh->coords().size(); ++i) {
float totalWeight = 0.0f;
for (unsigned int boneIndex : mVertexBones[mesh][i])
totalWeight += mBones[boneIndex]->vertexWeight(mesh, i);
assert(totalWeight > 0.0f);
for (unsigned int boneIndex : mVertexBones[mesh][i]) {
const float boneWeight = mBones[boneIndex]->vertexWeight(mesh, i);
mBones[boneIndex]->setVertexWeight(mesh, i, boneWeight / totalWeight);
}
}
}
}
void Skeleton::applyBindingPose() {
for (DynamicMesh *mesh : mMeshes)
mesh->applySkeletonOffset();
for (SkeletonBone *bone : mBones)
bone->applyBindingPose();
if (parent())
mOffsetMatrix = matrix() * glm::inverse(parent()->relativeMatrix());
}
void Skeleton::notifyDirty() {
for (DynamicMesh *mesh : mMeshes)
mesh->notifySkeletonDirty();
}
float *Skeleton::computeBoundingSphere(int &meshCount) {
meshCount = mMeshes.size();
if (meshCount == 0)
return NULL;
float *result = new float[4 * meshCount];
int index = 0;
for (DynamicMesh *mesh : mMeshes) {
const primitive::Sphere &bs = mesh->recomputeBoundingSphere();
result[index] = bs.mCenter.x;
result[index + 1] = bs.mCenter.y;
result[index + 2] = bs.mCenter.z;
result[index + 3] = bs.mRadius;
index += 4;
}
return result;
}
}
WrSkeleton *wr_skeleton_new() {
return reinterpret_cast<WrSkeleton *>(wren::Skeleton::createSkeleton());
}
int wr_skeleton_get_bone_count(WrSkeleton *skeleton) {
return reinterpret_cast<wren::Skeleton *>(skeleton)->getBoneCount();
}
WrSkeletonBone *wr_skeleton_get_bone_by_index(WrSkeleton *skeleton, int index) {
return reinterpret_cast<WrSkeletonBone *>(reinterpret_cast<wren::Skeleton *>(skeleton)->getBoneByIndex(index));
}
WrSkeletonBone *wr_skeleton_get_bone_by_name(WrSkeleton *skeleton, const char *name) {
return reinterpret_cast<WrSkeletonBone *>(reinterpret_cast<wren::Skeleton *>(skeleton)->getBoneByName(name));
}
void wr_skeleton_apply_binding_pose(WrSkeleton *skeleton) {
reinterpret_cast<wren::Skeleton *>(skeleton)->applyBindingPose();
}
void wr_skeleton_update_offset(WrSkeleton *skeleton) {
reinterpret_cast<wren::Skeleton *>(skeleton)->updateOffset();
}
float *wr_skeleton_compute_bounding_spheres(WrSkeleton *skeleton, int &count) {
return reinterpret_cast<wren::Skeleton *>(skeleton)->computeBoundingSphere(count);
}