From e7ed4d009636804d5dbe05aae9e7ab23b80fdd37 Mon Sep 17 00:00:00 2001 From: aap Date: Tue, 11 Jun 2019 08:59:28 +0200 Subject: added animation system (with skin support for now) --- src/animation/AnimBlendAssociation.cpp | 227 +++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 src/animation/AnimBlendAssociation.cpp (limited to 'src/animation/AnimBlendAssociation.cpp') diff --git a/src/animation/AnimBlendAssociation.cpp b/src/animation/AnimBlendAssociation.cpp new file mode 100644 index 00000000..eb7019ab --- /dev/null +++ b/src/animation/AnimBlendAssociation.cpp @@ -0,0 +1,227 @@ +#include "common.h" +#include "patcher.h" +#include "AnimBlendHierarchy.h" +#include "AnimBlendClumpData.h" +#include "RpAnimBlend.h" +#include "AnimManager.h" +#include "AnimBlendAssociation.h" + +// TODO: implement those +#define RwFreeAlign RwFree +#define RwMallocAlign(sz, algn) RwMalloc(sz) + +CAnimBlendAssociation::CAnimBlendAssociation(void) +{ + nodes = nil; + blendAmount = 1.0f; + blendDelta = 0.0f; + currentTime = 0.0f; + speed = 1.0f; + timeStep = 0.0f; + animId = -1; + flags = 0; + callbackType = CB_NONE; + link.Init(); +} + +CAnimBlendAssociation::CAnimBlendAssociation(CAnimBlendAssociation &other) +{ + nodes = nil; + blendAmount = 1.0f; + blendDelta = 0.0f; + currentTime = 0.0f; + speed = 1.0f; + timeStep = 0.0f; + callbackType = CB_NONE; + link.Init(); + Init(other); +} + +CAnimBlendAssociation::~CAnimBlendAssociation(void) +{ + FreeAnimBlendNodeArray(); + link.Remove(); +} + + +void +CAnimBlendAssociation::AllocateAnimBlendNodeArray(int n) +{ + int i; + + nodes = (CAnimBlendNode*)RwMallocAlign(n*sizeof(CAnimBlendNode), 64); + for(i = 0; i < n; i++) + nodes[i].Init(); +} + +void +CAnimBlendAssociation::FreeAnimBlendNodeArray(void) +{ + RwFreeAlign(nodes); +} + +void +CAnimBlendAssociation::Init(RpClump *clump, CAnimBlendHierarchy *hier) +{ + int i; + AnimBlendFrameData *frame; + + CAnimBlendClumpData *clumpData = *RPANIMBLENDCLUMPDATA(clump); + numNodes = clumpData->numFrames; + AllocateAnimBlendNodeArray(numNodes); + for(i = 0; i < numNodes; i++) + nodes[i].association = this; + hierarchy = hier; + + // Init every node from a sequence and a Clump frame + // NB: This is where the order of nodes is defined + for(i = 0; i < hier->numSequences; i++){ + CAnimBlendSequence *seq = &hier->sequences[i]; + frame = RpAnimBlendClumpFindFrame(clump, seq->name); + if(frame && seq->numFrames > 0) + nodes[frame - clumpData->frames].sequence = seq; + } +} + +void +CAnimBlendAssociation::Init(CAnimBlendAssociation &assoc) +{ + int i; + + hierarchy = assoc.hierarchy; + numNodes = assoc.numNodes; + flags = assoc.flags; + animId = assoc.animId; + AllocateAnimBlendNodeArray(numNodes); + for(i = 0; i < numNodes; i++){ + nodes[i] = assoc.nodes[i]; + nodes[i].association = this; + } +} + +void +CAnimBlendAssociation::SetBlend(float amount, float delta) +{ + blendAmount = amount; + blendDelta = delta; +} + +void +CAnimBlendAssociation::SetFinishCallback(void (*cb)(CAnimBlendAssociation*, void*), void *arg) +{ + callbackType = CB_FINISH; + callback = cb; + callbackArg = arg; +} + +void +CAnimBlendAssociation::SetDeleteCallback(void (*cb)(CAnimBlendAssociation*, void*), void *arg) +{ + callbackType = CB_DELETE; + callback = cb; + callbackArg = arg; +} + +void +CAnimBlendAssociation::SetCurrentTime(float time) +{ + int i; + + for(currentTime = time; currentTime >= hierarchy->totalLength; currentTime -= hierarchy->totalLength) + if(!IsRepeating()) + return; + CAnimManager::UncompressAnimation(hierarchy); + for(i = 0; i < numNodes; i++) + if(nodes[i].sequence) + nodes[i].FindKeyFrame(currentTime); +} + +void +CAnimBlendAssociation::SyncAnimation(CAnimBlendAssociation *other) +{ + SetCurrentTime(other->currentTime/other->hierarchy->totalLength * hierarchy->totalLength); +} + +void +CAnimBlendAssociation::Start(float time) +{ + flags |= ASSOC_RUNNING; + SetCurrentTime(time); +} + +void +CAnimBlendAssociation::UpdateTime(float timeDelta, float relSpeed) +{ + if(!IsRunning()) + return; + + timeStep = (flags & ASSOC_MOVEMENT ? relSpeed*hierarchy->totalLength : speed) * timeDelta; + currentTime += timeStep; + + if(currentTime >= hierarchy->totalLength){ + // Ran past end + + if(IsRepeating()) + currentTime -= hierarchy->totalLength; + else{ + currentTime = hierarchy->totalLength; + flags &= ~ASSOC_RUNNING; + if(flags & ASSOC_FADEOUTWHENDONE){ + flags |= ASSOC_DELETEFADEDOUT; + blendDelta = -4.0f; + } + if(callbackType == CB_FINISH){ + callbackType = CB_NONE; + callback(this, callbackArg); + } + } + } +} + +// return whether we still exist after this function +bool +CAnimBlendAssociation::UpdateBlend(float timeDelta) +{ + blendAmount += blendDelta * timeDelta; + + if(blendAmount <= 0.0f && blendDelta < 0.0f){ + // We're faded out and are not fading in + blendAmount = 0.0f; + blendDelta = max(0.0, blendDelta); + if(flags & ASSOC_DELETEFADEDOUT){ + if(callbackType == CB_FINISH || callbackType == CB_DELETE) + callback(this, callbackArg); + delete this; + return false; + } + } + + if(blendAmount > 1.0f){ + // Maximally faded in, clamp values + blendAmount = 1.0f; + blendDelta = min(0.0, blendDelta); + } + + return true; +} + + +STARTPATCHES + InjectHook(0x4016A0, &CAnimBlendAssociation::AllocateAnimBlendNodeArray, PATCH_JUMP); + InjectHook(0x4016F0, &CAnimBlendAssociation::FreeAnimBlendNodeArray, PATCH_JUMP); + InjectHook(0x4017B0, &CAnimBlendAssociation::GetNode, PATCH_JUMP); + InjectHook(0x401560, (void (CAnimBlendAssociation::*)(RpClump*, CAnimBlendHierarchy*))&CAnimBlendAssociation::Init, PATCH_JUMP); + InjectHook(0x401620, (void (CAnimBlendAssociation::*)(CAnimBlendAssociation&))&CAnimBlendAssociation::Init, PATCH_JUMP); + InjectHook(0x4017E0, &CAnimBlendAssociation::SetBlend, PATCH_JUMP); + InjectHook(0x401820, &CAnimBlendAssociation::SetFinishCallback, PATCH_JUMP); + InjectHook(0x401800, &CAnimBlendAssociation::SetDeleteCallback, PATCH_JUMP); + InjectHook(0x401700, &CAnimBlendAssociation::SetCurrentTime, PATCH_JUMP); + InjectHook(0x401780, &CAnimBlendAssociation::SyncAnimation, PATCH_JUMP); + InjectHook(0x4017D0, &CAnimBlendAssociation::Start, PATCH_JUMP); + InjectHook(0x4031F0, &CAnimBlendAssociation::UpdateTime, PATCH_JUMP); + InjectHook(0x4032B0, &CAnimBlendAssociation::UpdateBlend, PATCH_JUMP); + + InjectHook(0x401460, &CAnimBlendAssociation::ctor1, PATCH_JUMP); + InjectHook(0x4014C0, &CAnimBlendAssociation::ctor2, PATCH_JUMP); + InjectHook(0x401520, &CAnimBlendAssociation::dtor, PATCH_JUMP); +ENDPATCHES -- cgit v1.2.3