From 0060c2a00a1690e618e337b857b8509cbf899915 Mon Sep 17 00:00:00 2001 From: john Date: Sun, 18 Oct 2026 12:36:05 -0400 Subject: [PATCH] aded fo;e --- .!7804!Animator.h | 105 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 .!7804!Animator.h diff --git a/.!7804!Animator.h b/.!7804!Animator.h new file mode 100644 index 0000000..44bd173 --- /dev/null +++ b/.!7804!Animator.h @@ -0,0 +1,105 @@ +#ifndef ANIMATOR_CLASS +#define ANIMATOR_CLASS + +#include +#include +#include +#include +#include +#include +#include +#include "Rig.h" + +// Scale of the "Head" bone (and what hangs off it), around the neck. 1 = as authored. +inline float HeadScale = 1.0f; + +struct AssimpNodeData +{ + glm::mat4 transformation; + std::string name; + int childrenCount; + std::vector children; +}; + +// ============================================================================ +// Animation +// ============================================================================ +class Animation +{ +public: + Animation() = default; + + Animation(const std::string& animationPath, Rig* rig = nullptr) + { + Assimp::Importer importer; + const aiScene* scene = importer.ReadFile(animationPath, aiProcess_Triangulate); + assert(scene && scene->mRootNode); + + const aiAnimation* anim = scene->mAnimations[0]; + m_Duration = (float)anim->mDuration; + m_TicksPerSecond = (int)(anim->mTicksPerSecond != 0 ? anim->mTicksPerSecond : 24); + + ReadHierarchyData(m_RootNode, scene->mRootNode); + + for (unsigned int i = 0; i < anim->mNumChannels; i++) { + const aiNodeAnim* channel = anim->mChannels[i]; + m_Bones.emplace_back(channel->mNodeName.data, 0, channel); + m_BoneNames.push_back(channel->mNodeName.data); + } + + if (rig) RegisterBonesWithRig(*rig); + } + + void RegisterBonesWithRig(Rig& rig) + { + for (const std::string& name : m_BoneNames) { + if (rig.m_BoneInfoMap.find(name) == rig.m_BoneInfoMap.end()) { + BoneInfo info; + info.id = rig.m_BoneCounter++; + info.offset = glm::mat4(1.0f); + rig.m_BoneInfoMap[name] = info; + } + } + } + + Bone* FindBone(const std::string& name) + { + for (Bone& b : m_Bones) + if (b.GetBoneName() == name) return &b; + return nullptr; + } + + float GetTicksPerSecond() const { return (float)m_TicksPerSecond; } + float GetDuration() const { return m_Duration; } + const AssimpNodeData& GetRootNode() const { return m_RootNode; } + +public: + float m_Duration = 0.0f; + int m_TicksPerSecond = 24; + std::vector m_Bones; + std::vector m_BoneNames; + AssimpNodeData m_RootNode; + +private: + void ReadHierarchyData(AssimpNodeData& dest, const aiNode* src) + { + assert(src); + dest.name = src->mName.data; + dest.transformation = AssimpGLMHelpers::ConvertMatrixToGLMFormat(src->mTransformation); + dest.childrenCount = (int)src->mNumChildren; + for (unsigned int i = 0; i < src->mNumChildren; i++) { + AssimpNodeData child; + ReadHierarchyData(child, src->mChildren[i]); + dest.children.push_back(child); + } + } +}; + +// ============================================================================ +// Animator +// blendWeight ramps from 0?1 over blendDuration when PlayAnimation is called. +// CharacterBody::GetBlendedBoneMatrices() lerps all animators by blendWeight. +// ============================================================================ +class Animator +{ +public: