summaryrefslogtreecommitdiffstats
path: root/src/animation/AnimBlendNode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/animation/AnimBlendNode.cpp')
-rw-r--r--src/animation/AnimBlendNode.cpp170
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