Clean up the code to be not everything in hpp files.

This commit is contained in:
Zed A. Shaw 2026-10-07 12:30:22 -04:00
parent a1c8208b47
commit 6d21b7f163
6 changed files with 308 additions and 264 deletions

View file

@ -1 +1,84 @@
#include "animation.hpp" #include "animation.hpp"
#include "model.hpp"
#include "assimp_glm_helpers.hpp"
Animation::Animation(const std::string& animationPath, Model *model) {
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(animationPath, aiProcess_Triangulate);
dbc::check(scene != nullptr, $F("Scene for animation {} failed to load.", animationPath));
dbc::check(scene->mRootNode, $F("Scene {} doesn't have a root node.", animationPath));
auto animation = scene->mAnimations[0];
$duration = animation->mDuration;
$ticks_per_sec = animation->mTicksPerSecond;
aiMatrix4x4 globalTransformation = scene->mRootNode->mTransformation;
globalTransformation = globalTransformation.Inverse();
ReadHierarchyData($root_node, scene->mRootNode);
ReadMissingBones(animation, *model);
}
Bone* Animation::FindBone(const std::string& name) {
auto iter = std::find_if($bones.begin(), $bones.end(),
[&](const auto& bone) {
return bone.GetBoneName() == name;
}
);
return iter == $bones.end() ? nullptr : &(*iter);
}
float Animation::GetTicksPerSecond() {
return $ticks_per_sec;
}
float Animation::GetDuration() {
return $duration;
}
const AssimpNodeData& Animation::GetRootNode() {
return $root_node;
}
const std::unordered_map<std::string, BoneInfo>& Animation::GetBoneIDMap()
{
return $bone_info_map;
}
void Animation::ReadMissingBones(const aiAnimation* animation, Model& model) {
// this code is weird as hell
int size = animation->mNumChannels;
auto& boneInfoMap = model.bone_info_map;
int& boneCount = model.bone_counter;
for(int i = 0; i < size; i++) {
auto channel = animation->mChannels[i];
std::string boneName = channel->mNodeName.data;
if(!boneInfoMap.contains(boneName)) {
boneInfoMap[boneName].id = boneCount;
boneCount++;
}
dbc::check(boneCount < MAX_BONES, "Too many bones!");
$bones.emplace_back(boneName,
boneInfoMap[boneName].id, channel);
}
$bone_info_map = boneInfoMap;
}
void Animation::ReadHierarchyData(AssimpNodeData& dest, const aiNode* src) {
dbc::check(src != nullptr, "aiNode src is null?!");
dest.name = src->mName.data;
dest.transformation = AssimpGLMHelpers::ConvertMatrixToGLMFormat(src->mTransformation);
dest.children_count = src->mNumChildren;
for(size_t i = 0; i < src->mNumChildren; i++) {
AssimpNodeData newData;
ReadHierarchyData(newData, src->mChildren[i]);
dest.children.push_back(newData);
}
}

View file

@ -7,8 +7,6 @@
#include <functional> #include <functional>
#include "animdata.hpp" #include "animdata.hpp"
#include "bone.hpp" #include "bone.hpp"
#include "model.hpp"
#include "assimp_glm_helpers.hpp"
struct Bone; struct Bone;
@ -28,88 +26,21 @@ struct Animation {
Animation() = default; Animation() = default;
Animation(const std::string& animationPath, Model *model) { Animation(const std::string& animationPath, Model *model);
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(animationPath, aiProcess_Triangulate); ~Animation() {}
dbc::check(scene != nullptr, $F("Scene for animation {} failed to load.", animationPath));
dbc::check(scene->mRootNode, $F("Scene {} doesn't have a root node.", animationPath));
auto animation = scene->mAnimations[0]; Bone* FindBone(const std::string& name);
$duration = animation->mDuration;
$ticks_per_sec = animation->mTicksPerSecond;
aiMatrix4x4 globalTransformation = scene->mRootNode->mTransformation;
globalTransformation = globalTransformation.Inverse();
ReadHierarchyData($root_node, scene->mRootNode);
ReadMissingBones(animation, *model);
}
~Animation() { float GetTicksPerSecond();
}
float GetDuration();
Bone* FindBone(const std::string& name) { const AssimpNodeData& GetRootNode();
auto iter = std::find_if($bones.begin(), $bones.end(),
[&](const auto& bone) {
return bone.GetBoneName() == name;
}
);
return iter == $bones.end() ? nullptr : &(*iter); const std::unordered_map<std::string, BoneInfo>& GetBoneIDMap();
}
float GetTicksPerSecond() { void ReadMissingBones(const aiAnimation* animation, Model& model);
return $ticks_per_sec;
}
float GetDuration() { void ReadHierarchyData(AssimpNodeData& dest, const aiNode* src);
return $duration;
}
const AssimpNodeData& GetRootNode() {
return $root_node;
}
const std::unordered_map<std::string, BoneInfo>& GetBoneIDMap()
{
return $bone_info_map;
}
void ReadMissingBones(const aiAnimation* animation, Model& model) {
// this code is weird as hell
int size = animation->mNumChannels;
auto& boneInfoMap = model.bone_info_map;
int& boneCount = model.bone_counter;
for(int i = 0; i < size; i++) {
auto channel = animation->mChannels[i];
std::string boneName = channel->mNodeName.data;
if(!boneInfoMap.contains(boneName)) {
boneInfoMap[boneName].id = boneCount;
boneCount++;
}
dbc::check(boneCount < MAX_BONES, "Too many bones!");
$bones.emplace_back(boneName,
boneInfoMap[boneName].id, channel);
}
$bone_info_map = boneInfoMap;
}
void ReadHierarchyData(AssimpNodeData& dest, const aiNode* src) {
dbc::check(src != nullptr, "aiNode src is null?!");
dest.name = src->mName.data;
dest.transformation = AssimpGLMHelpers::ConvertMatrixToGLMFormat(src->mTransformation);
dest.children_count = src->mNumChildren;
for(size_t i = 0; i < src->mNumChildren; i++) {
AssimpNodeData newData;
ReadHierarchyData(newData, src->mChildren[i]);
dest.children.push_back(newData);
}
}
}; };

View file

@ -1 +1,57 @@
#include "animator.hpp" #include "animator.hpp"
#include <assimp/scene.h>
#include <assimp/Importer.hpp>
#include "bone.hpp"
Animator::Animator(Animation* animation) :
$current_animation(animation)
{
$final_bone_matrices.reserve(MAX_BONES);
for(size_t i = 0; i < MAX_BONES; i++) {
$final_bone_matrices.push_back(glm::mat4(1.0f));
}
}
void Animator::UpdateAnimation(float current_time) {
if($current_animation) {
$current_time = $current_animation->GetTicksPerSecond() * current_time;
$current_time = fmod($current_time, $current_animation->GetDuration());
CalculateBoneTransform(&$current_animation->GetRootNode(), glm::mat4(1.0f));
}
}
void Animator::PlayAnimation(Animation* animation) {
$current_animation = animation;
$current_time = 0.0f;
}
void Animator::CalculateBoneTransform(const AssimpNodeData* node, glm::mat4 parentTransform) {
std::string node_name = node->name;
glm::mat4 node_transform = node->transformation;
Bone *bone = $current_animation->FindBone(node_name);
if(bone) {
bone->Update($current_time);
node_transform = bone->GetLocalTransform();
}
glm::mat4 global_transformation = parentTransform * node_transform;
auto bone_map = $current_animation->GetBoneIDMap();
if(bone_map.contains(node_name)) {
auto& bone_info = bone_map[node_name];
$final_bone_matrices[bone_info.id] = global_transformation * bone_info.offset;
}
for(int i = 0; i < node->children_count; i++) {
CalculateBoneTransform(&node->children[i], global_transformation);
}
}
std::vector<glm::mat4>& Animator::GetFinalBoneMatrices() {
return $final_bone_matrices;
}

View file

@ -1,72 +1,22 @@
#pragma once #pragma once
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <map> #include <map>
#include <vector> #include <vector>
#include <assimp/scene.h>
#include <assimp/Importer.hpp>
#include "animation.hpp" #include "animation.hpp"
#include "bone.hpp"
struct Bone;
struct Animator { struct Animator {
std::vector<glm::mat4> $final_bone_matrices; std::vector<glm::mat4> $final_bone_matrices;
Animation* $current_animation = nullptr; Animation* $current_animation = nullptr;
float $current_time = 0.0f; float $current_time = 0.0f;
Animator(Animation* animation) : Animator(Animation* animation);
$current_animation(animation)
{
$final_bone_matrices.reserve(MAX_BONES);
for(size_t i = 0; i < MAX_BONES; i++) { void UpdateAnimation(float current_time);
$final_bone_matrices.push_back(glm::mat4(1.0f));
}
}
void UpdateAnimation(float current_time) { void PlayAnimation(Animation* animation);
if($current_animation) {
$current_time = $current_animation->GetTicksPerSecond() * current_time;
$current_time = fmod($current_time, $current_animation->GetDuration());
CalculateBoneTransform(&$current_animation->GetRootNode(), glm::mat4(1.0f));
}
}
void PlayAnimation(Animation* animation) { void CalculateBoneTransform(const AssimpNodeData* node, glm::mat4 parentTransform);
$current_animation = animation;
$current_time = 0.0f;
}
void CalculateBoneTransform(const AssimpNodeData* node, glm::mat4 parentTransform) {
std::string node_name = node->name;
glm::mat4 node_transform = node->transformation;
Bone *bone = $current_animation->FindBone(node_name);
if(bone) {
bone->Update($current_time);
node_transform = bone->GetLocalTransform();
}
glm::mat4 global_transformation = parentTransform * node_transform;
auto bone_map = $current_animation->GetBoneIDMap();
if(bone_map.contains(node_name)) {
auto& bone_info = bone_map[node_name];
$final_bone_matrices[bone_info.id] = global_transformation * bone_info.offset;
}
for(int i = 0; i < node->children_count; i++) {
CalculateBoneTransform(&node->children[i], global_transformation);
}
}
std::vector<glm::mat4>& GetFinalBoneMatrices() {
return $final_bone_matrices;
}
std::vector<glm::mat4>& GetFinalBoneMatrices();
}; };

View file

@ -1 +1,144 @@
#include "bone.hpp" #include "bone.hpp"
#include "assimp_glm_helpers.hpp"
Bone::Bone(const std::string& name, int ID, const aiNodeAnim* channel) :
$name(name),
$id(ID)
{
$num_positions = channel->mNumPositionKeys;
for(size_t pos_i = 0; pos_i < $num_positions; pos_i++) {
const auto& ai_position = channel->mPositionKeys[pos_i];
auto position = AssimpGLMHelpers::GetGLMVec(ai_position.mValue);
$positions.emplace_back(position, ai_position.mTime);
}
$num_rotations = channel->mNumRotationKeys;
for(size_t rot_i = 0; rot_i < $num_rotations; rot_i++) {
const auto& ai_orientation = channel->mRotationKeys[rot_i];
auto orientation = AssimpGLMHelpers::GetGLMQuat(ai_orientation.mValue);
$rotations.emplace_back(orientation, ai_orientation.mTime);
}
$num_scalings = channel->mNumScalingKeys;
for(size_t key_i = 0; key_i < $num_scalings; key_i++) {
const auto& ai_scale = channel->mScalingKeys[key_i];
auto scale = AssimpGLMHelpers::GetGLMVec(ai_scale.mValue);
$scales.emplace_back(scale, ai_scale.mTime);
}
}
void Bone::Update(float animationTime) {
glm::mat4 translation = InterpolatPosition(animationTime);
glm::mat4 rotation = InterpolateRotation(animationTime);
glm::mat4 scale = InterpolateScaling(animationTime);
$local_transform = translation * rotation * scale;
}
glm::mat4 Bone::GetLocalTransform() {
return $local_transform;
}
std::string Bone::GetBoneName() const {
return $name;
}
int Bone::GetBoneId() {
return $id;
}
int Bone::GetPositionIndex(float animationTime) {
for(size_t index = 0; index < $num_positions - 1; ++index) {
auto ts = $positions[index + 1].timeStamp;
if(animationTime < ts) {
return index;
}
}
dbc::sentinel("Failed to find an animation position");
}
int Bone::GetRotationIndex(float animationTime) {
for(size_t index = 0; index < $num_rotations - 1; ++index) {
auto ts = $rotations[index + 1].timeStamp;
if(animationTime < ts) {
return index;
}
}
dbc::sentinel("Failed to find an animation rotation");
}
int Bone::GetScaleIndex(float animationTime) {
for(size_t index = 0; index < $num_scalings - 1; ++index) {
auto ts = $scales[index + 1].timeStamp;
if(animationTime < ts) {
return index;
}
}
dbc::sentinel("Failed to find an animation scale");
}
float Bone::GetScaleFactor(float lastTimeStamp, float nextTimeStamp, float animationTime) {
float scaleFactor = 0.0f;
float midWayLength = animationTime - lastTimeStamp;
float framesDiff = nextTimeStamp - lastTimeStamp;
scaleFactor = midWayLength / framesDiff;
return scaleFactor;
}
glm::mat4 Bone::InterpolatPosition(float animationTime) {
if($num_positions == 1) {
return glm::translate(glm::mat4(1.0f), $positions[0].position);
}
int p0Index = GetPositionIndex(animationTime);
auto& p0 = $positions[p0Index];
auto& p1 = $positions[p0Index + 1];
float scaleFactor = GetScaleFactor(
p0.timeStamp, p1.timeStamp, animationTime);
glm::vec3 finalPosition = glm::mix(p0.position,
p1.position, scaleFactor);
return glm::translate(glm::mat4(1.0f), finalPosition);
}
glm::mat4 Bone::InterpolateRotation(float animationTime) {
if($num_rotations == 1) {
auto rotation = glm::normalize($rotations[0].orientation);
return glm::toMat4(rotation);
}
int p0Index = GetRotationIndex(animationTime);
auto& p0 = $rotations[p0Index];
auto& p1 = $rotations[p0Index + 1];
float scaleFactor = GetScaleFactor(
p0.timeStamp, p1.timeStamp, animationTime);
glm::quat finalRotation = glm::slerp(
p0.orientation, p1.orientation, scaleFactor);
return glm::toMat4(finalRotation);
}
glm::mat4 Bone::InterpolateScaling(float animationTime) {
if($num_scalings == 1) {
return glm::scale(glm::mat4(1.0f), $scales[0].scale);
}
int p0Index = GetScaleIndex(animationTime);
auto& p0 = $scales[p0Index];
auto& p1 = $scales[p0Index + 1];
float scaleFactor = GetScaleFactor(
p0.timeStamp, p1.timeStamp, animationTime);
glm::vec3 finalScale = glm::mix(p0.scale, p1.scale, scaleFactor);
return glm::scale(glm::mat4(1.0f), finalScale);
}

View file

@ -6,7 +6,6 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#define GLM_ENABLE_EXPERIMENTAL #define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/quaternion.hpp> #include <glm/gtx/quaternion.hpp>
#include "assimp_glm_helpers.hpp"
#include <string> #include <string>
struct KeyPosition { struct KeyPosition {
@ -40,145 +39,27 @@ struct Bone
std::string $name{}; std::string $name{};
int $id = 0; int $id = 0;
Bone(const std::string& name, int ID, const aiNodeAnim* channel) : Bone(const std::string& name, int ID, const aiNodeAnim* channel);
$name(name),
$id(ID)
{
$num_positions = channel->mNumPositionKeys;
for(size_t pos_i = 0; pos_i < $num_positions; pos_i++) { void Update(float animationTime);
const auto& ai_position = channel->mPositionKeys[pos_i];
auto position = AssimpGLMHelpers::GetGLMVec(ai_position.mValue);
$positions.emplace_back(position, ai_position.mTime);
}
$num_rotations = channel->mNumRotationKeys; glm::mat4 GetLocalTransform();
for(size_t rot_i = 0; rot_i < $num_rotations; rot_i++) {
const auto& ai_orientation = channel->mRotationKeys[rot_i];
auto orientation = AssimpGLMHelpers::GetGLMQuat(ai_orientation.mValue);
$rotations.emplace_back(orientation, ai_orientation.mTime); std::string GetBoneName() const;
}
$num_scalings = channel->mNumScalingKeys; int GetBoneId();
for(size_t key_i = 0; key_i < $num_scalings; key_i++) {
const auto& ai_scale = channel->mScalingKeys[key_i];
auto scale = AssimpGLMHelpers::GetGLMVec(ai_scale.mValue);
$scales.emplace_back(scale, ai_scale.mTime);
}
}
void Update(float animationTime) { int GetPositionIndex(float animationTime);
glm::mat4 translation = InterpolatPosition(animationTime);
glm::mat4 rotation = InterpolateRotation(animationTime);
glm::mat4 scale = InterpolateScaling(animationTime);
$local_transform = translation * rotation * scale;
}
glm::mat4 GetLocalTransform() { int GetRotationIndex(float animationTime);
return $local_transform;
}
std::string GetBoneName() const { int GetScaleIndex(float animationTime);
return $name;
}
int GetBoneId() { float GetScaleFactor(float lastTimeStamp, float nextTimeStamp, float animationTime);
return $id;
}
int GetPositionIndex(float animationTime) { glm::mat4 InterpolatPosition(float animationTime);
for(size_t index = 0; index < $num_positions - 1; ++index) {
auto ts = $positions[index + 1].timeStamp;
if(animationTime < ts) { glm::mat4 InterpolateRotation(float animationTime);
return index;
}
}
dbc::sentinel("Failed to find an animation position"); glm::mat4 InterpolateScaling(float animationTime);
}
int GetRotationIndex(float animationTime) {
for(size_t index = 0; index < $num_rotations - 1; ++index) {
auto ts = $rotations[index + 1].timeStamp;
if(animationTime < ts) {
return index;
}
}
dbc::sentinel("Failed to find an animation rotation");
}
int GetScaleIndex(float animationTime) {
for(size_t index = 0; index < $num_scalings - 1; ++index) {
auto ts = $scales[index + 1].timeStamp;
if(animationTime < ts) {
return index;
}
}
dbc::sentinel("Failed to find an animation scale");
}
float GetScaleFactor(float lastTimeStamp, float nextTimeStamp, float animationTime) {
float scaleFactor = 0.0f;
float midWayLength = animationTime - lastTimeStamp;
float framesDiff = nextTimeStamp - lastTimeStamp;
scaleFactor = midWayLength / framesDiff;
return scaleFactor;
}
glm::mat4 InterpolatPosition(float animationTime) {
if($num_positions == 1) {
return glm::translate(glm::mat4(1.0f), $positions[0].position);
}
int p0Index = GetPositionIndex(animationTime);
auto& p0 = $positions[p0Index];
auto& p1 = $positions[p0Index + 1];
float scaleFactor = GetScaleFactor(
p0.timeStamp, p1.timeStamp, animationTime);
glm::vec3 finalPosition = glm::mix(p0.position,
p1.position, scaleFactor);
return glm::translate(glm::mat4(1.0f), finalPosition);
}
glm::mat4 InterpolateRotation(float animationTime) {
if($num_rotations == 1) {
auto rotation = glm::normalize($rotations[0].orientation);
return glm::toMat4(rotation);
}
int p0Index = GetRotationIndex(animationTime);
auto& p0 = $rotations[p0Index];
auto& p1 = $rotations[p0Index + 1];
float scaleFactor = GetScaleFactor(
p0.timeStamp, p1.timeStamp, animationTime);
glm::quat finalRotation = glm::slerp(
p0.orientation, p1.orientation, scaleFactor);
return glm::toMat4(finalRotation);
}
glm::mat4 InterpolateScaling(float animationTime) {
if($num_scalings == 1) {
return glm::scale(glm::mat4(1.0f), $scales[0].scale);
}
int p0Index = GetScaleIndex(animationTime);
auto& p0 = $scales[p0Index];
auto& p1 = $scales[p0Index + 1];
float scaleFactor = GetScaleFactor(
p0.timeStamp, p1.timeStamp, animationTime);
glm::vec3 finalScale = glm::mix(p0.scale, p1.scale, scaleFactor);
return glm::scale(glm::mat4(1.0f), finalScale);
}
}; };