diff options
Diffstat (limited to 'src/animation/AnimBlendNode.cpp')
-rw-r--r-- | src/animation/AnimBlendNode.cpp | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/src/animation/AnimBlendNode.cpp b/src/animation/AnimBlendNode.cpp new file mode 100644 index 00000000..3d3d80ec --- /dev/null +++ b/src/animation/AnimBlendNode.cpp @@ -0,0 +1,170 @@ +#include "common.h" +#include "patcher.h" +#include "AnimBlendAssociation.h" +#include "AnimBlendNode.h" + +void +CAnimBlendNode::Init(void) +{ + frameA = 0; + frameB = 0; + remainingTime = 0.0f; + sequence = nil; + association = nil; +} + +bool +CAnimBlendNode::Update(CVector &trans, CQuaternion &rot, float weight) +{ + bool looped = false; + + trans = CVector(0.0f, 0.0f, 0.0f); + rot = CQuaternion(0.0f, 0.0f, 0.0f, 0.0f); + + if(association->IsRunning()){ + remainingTime -= association->timeStep; + if(remainingTime <= 0.0f) + looped = NextKeyFrame(); + } + + float blend = association->GetBlendAmount(weight); + if(blend > 0.0f){ + KeyFrameTrans *kfA = (KeyFrameTrans*)sequence->GetKeyFrame(frameA); + KeyFrameTrans *kfB = (KeyFrameTrans*)sequence->GetKeyFrame(frameB); + float t = kfA->deltaTime == 0.0f ? 0.0f : (kfA->deltaTime - remainingTime)/kfA->deltaTime; + if(sequence->type & CAnimBlendSequence::KF_TRANS){ + trans = kfB->translation + t*(kfA->translation - kfB->translation); + trans *= blend; + } + if(sequence->type & CAnimBlendSequence::KF_ROT){ + rot.Slerp(kfB->rotation, kfA->rotation, theta, invSin, t); + rot *= blend; + } + } + + return looped; +} + +bool +CAnimBlendNode::NextKeyFrame(void) +{ + bool looped; + + if(sequence->numFrames <= 1) + return false; + + looped = false; + frameB = frameA; + + // Advance as long as we have to + while(remainingTime <= 0.0f){ + frameA++; + + if(frameA >= sequence->numFrames){ + // reached end of animation + if(!association->IsRepeating()){ + frameA--; + remainingTime = 0.0f; + return false; + } + looped = true; + frameA = 0; + } + + remainingTime += sequence->GetKeyFrame(frameA)->deltaTime; + } + + frameB = frameA - 1; + if(frameB < 0) + frameB += sequence->numFrames; + + CalcDeltas(); + return looped; +} + +// Set animation to time t +bool +CAnimBlendNode::FindKeyFrame(float t) +{ + if(sequence->numFrames < 1) + return false; + + frameA = 0; + frameB = frameA; + + if(sequence->numFrames >= 2){ + frameA++; + + // advance until t is between frameB and frameA + while(t > sequence->GetKeyFrame(frameA)->deltaTime){ + t -= sequence->GetKeyFrame(frameA)->deltaTime; + frameB = frameA++; + if(frameA >= sequence->numFrames){ + // reached end of animation + if(!association->IsRepeating()) + return false; + frameA = 0; + frameB = 0; + } + } + + remainingTime = sequence->GetKeyFrame(frameA)->deltaTime - t; + } + + CalcDeltas(); + return true; +} + +void +CAnimBlendNode::CalcDeltas(void) +{ + if((sequence->type & CAnimBlendSequence::KF_ROT) == 0) + return; + KeyFrame *kfA = sequence->GetKeyFrame(frameA); + KeyFrame *kfB = sequence->GetKeyFrame(frameB); + float cos = DotProduct(kfA->rotation, kfB->rotation); + if(cos > 1.0f) + cos = 1.0f; + theta = acos(cos); + invSin = theta == 0.0f ? 0.0f : 1.0f/sin(theta); +} + +void +CAnimBlendNode::GetCurrentTranslation(CVector &trans, float weight) +{ + trans = CVector(0.0f, 0.0f, 0.0f); + + float blend = association->GetBlendAmount(weight); + if(blend > 0.0f){ + KeyFrameTrans *kfA = (KeyFrameTrans*)sequence->GetKeyFrame(frameA); + KeyFrameTrans *kfB = (KeyFrameTrans*)sequence->GetKeyFrame(frameB); + float t = (kfA->deltaTime - remainingTime)/kfA->deltaTime; + if(sequence->type & CAnimBlendSequence::KF_TRANS){ + trans = kfB->translation + t*(kfA->translation - kfB->translation); + trans *= blend; + } + } +} + +void +CAnimBlendNode::GetEndTranslation(CVector &trans, float weight) +{ + trans = CVector(0.0f, 0.0f, 0.0f); + + float blend = association->GetBlendAmount(weight); + if(blend > 0.0f){ + KeyFrameTrans *kf = (KeyFrameTrans*)sequence->GetKeyFrame(sequence->numFrames-1); + if(sequence->type & CAnimBlendSequence::KF_TRANS) + trans = kf->translation * blend; + } +} + +STARTPATCHES + InjectHook(0x401B10, &CAnimBlendNode::Init, PATCH_JUMP); + InjectHook(0x401B30, &CAnimBlendNode::Update, PATCH_JUMP); + InjectHook(0x401DC0, &CAnimBlendNode::NextKeyFrame, PATCH_JUMP); + InjectHook(0x4021B0, &CAnimBlendNode::FindKeyFrame, PATCH_JUMP); + InjectHook(0x401E70, &CAnimBlendNode::CalcDeltas, PATCH_JUMP); + InjectHook(0x401FE0, &CAnimBlendNode::GetCurrentTranslation, PATCH_JUMP); + InjectHook(0x402110, &CAnimBlendNode::GetEndTranslation, PATCH_JUMP); +ENDPATCHES |