commit
0f402c97ea
@ -11,6 +11,7 @@ workspace "re3"
|
|||||||
files { "src/weapons/*.*" }
|
files { "src/weapons/*.*" }
|
||||||
files { "src/render/*.*" }
|
files { "src/render/*.*" }
|
||||||
files { "src/control/*.*" }
|
files { "src/control/*.*" }
|
||||||
|
files { "src/animation/*.*" }
|
||||||
files { "src/audio/*.*" }
|
files { "src/audio/*.*" }
|
||||||
|
|
||||||
includedirs { "src" }
|
includedirs { "src" }
|
||||||
@ -22,6 +23,7 @@ workspace "re3"
|
|||||||
includedirs { "src/render" }
|
includedirs { "src/render" }
|
||||||
includedirs { "src/control" }
|
includedirs { "src/control" }
|
||||||
includedirs { "src/audio" }
|
includedirs { "src/audio" }
|
||||||
|
includedirs { "src/animation" }
|
||||||
includedirs { "dxsdk/include" }
|
includedirs { "dxsdk/include" }
|
||||||
includedirs { "rwsdk/include/d3d8" }
|
includedirs { "rwsdk/include/d3d8" }
|
||||||
|
|
||||||
|
65
src/Directory.cpp
Normal file
65
src/Directory.cpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "FileMgr.h"
|
||||||
|
#include "Directory.h"
|
||||||
|
|
||||||
|
CDirectory::CDirectory(int32 maxEntries)
|
||||||
|
: numEntries(0), maxEntries(maxEntries)
|
||||||
|
{
|
||||||
|
entries = new DirectoryInfo[maxEntries];
|
||||||
|
}
|
||||||
|
|
||||||
|
CDirectory::~CDirectory(void)
|
||||||
|
{
|
||||||
|
delete[] entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CDirectory::ReadDirFile(const char *filename)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
DirectoryInfo dirinfo;
|
||||||
|
|
||||||
|
fd = CFileMgr::OpenFile(filename, "rb");
|
||||||
|
while(CFileMgr::Read(fd, (char*)&dirinfo, sizeof(dirinfo)))
|
||||||
|
AddItem(dirinfo);
|
||||||
|
return CFileMgr::CloseFile(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CDirectory::WriteDirFile(const char *filename)
|
||||||
|
{
|
||||||
|
int fd, n;
|
||||||
|
fd = CFileMgr::OpenFileForWriting(filename);
|
||||||
|
n = CFileMgr::Write(fd, (char*)entries, numEntries*sizeof(DirectoryInfo));
|
||||||
|
CFileMgr::CloseFile(fd);
|
||||||
|
return n == numEntries*sizeof(DirectoryInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CDirectory::AddItem(const DirectoryInfo &dirinfo)
|
||||||
|
{
|
||||||
|
assert(numEntries < maxEntries);
|
||||||
|
entries[numEntries++] = dirinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CDirectory::FindItem(const char *name, uint32 &offset, uint32 &size)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < numEntries; i++)
|
||||||
|
if(strcmpi(entries[i].name, name) == 0){
|
||||||
|
offset = entries[i].offset;
|
||||||
|
size = entries[i].size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x473630, &CDirectory::ReadDirFile, PATCH_JUMP);
|
||||||
|
InjectHook(0x473690, &CDirectory::WriteDirFile, PATCH_JUMP);
|
||||||
|
InjectHook(0x473600, &CDirectory::AddItem, PATCH_JUMP);
|
||||||
|
InjectHook(0x4736E0, &CDirectory::FindItem, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
22
src/Directory.h
Normal file
22
src/Directory.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class CDirectory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct DirectoryInfo {
|
||||||
|
uint32 offset;
|
||||||
|
uint32 size;
|
||||||
|
char name[24];
|
||||||
|
};
|
||||||
|
DirectoryInfo *entries;
|
||||||
|
int32 maxEntries;
|
||||||
|
int32 numEntries;
|
||||||
|
|
||||||
|
CDirectory(int32 maxEntries);
|
||||||
|
~CDirectory(void);
|
||||||
|
|
||||||
|
void ReadDirFile(const char *filename);
|
||||||
|
bool WriteDirFile(const char *filename);
|
||||||
|
void AddItem(const DirectoryInfo &dirinfo);
|
||||||
|
bool FindItem(const char *name, uint32 &offset, uint32 &size);
|
||||||
|
};
|
161
src/animation/AnimBlendAssocGroup.cpp
Normal file
161
src/animation/AnimBlendAssocGroup.cpp
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "ModelInfo.h"
|
||||||
|
#include "AnimManager.h"
|
||||||
|
#include "RpAnimBlend.h"
|
||||||
|
#include "AnimBlendAssociation.h"
|
||||||
|
#include "AnimBlendAssocGroup.h"
|
||||||
|
|
||||||
|
CAnimBlendAssocGroup::CAnimBlendAssocGroup(void)
|
||||||
|
{
|
||||||
|
assocList = nil;
|
||||||
|
numAssociations = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlendAssocGroup::~CAnimBlendAssocGroup(void)
|
||||||
|
{
|
||||||
|
DestroyAssociations();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CAnimBlendAssocGroup::DestroyAssociations(void)
|
||||||
|
{
|
||||||
|
if(assocList){
|
||||||
|
delete[] assocList;
|
||||||
|
assocList = nil;
|
||||||
|
numAssociations = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlendAssociation*
|
||||||
|
CAnimBlendAssocGroup::GetAnimation(uint32 id)
|
||||||
|
{
|
||||||
|
return &assocList[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlendAssociation*
|
||||||
|
CAnimBlendAssocGroup::GetAnimation(const char *name)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < numAssociations; i++)
|
||||||
|
if(strcmpi(assocList[i].hierarchy->name, name) == 0)
|
||||||
|
return &assocList[i];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CAnimBlendAssociation*
|
||||||
|
CAnimBlendAssocGroup::CopyAnimation(uint32 id)
|
||||||
|
{
|
||||||
|
CAnimBlendAssociation *anim = GetAnimation(id);
|
||||||
|
if(anim == nil)
|
||||||
|
return nil;
|
||||||
|
CAnimManager::UncompressAnimation(anim->hierarchy);
|
||||||
|
return new CAnimBlendAssociation(*anim);
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlendAssociation*
|
||||||
|
CAnimBlendAssocGroup::CopyAnimation(const char *name)
|
||||||
|
{
|
||||||
|
CAnimBlendAssociation *anim = GetAnimation(name);
|
||||||
|
if(anim == nil)
|
||||||
|
return nil;
|
||||||
|
CAnimManager::UncompressAnimation(anim->hierarchy);
|
||||||
|
return new CAnimBlendAssociation(*anim);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
strcmpIgnoringDigits(const char *s1, const char *s2)
|
||||||
|
{
|
||||||
|
char c1, c2;
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
c1 = *s1;
|
||||||
|
c2 = *s2;
|
||||||
|
if(c1) s1++;
|
||||||
|
if(c2) s2++;
|
||||||
|
if(c1 == '\0' && c2 == '\0')
|
||||||
|
return 1;
|
||||||
|
if(islower(c1)) c1 = toupper(c1);
|
||||||
|
if(islower(c2)) c2 = toupper(c2);
|
||||||
|
if(isdigit(c1) && isdigit(c2))
|
||||||
|
continue;
|
||||||
|
if(c1 != c2)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CBaseModelInfo*
|
||||||
|
GetModelFromName(const char *name)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
CBaseModelInfo *mi;
|
||||||
|
|
||||||
|
for(i = 0; i < MODELINFOSIZE; i++){
|
||||||
|
mi = CModelInfo::GetModelInfo(i);
|
||||||
|
if(mi->GetRwObject() && RwObjectGetType(mi->GetRwObject()) == rpCLUMP &&
|
||||||
|
strcmpIgnoringDigits(mi->GetName(), name))
|
||||||
|
return mi;
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CAnimBlendAssocGroup::CreateAssociations(const char *name)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
CAnimBlock *animBlock;
|
||||||
|
|
||||||
|
if(assocList)
|
||||||
|
DestroyAssociations();
|
||||||
|
|
||||||
|
animBlock = CAnimManager::GetAnimationBlock(name);
|
||||||
|
assocList = new CAnimBlendAssociation[animBlock->numAnims];
|
||||||
|
numAssociations = 0;
|
||||||
|
|
||||||
|
for(i = 0; i < animBlock->numAnims; i++){
|
||||||
|
CAnimBlendHierarchy *anim = CAnimManager::GetAnimation(animBlock->firstIndex + i);
|
||||||
|
CBaseModelInfo *model = GetModelFromName(anim->name);
|
||||||
|
printf("Associated anim %s with model %s\n", anim->name, model->GetName());
|
||||||
|
if(model){
|
||||||
|
RpClump *clump = (RpClump*)model->CreateInstance();
|
||||||
|
RpAnimBlendClumpInit(clump);
|
||||||
|
assocList[i].Init(clump, anim);
|
||||||
|
RpClumpDestroy(clump);
|
||||||
|
assocList[i].animId = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
numAssociations = animBlock->numAnims;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create associations from hierarchies for a given clump
|
||||||
|
void
|
||||||
|
CAnimBlendAssocGroup::CreateAssociations(const char *blockName, RpClump *clump, char **animNames, int numAssocs)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
CAnimBlock *animBlock;
|
||||||
|
|
||||||
|
if(assocList)
|
||||||
|
DestroyAssociations();
|
||||||
|
|
||||||
|
animBlock = CAnimManager::GetAnimationBlock(blockName);
|
||||||
|
assocList = new CAnimBlendAssociation[animBlock->numAnims];
|
||||||
|
|
||||||
|
numAssociations = 0;
|
||||||
|
for(i = 0; i < numAssocs; i++){
|
||||||
|
assocList[i].Init(clump, CAnimManager::GetAnimation(animNames[i], animBlock));
|
||||||
|
assocList[i].animId = i;
|
||||||
|
}
|
||||||
|
numAssociations = numAssocs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x4013D0, (CAnimBlendAssociation *(CAnimBlendAssocGroup::*)(uint32))&CAnimBlendAssocGroup::GetAnimation, PATCH_JUMP);
|
||||||
|
InjectHook(0x401300, (CAnimBlendAssociation *(CAnimBlendAssocGroup::*)(const char*))&CAnimBlendAssocGroup::GetAnimation, PATCH_JUMP);
|
||||||
|
InjectHook(0x401420, (CAnimBlendAssociation *(CAnimBlendAssocGroup::*)(uint32))&CAnimBlendAssocGroup::CopyAnimation, PATCH_JUMP);
|
||||||
|
InjectHook(0x4013E0, (CAnimBlendAssociation *(CAnimBlendAssocGroup::*)(const char*))&CAnimBlendAssocGroup::CopyAnimation, PATCH_JUMP);
|
||||||
|
InjectHook(0x401130, (void (CAnimBlendAssocGroup::*)(const char*))&CAnimBlendAssocGroup::CreateAssociations, PATCH_JUMP);
|
||||||
|
InjectHook(0x401220, (void (CAnimBlendAssocGroup::*)(const char*, RpClump*, char**, int))&CAnimBlendAssocGroup::CreateAssociations, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
20
src/animation/AnimBlendAssocGroup.h
Normal file
20
src/animation/AnimBlendAssocGroup.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class CAnimBlendAssociation;
|
||||||
|
|
||||||
|
class CAnimBlendAssocGroup
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CAnimBlendAssociation *assocList;
|
||||||
|
int32 numAssociations;
|
||||||
|
|
||||||
|
CAnimBlendAssocGroup(void);
|
||||||
|
~CAnimBlendAssocGroup(void);
|
||||||
|
void DestroyAssociations(void);
|
||||||
|
CAnimBlendAssociation *GetAnimation(uint32 id);
|
||||||
|
CAnimBlendAssociation *GetAnimation(const char *name);
|
||||||
|
CAnimBlendAssociation *CopyAnimation(uint32 id);
|
||||||
|
CAnimBlendAssociation *CopyAnimation(const char *name);
|
||||||
|
void CreateAssociations(const char *name);
|
||||||
|
void CreateAssociations(const char *blockName, RpClump *clump, char **animNames, int numAssocs);
|
||||||
|
};
|
227
src/animation/AnimBlendAssociation.cpp
Normal file
227
src/animation/AnimBlendAssociation.cpp
Normal file
@ -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
|
89
src/animation/AnimBlendAssociation.h
Normal file
89
src/animation/AnimBlendAssociation.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AnimBlendList.h"
|
||||||
|
#include "AnimBlendNode.h"
|
||||||
|
|
||||||
|
class CAnimBlendHierarchy;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
// TODO
|
||||||
|
ASSOC_RUNNING = 1,
|
||||||
|
ASSOC_REPEAT = 2,
|
||||||
|
ASSOC_DELETEFADEDOUT = 4,
|
||||||
|
ASSOC_FADEOUTWHENDONE = 8,
|
||||||
|
ASSOC_PARTIAL = 0x10,
|
||||||
|
ASSOC_MOVEMENT = 0x20, // ???
|
||||||
|
ASSOC_HAS_TRANSLATION = 0x40,
|
||||||
|
ASSOC_FLAG80 = 0x80,
|
||||||
|
ASSOC_FLAG100 = 0x100,
|
||||||
|
ASSOC_FLAG200 = 0x200,
|
||||||
|
ASSOC_FLAG400 = 0x400, // not seen yet
|
||||||
|
ASSOC_FLAG800 = 0x800,
|
||||||
|
ASSOC_HAS_X_TRANSLATION = 0x1000,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Anim hierarchy associated with a clump
|
||||||
|
// Holds the interpolated state of all nodes.
|
||||||
|
// Also used as template for other clumps.
|
||||||
|
class CAnimBlendAssociation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum {
|
||||||
|
// callbackType
|
||||||
|
CB_NONE,
|
||||||
|
CB_FINISH,
|
||||||
|
CB_DELETE
|
||||||
|
};
|
||||||
|
|
||||||
|
CAnimBlendLink link;
|
||||||
|
|
||||||
|
int numNodes; // taken from CAnimBlendClumpData::numFrames
|
||||||
|
// NB: Order of these depends on order of nodes in Clump this was built from
|
||||||
|
CAnimBlendNode *nodes;
|
||||||
|
CAnimBlendHierarchy *hierarchy;
|
||||||
|
float blendAmount;
|
||||||
|
float blendDelta; // how much blendAmount changes over time
|
||||||
|
float currentTime;
|
||||||
|
float speed;
|
||||||
|
float timeStep;
|
||||||
|
int32 animId;
|
||||||
|
int32 flags;
|
||||||
|
int32 callbackType;
|
||||||
|
void (*callback)(CAnimBlendAssociation*, void*);
|
||||||
|
void *callbackArg;
|
||||||
|
|
||||||
|
bool IsRunning(void) { return !!(flags & ASSOC_RUNNING); }
|
||||||
|
bool IsRepeating(void) { return !!(flags & ASSOC_REPEAT); }
|
||||||
|
bool IsPartial(void) { return !!(flags & ASSOC_PARTIAL); }
|
||||||
|
bool IsMovement(void) { return !!(flags & ASSOC_MOVEMENT); }
|
||||||
|
bool HasTranslation(void) { return !!(flags & ASSOC_HAS_TRANSLATION); }
|
||||||
|
bool HasXTranslation(void) { return !!(flags & ASSOC_HAS_X_TRANSLATION); }
|
||||||
|
|
||||||
|
float GetBlendAmount(float weight) { return IsPartial() ? blendAmount : blendAmount*weight; }
|
||||||
|
CAnimBlendNode *GetNode(int i) { return &nodes[i]; }
|
||||||
|
|
||||||
|
CAnimBlendAssociation(void);
|
||||||
|
CAnimBlendAssociation(CAnimBlendAssociation &other);
|
||||||
|
virtual ~CAnimBlendAssociation(void);
|
||||||
|
void AllocateAnimBlendNodeArray(int n);
|
||||||
|
void FreeAnimBlendNodeArray(void);
|
||||||
|
void Init(RpClump *clump, CAnimBlendHierarchy *hier);
|
||||||
|
void Init(CAnimBlendAssociation &assoc);
|
||||||
|
void SetBlend(float amount, float delta);
|
||||||
|
void SetFinishCallback(void (*callback)(CAnimBlendAssociation*, void*), void *arg);
|
||||||
|
void SetDeleteCallback(void (*callback)(CAnimBlendAssociation*, void*), void *arg);
|
||||||
|
void SetCurrentTime(float time);
|
||||||
|
void SyncAnimation(CAnimBlendAssociation *other);
|
||||||
|
void Start(float time);
|
||||||
|
void UpdateTime(float timeDelta, float relSpeed);
|
||||||
|
bool UpdateBlend(float timeDelta);
|
||||||
|
|
||||||
|
static CAnimBlendAssociation *FromLink(CAnimBlendLink *l) {
|
||||||
|
return (CAnimBlendAssociation*)((uint8*)l - offsetof(CAnimBlendAssociation, link));
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlendAssociation *ctor1(void) { return ::new (this) CAnimBlendAssociation(); }
|
||||||
|
CAnimBlendAssociation *ctor2(CAnimBlendAssociation &other) { return ::new (this) CAnimBlendAssociation(other); }
|
||||||
|
void dtor(void) { this->CAnimBlendAssociation::~CAnimBlendAssociation(); }
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CAnimBlendAssociation) == 0x40, "CAnimBlendAssociation: error");
|
46
src/animation/AnimBlendClumpData.cpp
Normal file
46
src/animation/AnimBlendClumpData.cpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "AnimBlendClumpData.h"
|
||||||
|
|
||||||
|
// TODO: implement those
|
||||||
|
#define RwFreeAlign RwFree
|
||||||
|
#define RwMallocAlign(sz, algn) RwMalloc(sz)
|
||||||
|
|
||||||
|
CAnimBlendClumpData::CAnimBlendClumpData(void)
|
||||||
|
{
|
||||||
|
numFrames = 0;
|
||||||
|
pedPosition = nil;
|
||||||
|
frames = nil;
|
||||||
|
link.Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlendClumpData::~CAnimBlendClumpData(void)
|
||||||
|
{
|
||||||
|
link.Remove();
|
||||||
|
if(frames)
|
||||||
|
RwFreeAlign(frames);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CAnimBlendClumpData::SetNumberOfFrames(int n)
|
||||||
|
{
|
||||||
|
if(frames)
|
||||||
|
RwFreeAlign(frames);
|
||||||
|
numFrames = n;
|
||||||
|
frames = (AnimBlendFrameData*)RwMallocAlign(numFrames * sizeof(AnimBlendFrameData), 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CAnimBlendClumpData::ForAllFrames(void (*cb)(AnimBlendFrameData*, void*), void *arg)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < numFrames; i++)
|
||||||
|
cb(&frames[i], arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x401880, &CAnimBlendClumpData::ctor, PATCH_JUMP);
|
||||||
|
InjectHook(0x4018B0, &CAnimBlendClumpData::dtor, PATCH_JUMP);
|
||||||
|
InjectHook(0x4018F0, &CAnimBlendClumpData::SetNumberOfFrames, PATCH_JUMP);
|
||||||
|
InjectHook(0x401930, &CAnimBlendClumpData::ForAllFrames, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
57
src/animation/AnimBlendClumpData.h
Normal file
57
src/animation/AnimBlendClumpData.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AnimBlendList.h"
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: put somewhere else
|
||||||
|
struct AnimBlendFrameData
|
||||||
|
{
|
||||||
|
enum {
|
||||||
|
IGNORE_ROTATION = 2,
|
||||||
|
IGNORE_TRANSLATION = 4,
|
||||||
|
VELOCITY_EXTRACTION = 8,
|
||||||
|
VELOCITY_EXTRACTION_3D = 0x10,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8 flag;
|
||||||
|
RwV3d resetPos;
|
||||||
|
#ifdef PED_SKIN
|
||||||
|
union {
|
||||||
|
RwFrame *frame;
|
||||||
|
RpHAnimStdKeyFrame *hanimframe;
|
||||||
|
};
|
||||||
|
int32 nodeID;
|
||||||
|
#else
|
||||||
|
RwFrame *frame;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
#ifndef PED_SKIN
|
||||||
|
static_assert(sizeof(AnimBlendFrameData) == 0x14, "AnimBlendFrameData: error");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
class CAnimBlendClumpData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CAnimBlendLink link;
|
||||||
|
int32 numFrames;
|
||||||
|
#ifdef PED_SKIN
|
||||||
|
int32 modelNumber; // doesn't seem to be used
|
||||||
|
#endif
|
||||||
|
CVector *pedPosition;
|
||||||
|
// order of frames is determined by RW hierarchy
|
||||||
|
AnimBlendFrameData *frames;
|
||||||
|
|
||||||
|
CAnimBlendClumpData(void);
|
||||||
|
~CAnimBlendClumpData(void);
|
||||||
|
void SetNumberOfFrames(int n);
|
||||||
|
#ifdef PED_SKIN
|
||||||
|
void SetNumberOfBones(int n) { SetNumberOfFrames(n); }
|
||||||
|
#endif
|
||||||
|
void ForAllFrames(void (*cb)(AnimBlendFrameData*, void*), void *arg);
|
||||||
|
|
||||||
|
|
||||||
|
CAnimBlendClumpData *ctor(void) { return ::new (this) CAnimBlendClumpData(); }
|
||||||
|
void dtor(void) { this->CAnimBlendClumpData::~CAnimBlendClumpData(); }
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CAnimBlendClumpData) == 0x14, "CAnimBlendClumpData: error");
|
84
src/animation/AnimBlendHierarchy.cpp
Normal file
84
src/animation/AnimBlendHierarchy.cpp
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "AnimBlendSequence.h"
|
||||||
|
#include "AnimBlendHierarchy.h"
|
||||||
|
|
||||||
|
CAnimBlendHierarchy::CAnimBlendHierarchy(void)
|
||||||
|
{
|
||||||
|
sequences = nil;
|
||||||
|
numSequences = 0;
|
||||||
|
compressed = 0;
|
||||||
|
totalLength = 0.0f;
|
||||||
|
linkPtr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CAnimBlendHierarchy::Shutdown(void)
|
||||||
|
{
|
||||||
|
RemoveAnimSequences();
|
||||||
|
compressed = 0;
|
||||||
|
linkPtr = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CAnimBlendHierarchy::SetName(char *name)
|
||||||
|
{
|
||||||
|
strncpy(this->name, name, 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CAnimBlendHierarchy::CalcTotalTime(void)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
float totalTime = 0.0f;
|
||||||
|
|
||||||
|
for(i = 0; i < numSequences; i++){
|
||||||
|
float seqTime = 0.0f;
|
||||||
|
for(j = 0; j < sequences[i].numFrames; j++)
|
||||||
|
seqTime += sequences[i].GetKeyFrame(j)->deltaTime;
|
||||||
|
totalTime = max(totalTime, seqTime);
|
||||||
|
}
|
||||||
|
totalLength = totalTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CAnimBlendHierarchy::RemoveQuaternionFlips(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < numSequences; i++)
|
||||||
|
sequences[i].RemoveQuaternionFlips();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CAnimBlendHierarchy::RemoveAnimSequences(void)
|
||||||
|
{
|
||||||
|
if(sequences)
|
||||||
|
delete[] sequences;
|
||||||
|
numSequences = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CAnimBlendHierarchy::Uncompress(void)
|
||||||
|
{
|
||||||
|
if(totalLength == 0.0f)
|
||||||
|
CalcTotalTime();
|
||||||
|
compressed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CAnimBlendHierarchy::RemoveUncompressedData(void)
|
||||||
|
{
|
||||||
|
// useless
|
||||||
|
compressed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x4019A0, &CAnimBlendHierarchy::Shutdown, PATCH_JUMP);
|
||||||
|
InjectHook(0x4019C0, &CAnimBlendHierarchy::SetName, PATCH_JUMP);
|
||||||
|
InjectHook(0x4019E0, &CAnimBlendHierarchy::CalcTotalTime, PATCH_JUMP);
|
||||||
|
InjectHook(0x401A80, &CAnimBlendHierarchy::RemoveQuaternionFlips, PATCH_JUMP);
|
||||||
|
InjectHook(0x401AB0, &CAnimBlendHierarchy::RemoveAnimSequences, PATCH_JUMP);
|
||||||
|
InjectHook(0x401AD0, &CAnimBlendHierarchy::Uncompress, PATCH_JUMP);
|
||||||
|
InjectHook(0x401B00, &CAnimBlendHierarchy::RemoveUncompressedData, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
27
src/animation/AnimBlendHierarchy.h
Normal file
27
src/animation/AnimBlendHierarchy.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "templates.h"
|
||||||
|
|
||||||
|
class CAnimBlendSequence;
|
||||||
|
|
||||||
|
// A collection of sequences
|
||||||
|
class CAnimBlendHierarchy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
char name[24];
|
||||||
|
CAnimBlendSequence *sequences;
|
||||||
|
int16 numSequences;
|
||||||
|
int16 compressed; // not really used
|
||||||
|
float totalLength;
|
||||||
|
CLink<CAnimBlendHierarchy*> *linkPtr;
|
||||||
|
|
||||||
|
CAnimBlendHierarchy(void);
|
||||||
|
void Shutdown(void);
|
||||||
|
void SetName(char *name);
|
||||||
|
void CalcTotalTime(void);
|
||||||
|
void RemoveQuaternionFlips(void);
|
||||||
|
void RemoveAnimSequences(void);
|
||||||
|
void Uncompress(void);
|
||||||
|
void RemoveUncompressedData(void);
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CAnimBlendHierarchy) == 0x28, "CAnimBlendHierarchy: error");
|
27
src/animation/AnimBlendList.h
Normal file
27
src/animation/AnimBlendList.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// name made up
|
||||||
|
class CAnimBlendLink
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CAnimBlendLink *next;
|
||||||
|
CAnimBlendLink *prev;
|
||||||
|
|
||||||
|
void Init(void){
|
||||||
|
next = nil;
|
||||||
|
prev = nil;
|
||||||
|
}
|
||||||
|
void Prepend(CAnimBlendLink *link){
|
||||||
|
if(next)
|
||||||
|
next->prev = link;
|
||||||
|
link->next = next;
|
||||||
|
link->prev = this;
|
||||||
|
next = link;
|
||||||
|
}
|
||||||
|
void Remove(void){
|
||||||
|
if(prev)
|
||||||
|
prev->next = next;
|
||||||
|
if(next)
|
||||||
|
next->prev = prev;
|
||||||
|
}
|
||||||
|
};
|
170
src/animation/AnimBlendNode.cpp
Normal file
170
src/animation/AnimBlendNode.cpp
Normal file
@ -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
|
29
src/animation/AnimBlendNode.h
Normal file
29
src/animation/AnimBlendNode.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AnimBlendSequence.h"
|
||||||
|
|
||||||
|
class CAnimBlendAssociation;
|
||||||
|
|
||||||
|
// The interpolated state between two key frames in a sequence
|
||||||
|
class CAnimBlendNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// for slerp
|
||||||
|
float theta; // angle between quaternions
|
||||||
|
float invSin; // 1/sin(theta)
|
||||||
|
// indices into array in sequence
|
||||||
|
int32 frameA; // next key frame
|
||||||
|
int32 frameB; // previous key frame
|
||||||
|
float remainingTime; // time until frames have to advance
|
||||||
|
CAnimBlendSequence *sequence;
|
||||||
|
CAnimBlendAssociation *association;
|
||||||
|
|
||||||
|
void Init(void);
|
||||||
|
bool Update(CVector &trans, CQuaternion &rot, float weight);
|
||||||
|
bool NextKeyFrame(void);
|
||||||
|
bool FindKeyFrame(float t);
|
||||||
|
void CalcDeltas(void);
|
||||||
|
void GetCurrentTranslation(CVector &trans, float weight);
|
||||||
|
void GetEndTranslation(CVector &trans, float weight);
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CAnimBlendNode) == 0x1C, "CAnimBlendNode: error");
|
68
src/animation/AnimBlendSequence.cpp
Normal file
68
src/animation/AnimBlendSequence.cpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "AnimBlendSequence.h"
|
||||||
|
|
||||||
|
CAnimBlendSequence::CAnimBlendSequence(void)
|
||||||
|
{
|
||||||
|
type = 0;
|
||||||
|
numFrames = 0;
|
||||||
|
keyFrames = nil;
|
||||||
|
keyFramesCompressed = nil;
|
||||||
|
#ifdef PED_SKIN
|
||||||
|
boneTag = -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlendSequence::~CAnimBlendSequence(void)
|
||||||
|
{
|
||||||
|
if(keyFrames)
|
||||||
|
RwFree(keyFrames);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CAnimBlendSequence::SetName(char *name)
|
||||||
|
{
|
||||||
|
strncpy(this->name, name, 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CAnimBlendSequence::SetNumFrames(int numFrames, bool translation)
|
||||||
|
{
|
||||||
|
int sz;
|
||||||
|
|
||||||
|
if(translation){
|
||||||
|
sz = sizeof(KeyFrameTrans);
|
||||||
|
type |= KF_ROT | KF_TRANS;
|
||||||
|
}else{
|
||||||
|
sz = sizeof(KeyFrame);
|
||||||
|
type |= KF_ROT;
|
||||||
|
}
|
||||||
|
keyFrames = RwMalloc(sz * numFrames);
|
||||||
|
this->numFrames = numFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CAnimBlendSequence::RemoveQuaternionFlips(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
CQuaternion last;
|
||||||
|
KeyFrame *frame;
|
||||||
|
|
||||||
|
if(numFrames < 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
frame = GetKeyFrame(0);
|
||||||
|
last = frame->rotation;
|
||||||
|
for(i = 1; i < numFrames; i++){
|
||||||
|
frame = GetKeyFrame(i);
|
||||||
|
if(DotProduct(last, frame->rotation) < 0.0f)
|
||||||
|
frame->rotation = -frame->rotation;
|
||||||
|
last = frame->rotation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x402330, &CAnimBlendSequence::SetName, PATCH_JUMP);
|
||||||
|
InjectHook(0x402350, &CAnimBlendSequence::SetNumFrames, PATCH_JUMP);
|
||||||
|
InjectHook(0x4023A0, &CAnimBlendSequence::RemoveQuaternionFlips, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
55
src/animation/AnimBlendSequence.h
Normal file
55
src/animation/AnimBlendSequence.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "math/Quaternion.h"
|
||||||
|
|
||||||
|
// TODO: put them somewhere else?
|
||||||
|
struct KeyFrame {
|
||||||
|
CQuaternion rotation;
|
||||||
|
float deltaTime; // relative to previous key frame
|
||||||
|
};
|
||||||
|
|
||||||
|
struct KeyFrameTrans : KeyFrame {
|
||||||
|
CVector translation;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// The sequence of key frames of one animated node
|
||||||
|
class CAnimBlendSequence
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum {
|
||||||
|
KF_ROT = 1,
|
||||||
|
KF_TRANS = 2
|
||||||
|
};
|
||||||
|
int32 type;
|
||||||
|
char name[24];
|
||||||
|
int32 numFrames;
|
||||||
|
#ifdef PED_SKIN
|
||||||
|
int16 boneTag;
|
||||||
|
#endif
|
||||||
|
void *keyFrames;
|
||||||
|
void *keyFramesCompressed;
|
||||||
|
|
||||||
|
CAnimBlendSequence(void);
|
||||||
|
virtual ~CAnimBlendSequence(void);
|
||||||
|
void SetName(char *name);
|
||||||
|
void SetNumFrames(int numFrames, bool translation);
|
||||||
|
void RemoveQuaternionFlips(void);
|
||||||
|
KeyFrame *GetKeyFrame(int n) {
|
||||||
|
return type & KF_TRANS ?
|
||||||
|
&((KeyFrameTrans*)keyFrames)[n] :
|
||||||
|
&((KeyFrame*)keyFrames)[n];
|
||||||
|
}
|
||||||
|
bool HasTranslation(void) { return !!(type & KF_TRANS); }
|
||||||
|
// TODO? these are unused
|
||||||
|
// void Uncompress(void);
|
||||||
|
// void CompressKeyframes(void);
|
||||||
|
// void RemoveUncompressedData(void);
|
||||||
|
|
||||||
|
#ifdef PED_SKIN
|
||||||
|
void SetBoneTag(int tag) { boneTag = tag; }
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
#ifndef PED_SKIN
|
||||||
|
static_assert(sizeof(CAnimBlendSequence) == 0x2C, "CAnimBlendSequence: error");
|
||||||
|
#endif
|
930
src/animation/AnimManager.cpp
Normal file
930
src/animation/AnimManager.cpp
Normal file
@ -0,0 +1,930 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "ModelInfo.h"
|
||||||
|
#include "ModelIndices.h"
|
||||||
|
#include "FileMgr.h"
|
||||||
|
#include "RpAnimBlend.h"
|
||||||
|
#include "AnimBlendClumpData.h"
|
||||||
|
#include "AnimBlendAssociation.h"
|
||||||
|
#include "AnimBlendAssocGroup.h"
|
||||||
|
#include "AnimManager.h"
|
||||||
|
|
||||||
|
CAnimBlock *CAnimManager::ms_aAnimBlocks = (CAnimBlock*)0x6F01A0;
|
||||||
|
CAnimBlendHierarchy *CAnimManager::ms_aAnimations = (CAnimBlendHierarchy*)0x70F430;
|
||||||
|
int32 &CAnimManager::ms_numAnimBlocks = *(int32*)0x885AF8;
|
||||||
|
int32 &CAnimManager::ms_numAnimations = *(int32*)0x8E2DD4;
|
||||||
|
CAnimBlendAssocGroup *&CAnimManager::ms_aAnimAssocGroups = *(CAnimBlendAssocGroup**)0x8F583C;
|
||||||
|
CLinkList<CAnimBlendHierarchy*> &CAnimManager::ms_animCache = *(CLinkList<CAnimBlendHierarchy*>*)0x9414DC;
|
||||||
|
|
||||||
|
AnimAssocDesc aStdAnimDescs[] = {
|
||||||
|
{ ANIM_WALK, ASSOC_REPEAT | ASSOC_MOVEMENT | ASSOC_HAS_TRANSLATION | ASSOC_FLAG80 },
|
||||||
|
{ ANIM_RUN, ASSOC_REPEAT | ASSOC_MOVEMENT | ASSOC_HAS_TRANSLATION | ASSOC_FLAG80 },
|
||||||
|
{ ANIM_SPRINT, ASSOC_REPEAT | ASSOC_MOVEMENT | ASSOC_HAS_TRANSLATION | ASSOC_FLAG80 },
|
||||||
|
{ ANIM_IDLE_STANCE, ASSOC_REPEAT },
|
||||||
|
{ ANIM_WALK_START, ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_RUN_STOP, ASSOC_DELETEFADEDOUT | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_RUN_STOP_R, ASSOC_DELETEFADEDOUT | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_IDLE_CAM, ASSOC_REPEAT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_IDLE_HBHB, ASSOC_REPEAT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_IDLE_TIRED, ASSOC_REPEAT },
|
||||||
|
{ ANIM_IDLE_ARMED, ASSOC_REPEAT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_IDLE_CHAT, ASSOC_REPEAT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_IDLE_TAXI, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_KO_SHOT_FRONT1, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION | ASSOC_FLAG800 },
|
||||||
|
{ ANIM_KO_SHOT_FRONT2, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION | ASSOC_FLAG800 },
|
||||||
|
{ ANIM_KO_SHOT_FRONT3, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION | ASSOC_FLAG800 },
|
||||||
|
{ ANIM_KO_SHOT_FRONT4, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION | ASSOC_FLAG800 },
|
||||||
|
{ ANIM_KO_SHOT_FACE, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION | ASSOC_FLAG800 },
|
||||||
|
{ ANIM_KO_SHOT_STOM, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_KO_SHOT_ARML, ASSOC_PARTIAL | ASSOC_FLAG800 },
|
||||||
|
{ ANIM_KO_SHOT_ARMR, ASSOC_PARTIAL | ASSOC_FLAG800 },
|
||||||
|
{ ANIM_KO_SHOT_LEGL, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_KO_SHOT_LEGR, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_KD_LEFT, ASSOC_PARTIAL | ASSOC_FLAG800 },
|
||||||
|
{ ANIM_KD_RIGHT, ASSOC_PARTIAL | ASSOC_FLAG800 },
|
||||||
|
{ ANIM_KO_SKID_FRONT, ASSOC_PARTIAL },
|
||||||
|
{ ANIM_KO_SPIN_R, ASSOC_PARTIAL },
|
||||||
|
{ ANIM_KO_SKID_BACK, ASSOC_PARTIAL | ASSOC_FLAG800 },
|
||||||
|
{ ANIM_KO_SPIN_L, ASSOC_PARTIAL },
|
||||||
|
{ ANIM_SHOT_FRONT_PARTIAL, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_FLAG200 },
|
||||||
|
{ ANIM_SHOT_LEFT_PARTIAL, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_FLAG200 },
|
||||||
|
{ ANIM_SHOT_BACK_PARTIAL, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_FLAG200 },
|
||||||
|
{ ANIM_SHOT_RIGHT_PARTIAL, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_FLAG200 },
|
||||||
|
{ ANIM_HIT_FRONT, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_HIT_LEFT, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_HIT_BACK, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_HIT_RIGHT, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_FLOOR_HIT, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_HIT_BODYBLOW, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_HIT_CHEST, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_HIT_HEAD, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_HIT_WALK, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_HIT_WALL, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_FLOOR_HIT_F, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL | ASSOC_FLAG800 },
|
||||||
|
{ ANIM_HIT_BEHIND, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_PUNCH_R, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_KICK_FLOOR, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_WEAPON_BAT_H, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_WEAPON_BAT_V, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_WEAPON_HGUN_BODY, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_FLAG200 },
|
||||||
|
{ ANIM_WEAPON_AK_BODY, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_WEAPON_PUMP, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_WEAPON_SNIPER, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_WEAPON_THROW, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_WEAPON_THROWU, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_WEAPON_START_THROW, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_BOMBER, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_FLAG200 },
|
||||||
|
{ ANIM_HGUN_RELOAD, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_FLAG200 },
|
||||||
|
{ ANIM_AK_RELOAD, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_FLAG200 },
|
||||||
|
{ ANIM_FPS_PUNCH, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_FPS_BAT, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_FPS_UZI, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_FPS_PUMP, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_FPS_AK, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_FPS_M16, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_FPS_ROCKET, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_FIGHT_IDLE, ASSOC_REPEAT },
|
||||||
|
{ ANIM_FIGHT2_IDLE, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_FIGHT_SH_F, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_FIGHT_BODYBLOW, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_FIGHT_HEAD, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_FIGHT_KICK, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_FIGHT_KNEE, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_FIGHT_LHOOK, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_FIGHT_PUNCH, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_FIGHT_ROUNDHOUSE, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_FIGHT_LONGKICK, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_FIGHT_PPUNCH, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL | ASSOC_FLAG200 },
|
||||||
|
{ ANIM_CAR_JACKED_RHS, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_LJACKED_RHS, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_JACKED_LHS, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_LJACKED_LHS, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_QJACK, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_QJACKED, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_ALIGN_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_ALIGNHI_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_OPEN_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_DOORLOCKED_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_PULLOUT_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_PULLOUT_LOW_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_GETIN_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_GETIN_LOW_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_CLOSEDOOR_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_CLOSEDOOR_LOW_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_ROLLDOOR, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_ROLLDOOR_LOW, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_GETOUT_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_GETOUT_LOW_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_CLOSE_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_ALIGN_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_ALIGNHI_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_OPEN_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_DOORLOCKED_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_PULLOUT_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_PULLOUT_LOW_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_GETIN_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_GETIN_LOW_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_CLOSEDOOR_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_CLOSEDOOR_LOW_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_SHUFFLE_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_LSHUFFLE_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_SIT, ASSOC_DELETEFADEDOUT },
|
||||||
|
{ ANIM_CAR_LSIT, ASSOC_DELETEFADEDOUT },
|
||||||
|
{ ANIM_CAR_SITP, ASSOC_DELETEFADEDOUT },
|
||||||
|
{ ANIM_CAR_SITPLO, ASSOC_DELETEFADEDOUT },
|
||||||
|
{ ANIM_DRIVE_L, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_DRIVE_R, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_DRIVE_LOW_L, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_DRIVE_LOW_R, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_DRIVEBY_L, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_DRIVEBY_R, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_LB, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_DRIVE_BOAT, ASSOC_DELETEFADEDOUT },
|
||||||
|
{ ANIM_CAR_GETOUT_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_GETOUT_LOW_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_CLOSE_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_HOOKERTALK, ASSOC_REPEAT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_COACH_OPEN_L, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_COACH_OPEN_R, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_COACH_IN_L, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_COACH_IN_R, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_COACH_OUT_L, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_TRAIN_GETIN, ASSOC_PARTIAL },
|
||||||
|
{ ANIM_TRAIN_GETOUT, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_CRAWLOUT_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CAR_CRAWLOUT_RHS2, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_VAN_OPEN_L, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_VAN_GETIN_L, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_VAN_CLOSE_L, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_VAN_GETOUT_L, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_VAN_OPEN, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_VAN_GETIN, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_VAN_CLOSE, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_VAN_GETOUT, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_GETUP1, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_GETUP2, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_GETUP3, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_GETUP_FRONT, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_JUMP_LAUNCH, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_JUMP_GLIDE, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_JUMP_LAND, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_FALL_FALL, ASSOC_REPEAT | ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_FALL_GLIDE, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_FALL_LAND, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_FALL_COLLAPSE, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_EV_STEP, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_EV_DIVE, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION | ASSOC_FLAG800 },
|
||||||
|
{ ANIM_XPRESS_SCRATCH, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_FLAG100 },
|
||||||
|
{ ANIM_ROAD_CROSS, ASSOC_REPEAT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_TURN_180, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_ARREST_GUN, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_DROWN, ASSOC_PARTIAL },
|
||||||
|
{ ANIM_CPR, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_DUCK_DOWN, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_DUCK_LOW, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_RBLOCK_CSHOOT, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_WEAPON_THROWU, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_HANDSUP, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_HANDSCOWER, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||||
|
{ ANIM_FUCKU, ASSOC_DELETEFADEDOUT | ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_FLAG200 },
|
||||||
|
{ ANIM_PHONE_IN, ASSOC_PARTIAL },
|
||||||
|
{ ANIM_PHONE_OUT, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||||
|
{ ANIM_PHONE_TALK, ASSOC_REPEAT | ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||||
|
};
|
||||||
|
AnimAssocDesc aStdAnimDescsSide[] = {
|
||||||
|
{ ANIM_WALK, ASSOC_REPEAT | ASSOC_MOVEMENT | ASSOC_HAS_TRANSLATION | ASSOC_FLAG80 | ASSOC_HAS_X_TRANSLATION },
|
||||||
|
{ ANIM_RUN, ASSOC_REPEAT | ASSOC_MOVEMENT | ASSOC_HAS_TRANSLATION | ASSOC_FLAG80 | ASSOC_HAS_X_TRANSLATION },
|
||||||
|
{ ANIM_SPRINT, ASSOC_REPEAT | ASSOC_MOVEMENT | ASSOC_HAS_TRANSLATION | ASSOC_FLAG80 | ASSOC_HAS_X_TRANSLATION },
|
||||||
|
{ ANIM_IDLE_STANCE, ASSOC_REPEAT },
|
||||||
|
{ ANIM_WALK_START, ASSOC_HAS_TRANSLATION | ASSOC_HAS_X_TRANSLATION },
|
||||||
|
};
|
||||||
|
char *aStdAnimations[] = {
|
||||||
|
"walk_civi",
|
||||||
|
"run_civi",
|
||||||
|
"sprint_panic",
|
||||||
|
"idle_stance",
|
||||||
|
"walk_start",
|
||||||
|
"run_stop",
|
||||||
|
"run_stopR",
|
||||||
|
"idle_cam",
|
||||||
|
"idle_hbhb",
|
||||||
|
"idle_tired",
|
||||||
|
"idle_armed",
|
||||||
|
"idle_chat",
|
||||||
|
"idle_taxi",
|
||||||
|
"KO_shot_front",
|
||||||
|
"KO_shot_front",
|
||||||
|
"KO_shot_front",
|
||||||
|
"KO_shot_front",
|
||||||
|
"KO_shot_face",
|
||||||
|
"KO_shot_stom",
|
||||||
|
"KO_shot_arml",
|
||||||
|
"KO_shot_armR",
|
||||||
|
"KO_shot_legl",
|
||||||
|
"KO_shot_legR",
|
||||||
|
"KD_left",
|
||||||
|
"KD_right",
|
||||||
|
"KO_skid_front",
|
||||||
|
"KO_spin_R",
|
||||||
|
"KO_skid_back",
|
||||||
|
"KO_spin_L",
|
||||||
|
"SHOT_partial",
|
||||||
|
"SHOT_leftP",
|
||||||
|
"SHOT_partial",
|
||||||
|
"SHOT_rightP",
|
||||||
|
"HIT_front",
|
||||||
|
"HIT_L",
|
||||||
|
"HIT_back",
|
||||||
|
"HIT_R",
|
||||||
|
"FLOOR_hit",
|
||||||
|
"HIT_bodyblow",
|
||||||
|
"HIT_chest",
|
||||||
|
"HIT_head",
|
||||||
|
"HIT_walk",
|
||||||
|
"HIT_wall",
|
||||||
|
"FLOOR_hit_f",
|
||||||
|
"HIT_behind",
|
||||||
|
"punchR",
|
||||||
|
"KICK_floor",
|
||||||
|
"WEAPON_bat_h",
|
||||||
|
"WEAPON_bat_v",
|
||||||
|
"WEAPON_hgun_body",
|
||||||
|
"WEAPON_AK_body",
|
||||||
|
"WEAPON_pump",
|
||||||
|
"WEAPON_sniper",
|
||||||
|
"WEAPON_throw",
|
||||||
|
"WEAPON_throwu",
|
||||||
|
"WEAPON_start_throw",
|
||||||
|
"bomber",
|
||||||
|
"WEAPON_hgun_rload",
|
||||||
|
"WEAPON_AK_rload",
|
||||||
|
"FPS_PUNCH",
|
||||||
|
"FPS_BAT",
|
||||||
|
"FPS_UZI",
|
||||||
|
"FPS_PUMP",
|
||||||
|
"FPS_AK",
|
||||||
|
"FPS_M16",
|
||||||
|
"FPS_ROCKET",
|
||||||
|
"FIGHTIDLE",
|
||||||
|
"FIGHT2IDLE",
|
||||||
|
"FIGHTsh_F",
|
||||||
|
"FIGHTbodyblow",
|
||||||
|
"FIGHThead",
|
||||||
|
"FIGHTkick",
|
||||||
|
"FIGHTknee",
|
||||||
|
"FIGHTLhook",
|
||||||
|
"FIGHTpunch",
|
||||||
|
"FIGHTrndhse",
|
||||||
|
"FIGHTlngkck",
|
||||||
|
"FIGHTppunch",
|
||||||
|
"car_jackedRHS",
|
||||||
|
"car_LjackedRHS",
|
||||||
|
"car_jackedLHS",
|
||||||
|
"car_LjackedLHS",
|
||||||
|
"CAR_Qjack",
|
||||||
|
"CAR_Qjacked",
|
||||||
|
"CAR_align_LHS",
|
||||||
|
"CAR_alignHI_LHS",
|
||||||
|
"CAR_open_LHS",
|
||||||
|
"CAR_doorlocked_LHS",
|
||||||
|
"CAR_pullout_LHS",
|
||||||
|
"CAR_pulloutL_LHS",
|
||||||
|
"CAR_getin_LHS",
|
||||||
|
"CAR_getinL_LHS",
|
||||||
|
"CAR_closedoor_LHS",
|
||||||
|
"CAR_closedoorL_LHS",
|
||||||
|
"CAR_rolldoor",
|
||||||
|
"CAR_rolldoorLO",
|
||||||
|
"CAR_getout_LHS",
|
||||||
|
"CAR_getoutL_LHS",
|
||||||
|
"CAR_close_LHS",
|
||||||
|
"CAR_align_RHS",
|
||||||
|
"CAR_alignHI_RHS",
|
||||||
|
"CAR_open_RHS",
|
||||||
|
"CAR_doorlocked_RHS",
|
||||||
|
"CAR_pullout_RHS",
|
||||||
|
"CAR_pulloutL_RHS",
|
||||||
|
"CAR_getin_RHS",
|
||||||
|
"CAR_getinL_RHS",
|
||||||
|
"CAR_closedoor_RHS",
|
||||||
|
"CAR_closedoorL_RHS",
|
||||||
|
"CAR_shuffle_RHS",
|
||||||
|
"CAR_Lshuffle_RHS",
|
||||||
|
"CAR_sit",
|
||||||
|
"CAR_Lsit",
|
||||||
|
"CAR_sitp",
|
||||||
|
"CAR_sitpLO",
|
||||||
|
"DRIVE_L",
|
||||||
|
"Drive_R",
|
||||||
|
"Drive_LO_l",
|
||||||
|
"Drive_LO_R",
|
||||||
|
"Driveby_L",
|
||||||
|
"Driveby_R",
|
||||||
|
"CAR_LB",
|
||||||
|
"DRIVE_BOAT",
|
||||||
|
"CAR_getout_RHS",
|
||||||
|
"CAR_getoutL_RHS",
|
||||||
|
"CAR_close_RHS",
|
||||||
|
"car_hookertalk",
|
||||||
|
"COACH_opnL",
|
||||||
|
"COACH_opnR",
|
||||||
|
"COACH_inL",
|
||||||
|
"COACH_inR",
|
||||||
|
"COACH_outL",
|
||||||
|
"TRAIN_getin",
|
||||||
|
"TRAIN_getout",
|
||||||
|
"CAR_crawloutRHS",
|
||||||
|
"CAR_crawloutRHS",
|
||||||
|
"VAN_openL",
|
||||||
|
"VAN_getinL",
|
||||||
|
"VAN_closeL",
|
||||||
|
"VAN_getoutL",
|
||||||
|
"VAN_open",
|
||||||
|
"VAN_getin",
|
||||||
|
"VAN_close",
|
||||||
|
"VAN_getout",
|
||||||
|
"Getup",
|
||||||
|
"Getup",
|
||||||
|
"Getup",
|
||||||
|
"Getup_front",
|
||||||
|
"JUMP_launch",
|
||||||
|
"JUMP_glide",
|
||||||
|
"JUMP_land",
|
||||||
|
"FALL_fall",
|
||||||
|
"FALL_glide",
|
||||||
|
"FALL_land",
|
||||||
|
"FALL_collapse",
|
||||||
|
"EV_step",
|
||||||
|
"EV_dive",
|
||||||
|
"XPRESSscratch",
|
||||||
|
"roadcross",
|
||||||
|
"TURN_180",
|
||||||
|
"ARRESTgun",
|
||||||
|
"DROWN",
|
||||||
|
"CPR",
|
||||||
|
"DUCK_down",
|
||||||
|
"DUCK_low",
|
||||||
|
"RBLOCK_Cshoot",
|
||||||
|
"WEAPON_throwu",
|
||||||
|
"handsup",
|
||||||
|
"handsCOWER",
|
||||||
|
"FUCKU",
|
||||||
|
"PHONE_in",
|
||||||
|
"PHONE_out",
|
||||||
|
"PHONE_talk",
|
||||||
|
};
|
||||||
|
char *aPlayerAnimations[] = {
|
||||||
|
"walk_player",
|
||||||
|
"run_player",
|
||||||
|
"SPRINT_civi",
|
||||||
|
"IDLE_STANCE",
|
||||||
|
"walk_start",
|
||||||
|
};
|
||||||
|
char *aPlayerWithRocketAnimations[] = {
|
||||||
|
"walk_rocket",
|
||||||
|
"run_rocket",
|
||||||
|
"run_rocket",
|
||||||
|
"idle_rocket",
|
||||||
|
"walk_start_rocket",
|
||||||
|
};
|
||||||
|
char *aPlayer1ArmedAnimations[] = {
|
||||||
|
"walk_player",
|
||||||
|
"run_1armed",
|
||||||
|
"SPRINT_civi",
|
||||||
|
"IDLE_STANCE",
|
||||||
|
"walk_start",
|
||||||
|
};
|
||||||
|
char *aPlayer2ArmedAnimations[] = {
|
||||||
|
"walk_player",
|
||||||
|
"run_armed",
|
||||||
|
"run_armed",
|
||||||
|
"idle_stance",
|
||||||
|
"walk_start",
|
||||||
|
};
|
||||||
|
char *aPlayerBBBatAnimations[] = {
|
||||||
|
"walk_player",
|
||||||
|
"run_player",
|
||||||
|
"run_player",
|
||||||
|
"IDLE_STANCE",
|
||||||
|
"walk_start",
|
||||||
|
};
|
||||||
|
char *aShuffleAnimations[] = {
|
||||||
|
"WALK_shuffle",
|
||||||
|
"RUN_civi",
|
||||||
|
"SPRINT_civi",
|
||||||
|
"IDLE_STANCE",
|
||||||
|
};
|
||||||
|
char *aOldAnimations[] = {
|
||||||
|
"walk_old",
|
||||||
|
"run_civi",
|
||||||
|
"sprint_civi",
|
||||||
|
"idle_stance",
|
||||||
|
};
|
||||||
|
char *aGang1Animations[] = {
|
||||||
|
"walk_gang1",
|
||||||
|
"run_gang1",
|
||||||
|
"sprint_civi",
|
||||||
|
"idle_stance",
|
||||||
|
};
|
||||||
|
char *aGang2Animations[] = {
|
||||||
|
"walk_gang2",
|
||||||
|
"run_gang1",
|
||||||
|
"sprint_civi",
|
||||||
|
"idle_stance",
|
||||||
|
};
|
||||||
|
char *aFatAnimations[] = {
|
||||||
|
"walk_fat",
|
||||||
|
"run_civi",
|
||||||
|
"woman_runpanic",
|
||||||
|
"idle_stance",
|
||||||
|
};
|
||||||
|
char *aOldFatAnimations[] = {
|
||||||
|
"walk_fatold",
|
||||||
|
"run_fatold",
|
||||||
|
"woman_runpanic",
|
||||||
|
"idle_stance",
|
||||||
|
};
|
||||||
|
char *aStdWomanAnimations[] = {
|
||||||
|
"woman_walknorm",
|
||||||
|
"woman_run",
|
||||||
|
"woman_runpanic",
|
||||||
|
"woman_idlestance",
|
||||||
|
};
|
||||||
|
char *aWomanShopAnimations[] = {
|
||||||
|
"woman_walkshop",
|
||||||
|
"woman_run",
|
||||||
|
"woman_run",
|
||||||
|
"woman_idlestance",
|
||||||
|
};
|
||||||
|
char *aBusyWomanAnimations[] = {
|
||||||
|
"woman_walkbusy",
|
||||||
|
"woman_run",
|
||||||
|
"woman_runpanic",
|
||||||
|
"woman_idlestance",
|
||||||
|
};
|
||||||
|
char *aSexyWomanAnimations[] = {
|
||||||
|
"woman_walksexy",
|
||||||
|
"woman_run",
|
||||||
|
"woman_runpanic",
|
||||||
|
"woman_idlestance",
|
||||||
|
};
|
||||||
|
char *aOldWomanAnimations[] = {
|
||||||
|
"woman_walkold",
|
||||||
|
"woman_run",
|
||||||
|
"woman_runpanic",
|
||||||
|
"woman_idlestance",
|
||||||
|
};
|
||||||
|
char *aFatWomanAnimations[] = {
|
||||||
|
"walk_fat",
|
||||||
|
"woman_run",
|
||||||
|
"woman_runpanic",
|
||||||
|
"woman_idlestance",
|
||||||
|
};
|
||||||
|
char *aPanicChunkyAnimations[] = {
|
||||||
|
"run_fatold",
|
||||||
|
"woman_runpanic",
|
||||||
|
"woman_runpanic",
|
||||||
|
"idle_stance",
|
||||||
|
};
|
||||||
|
char *aPlayerStrafeBackAnimations[] = {
|
||||||
|
"walk_player_back",
|
||||||
|
"run_player_back",
|
||||||
|
"run_player_back",
|
||||||
|
"IDLE_STANCE",
|
||||||
|
"walk_start_back",
|
||||||
|
};
|
||||||
|
char *aPlayerStrafeLeftAnimations[] = {
|
||||||
|
"walk_player_left",
|
||||||
|
"run_left",
|
||||||
|
"run_left",
|
||||||
|
"IDLE_STANCE",
|
||||||
|
"walk_start_left",
|
||||||
|
};
|
||||||
|
char *aPlayerStrafeRightAnimations[] = {
|
||||||
|
"walk_player_right",
|
||||||
|
"run_right",
|
||||||
|
"run_right",
|
||||||
|
"IDLE_STANCE",
|
||||||
|
"walk_start_right",
|
||||||
|
};
|
||||||
|
char *aRocketStrafeBackAnimations[] = {
|
||||||
|
"walk_rocket_back",
|
||||||
|
"run_rocket_back",
|
||||||
|
"run_rocket_back",
|
||||||
|
"idle_rocket",
|
||||||
|
"walkst_rocket_back",
|
||||||
|
};
|
||||||
|
char *aRocketStrafeLeftAnimations[] = {
|
||||||
|
"walk_rocket_left",
|
||||||
|
"run_rocket_left",
|
||||||
|
"run_rocket_left",
|
||||||
|
"idle_rocket",
|
||||||
|
"walkst_rocket_left",
|
||||||
|
};
|
||||||
|
char *aRocketStrafeRightAnimations[] = {
|
||||||
|
"walk_rocket_right",
|
||||||
|
"run_rocket_right",
|
||||||
|
"run_rocket_right",
|
||||||
|
"idle_rocket",
|
||||||
|
"walkst_rocket_right",
|
||||||
|
};
|
||||||
|
AnimAssocDefinition CAnimManager::ms_aAnimAssocDefinitions[NUM_ANIM_ASSOC_GROUPS] = {
|
||||||
|
{ "man", "ped", MI_COP, 173, aStdAnimations, aStdAnimDescs },
|
||||||
|
{ "player", "ped", MI_COP, 5, aPlayerAnimations, aStdAnimDescs },
|
||||||
|
{ "playerrocket", "ped", MI_COP, 5, aPlayerWithRocketAnimations, aStdAnimDescs },
|
||||||
|
{ "player1armed", "ped", MI_COP, 5, aPlayer1ArmedAnimations, aStdAnimDescs },
|
||||||
|
{ "player2armed", "ped", MI_COP, 5, aPlayer2ArmedAnimations, aStdAnimDescs },
|
||||||
|
{ "playerBBBat", "ped", MI_COP, 5, aPlayerBBBatAnimations, aStdAnimDescs },
|
||||||
|
{ "shuffle", "ped", MI_COP, 4, aShuffleAnimations, aStdAnimDescs },
|
||||||
|
{ "oldman", "ped", MI_COP, 4, aOldAnimations, aStdAnimDescs },
|
||||||
|
{ "gang1", "ped", MI_COP, 4, aGang1Animations, aStdAnimDescs },
|
||||||
|
{ "gang2", "ped", MI_COP, 4, aGang2Animations, aStdAnimDescs },
|
||||||
|
{ "fatman", "ped", MI_COP, 4, aFatAnimations, aStdAnimDescs },
|
||||||
|
{ "oldfatman", "ped", MI_COP, 4, aOldFatAnimations, aStdAnimDescs },
|
||||||
|
{ "woman", "ped", MI_COP, 4, aStdWomanAnimations, aStdAnimDescs },
|
||||||
|
{ "shopping", "ped", MI_COP, 4, aWomanShopAnimations, aStdAnimDescs },
|
||||||
|
{ "busywoman", "ped", MI_COP, 4, aBusyWomanAnimations, aStdAnimDescs },
|
||||||
|
{ "sexywoman", "ped", MI_COP, 4, aSexyWomanAnimations, aStdAnimDescs },
|
||||||
|
{ "oldwoman", "ped", MI_COP, 4, aOldWomanAnimations, aStdAnimDescs },
|
||||||
|
{ "fatwoman", "ped", MI_COP, 4, aFatWomanAnimations, aStdAnimDescs },
|
||||||
|
{ "panicchunky", "ped", MI_COP, 4, aPanicChunkyAnimations, aStdAnimDescs },
|
||||||
|
{ "playerback", "ped", MI_COP, 5, aPlayerStrafeBackAnimations, aStdAnimDescs },
|
||||||
|
{ "playerleft", "ped", MI_COP, 5, aPlayerStrafeLeftAnimations, aStdAnimDescsSide },
|
||||||
|
{ "playerright", "ped", MI_COP, 5, aPlayerStrafeRightAnimations, aStdAnimDescsSide },
|
||||||
|
{ "rocketback", "ped", MI_COP, 5, aRocketStrafeBackAnimations, aStdAnimDescs },
|
||||||
|
{ "rocketleft", "ped", MI_COP, 5, aRocketStrafeLeftAnimations, aStdAnimDescsSide },
|
||||||
|
{ "rocketright", "ped", MI_COP, 5, aRocketStrafeRightAnimations, aStdAnimDescsSide },
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
CAnimManager::Initialise(void)
|
||||||
|
{
|
||||||
|
ms_numAnimations = 0;
|
||||||
|
ms_numAnimBlocks = 0;
|
||||||
|
ms_animCache.Init(25);
|
||||||
|
|
||||||
|
// dumpanimdata();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CAnimManager::Shutdown(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ms_animCache.Shutdown();
|
||||||
|
|
||||||
|
for(i = 0; i < ms_numAnimations; i++)
|
||||||
|
ms_aAnimations[i].Shutdown();
|
||||||
|
|
||||||
|
delete[] ms_aAnimAssocGroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CAnimManager::UncompressAnimation(CAnimBlendHierarchy *hier)
|
||||||
|
{
|
||||||
|
if(!hier->compressed){
|
||||||
|
if(hier->linkPtr){
|
||||||
|
hier->linkPtr->Remove();
|
||||||
|
ms_animCache.head.Insert(hier->linkPtr);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
CLink<CAnimBlendHierarchy*> *link = ms_animCache.Insert(hier);
|
||||||
|
if(link == nil){
|
||||||
|
ms_animCache.tail.prev->item->RemoveUncompressedData();
|
||||||
|
ms_animCache.Remove(ms_animCache.tail.prev);
|
||||||
|
link = ms_animCache.Insert(hier);
|
||||||
|
}
|
||||||
|
hier->linkPtr = link;
|
||||||
|
hier->Uncompress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlock*
|
||||||
|
CAnimManager::GetAnimationBlock(const char *name)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < ms_numAnimBlocks; i++)
|
||||||
|
if(strcmpi(ms_aAnimBlocks[i].name, name) == 0)
|
||||||
|
return &ms_aAnimBlocks[i];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlendHierarchy*
|
||||||
|
CAnimManager::GetAnimation(const char *name, CAnimBlock *animBlock)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
CAnimBlendHierarchy *hier = &ms_aAnimations[animBlock->firstIndex];
|
||||||
|
|
||||||
|
for(i = 0; i < animBlock->numAnims; i++){
|
||||||
|
if(strcmpi(hier->name, name) == 0)
|
||||||
|
return hier;
|
||||||
|
hier++;
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
CAnimManager::GetAnimGroupName(AssocGroupId groupId)
|
||||||
|
{
|
||||||
|
return ms_aAnimAssocDefinitions[groupId].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlendAssociation*
|
||||||
|
CAnimManager::CreateAnimAssociation(AssocGroupId groupId, AnimationId animId)
|
||||||
|
{
|
||||||
|
return ms_aAnimAssocGroups[groupId].CopyAnimation(animId);
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlendAssociation*
|
||||||
|
CAnimManager::GetAnimAssociation(AssocGroupId groupId, AnimationId animId)
|
||||||
|
{
|
||||||
|
return ms_aAnimAssocGroups[groupId].GetAnimation(animId);
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlendAssociation*
|
||||||
|
CAnimManager::GetAnimAssociation(AssocGroupId groupId, const char *name)
|
||||||
|
{
|
||||||
|
return ms_aAnimAssocGroups[groupId].GetAnimation(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlendAssociation*
|
||||||
|
CAnimManager::AddAnimation(RpClump *clump, AssocGroupId groupId, AnimationId animId)
|
||||||
|
{
|
||||||
|
CAnimBlendAssociation *anim = CreateAnimAssociation(groupId, animId);
|
||||||
|
CAnimBlendClumpData *clumpData = *RPANIMBLENDCLUMPDATA(clump);
|
||||||
|
if(anim->IsMovement()){
|
||||||
|
CAnimBlendAssociation *syncanim = nil;
|
||||||
|
CAnimBlendLink *link;
|
||||||
|
for(link = clumpData->link.next; link; link = link->next){
|
||||||
|
syncanim = CAnimBlendAssociation::FromLink(link);
|
||||||
|
if(syncanim->IsMovement())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(link){
|
||||||
|
anim->SyncAnimation(syncanim);
|
||||||
|
anim->flags |= ASSOC_RUNNING;
|
||||||
|
}else
|
||||||
|
anim->Start(0.0f);
|
||||||
|
}else
|
||||||
|
anim->Start(0.0f);
|
||||||
|
|
||||||
|
clumpData->link.Prepend(&anim->link);
|
||||||
|
return anim;
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlendAssociation*
|
||||||
|
CAnimManager::AddAnimationAndSync(RpClump *clump, CAnimBlendAssociation *syncanim, AssocGroupId groupId, AnimationId animId)
|
||||||
|
{
|
||||||
|
CAnimBlendAssociation *anim = CreateAnimAssociation(groupId, animId);
|
||||||
|
CAnimBlendClumpData *clumpData = *RPANIMBLENDCLUMPDATA(clump);
|
||||||
|
if (anim->IsMovement() && syncanim){
|
||||||
|
anim->SyncAnimation(syncanim);
|
||||||
|
anim->flags |= ASSOC_RUNNING;
|
||||||
|
}else
|
||||||
|
anim->Start(0.0f);
|
||||||
|
|
||||||
|
clumpData->link.Prepend(&anim->link);
|
||||||
|
return anim;
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlendAssociation*
|
||||||
|
CAnimManager::BlendAnimation(RpClump *clump, AssocGroupId groupId, AnimationId animId, float delta)
|
||||||
|
{
|
||||||
|
int removePrevAnim = 0;
|
||||||
|
CAnimBlendClumpData *clumpData = *RPANIMBLENDCLUMPDATA(clump);
|
||||||
|
CAnimBlendAssociation *anim = GetAnimAssociation(groupId, animId);
|
||||||
|
bool isMovement = anim->IsMovement();
|
||||||
|
bool isPartial = anim->IsPartial();
|
||||||
|
CAnimBlendLink *link;
|
||||||
|
CAnimBlendAssociation *found = nil, *movementAnim = nil;
|
||||||
|
for(link = clumpData->link.next; link; link = link->next){
|
||||||
|
anim = CAnimBlendAssociation::FromLink(link);
|
||||||
|
if(isMovement && anim->IsMovement())
|
||||||
|
movementAnim = anim;
|
||||||
|
if(anim->animId == animId)
|
||||||
|
found = anim;
|
||||||
|
else{
|
||||||
|
if(isPartial == anim->IsPartial()){
|
||||||
|
if(anim->blendAmount > 0.0f){
|
||||||
|
float blendDelta = -delta*anim->blendAmount;
|
||||||
|
if(blendDelta < anim->blendDelta || !isPartial)
|
||||||
|
anim->blendDelta = blendDelta;
|
||||||
|
}else{
|
||||||
|
anim->blendDelta = -1.0f;
|
||||||
|
}
|
||||||
|
anim->flags |= ASSOC_DELETEFADEDOUT;
|
||||||
|
removePrevAnim = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(found){
|
||||||
|
found->blendDelta = (1.0f - found->blendAmount)*delta;
|
||||||
|
if(!found->IsRunning() && found->currentTime == found->hierarchy->totalLength)
|
||||||
|
found->Start(0.0f);
|
||||||
|
}else{
|
||||||
|
found = AddAnimationAndSync(clump, movementAnim, groupId, animId);
|
||||||
|
if(!removePrevAnim && !isPartial){
|
||||||
|
found->blendAmount = 1.0f;
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
found->blendAmount = 0.0f;
|
||||||
|
found->blendDelta = delta;
|
||||||
|
}
|
||||||
|
UncompressAnimation(found->hierarchy);
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CAnimManager::LoadAnimFiles(void)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
LoadAnimFile("ANIM\\PED.IFP");
|
||||||
|
|
||||||
|
// Create all assoc groups
|
||||||
|
ms_aAnimAssocGroups = new CAnimBlendAssocGroup[NUM_ANIM_ASSOC_GROUPS];
|
||||||
|
for(i = 0; i < NUM_ANIM_ASSOC_GROUPS; i++){
|
||||||
|
CBaseModelInfo *mi = CModelInfo::GetModelInfo(ms_aAnimAssocDefinitions[i].modelIndex);
|
||||||
|
RpClump *clump = (RpClump*)mi->CreateInstance();
|
||||||
|
RpAnimBlendClumpInit(clump);
|
||||||
|
CAnimBlendAssocGroup *group = &CAnimManager::ms_aAnimAssocGroups[i];
|
||||||
|
AnimAssocDefinition *def = &CAnimManager::ms_aAnimAssocDefinitions[i];
|
||||||
|
group->CreateAssociations(def->blockName, clump, def->animNames, def->numAnims);
|
||||||
|
for(j = 0; j < group->numAssociations; j++)
|
||||||
|
group->GetAnimation(def->animDescs[j].animId)->flags |= def->animDescs[j].flags;
|
||||||
|
RpClumpDestroy(clump);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CAnimManager::LoadAnimFile(const char *filename)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
fd = CFileMgr::OpenFile(filename, "rb");
|
||||||
|
assert(fd > 0);
|
||||||
|
LoadAnimFile(fd, true);
|
||||||
|
CFileMgr::CloseFile(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CAnimManager::LoadAnimFile(int fd, bool compress)
|
||||||
|
{
|
||||||
|
#define ROUNDSIZE(x) if((x) & 3) (x) += 4 - ((x)&3)
|
||||||
|
struct IfpHeader {
|
||||||
|
char ident[4];
|
||||||
|
uint32 size;
|
||||||
|
};
|
||||||
|
IfpHeader anpk, info, name, dgan, cpan, anim;
|
||||||
|
int numANPK;
|
||||||
|
char buf[256];
|
||||||
|
int i, j, k, l;
|
||||||
|
float *fbuf = (float*)buf;
|
||||||
|
|
||||||
|
CFileMgr::Read(fd, (char*)&anpk, sizeof(IfpHeader));
|
||||||
|
if(strncmp(anpk.ident, "ANLF", 4) == 0){
|
||||||
|
ROUNDSIZE(anpk.size);
|
||||||
|
CFileMgr::Read(fd, buf, anpk.size);
|
||||||
|
numANPK = *(int*)buf;
|
||||||
|
}else if(strncmp(anpk.ident, "ANPK", 4) == 0){
|
||||||
|
CFileMgr::Seek(fd, -8, 1);
|
||||||
|
numANPK = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < numANPK; i++){
|
||||||
|
// block name
|
||||||
|
CFileMgr::Read(fd, (char*)&anpk, sizeof(IfpHeader));
|
||||||
|
ROUNDSIZE(anpk.size);
|
||||||
|
CFileMgr::Read(fd, (char*)&info, sizeof(IfpHeader));
|
||||||
|
ROUNDSIZE(info.size);
|
||||||
|
CFileMgr::Read(fd, buf, info.size);
|
||||||
|
CAnimBlock *animBlock = &ms_aAnimBlocks[ms_numAnimBlocks++];
|
||||||
|
strncpy(animBlock->name, buf+4, 24);
|
||||||
|
animBlock->numAnims = *(int*)buf;
|
||||||
|
|
||||||
|
animBlock->firstIndex = ms_numAnimations;
|
||||||
|
|
||||||
|
for(j = 0; j < animBlock->numAnims; j++){
|
||||||
|
CAnimBlendHierarchy *hier = &ms_aAnimations[ms_numAnimations++];
|
||||||
|
|
||||||
|
// animation name
|
||||||
|
CFileMgr::Read(fd, (char*)&name, sizeof(IfpHeader));
|
||||||
|
ROUNDSIZE(name.size);
|
||||||
|
CFileMgr::Read(fd, buf, name.size);
|
||||||
|
hier->SetName(buf);
|
||||||
|
|
||||||
|
// DG info has number of nodes/sequences
|
||||||
|
CFileMgr::Read(fd, (char*)&dgan, sizeof(IfpHeader));
|
||||||
|
ROUNDSIZE(dgan.size);
|
||||||
|
CFileMgr::Read(fd, (char*)&info, sizeof(IfpHeader));
|
||||||
|
ROUNDSIZE(info.size);
|
||||||
|
CFileMgr::Read(fd, buf, info.size);
|
||||||
|
hier->numSequences = *(int*)buf;
|
||||||
|
hier->sequences = new CAnimBlendSequence[hier->numSequences];
|
||||||
|
|
||||||
|
CAnimBlendSequence *seq = hier->sequences;
|
||||||
|
for(k = 0; k < hier->numSequences; k++, seq++){
|
||||||
|
// Each node has a name and key frames
|
||||||
|
CFileMgr::Read(fd, (char*)&cpan, sizeof(IfpHeader));
|
||||||
|
ROUNDSIZE(dgan.size);
|
||||||
|
CFileMgr::Read(fd, (char*)&anim, sizeof(IfpHeader));
|
||||||
|
ROUNDSIZE(anim.size);
|
||||||
|
CFileMgr::Read(fd, buf, anim.size);
|
||||||
|
int numFrames = *(int*)(buf+28);
|
||||||
|
#ifdef PED_SKIN
|
||||||
|
if(anim.size == 44)
|
||||||
|
seq->SetBoneTag(*(int*)(buf+40));
|
||||||
|
#endif
|
||||||
|
seq->SetName(buf);
|
||||||
|
if(numFrames == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
CFileMgr::Read(fd, (char*)&info, sizeof(info));
|
||||||
|
if(strncmp(info.ident, "KR00", 4) == 0){
|
||||||
|
seq->SetNumFrames(numFrames, false);
|
||||||
|
KeyFrame *kf = seq->GetKeyFrame(0);
|
||||||
|
for(l = 0; l < numFrames; l++, kf++){
|
||||||
|
CFileMgr::Read(fd, buf, 0x14);
|
||||||
|
kf->rotation.x = -fbuf[0];
|
||||||
|
kf->rotation.y = -fbuf[1];
|
||||||
|
kf->rotation.z = -fbuf[2];
|
||||||
|
kf->rotation.w = fbuf[3];
|
||||||
|
kf->deltaTime = fbuf[4]; // absolute time here
|
||||||
|
}
|
||||||
|
}else if(strncmp(info.ident, "KRT0", 4) == 0){
|
||||||
|
seq->SetNumFrames(numFrames, true);
|
||||||
|
KeyFrameTrans *kf = (KeyFrameTrans*)seq->GetKeyFrame(0);
|
||||||
|
for(l = 0; l < numFrames; l++, kf++){
|
||||||
|
CFileMgr::Read(fd, buf, 0x20);
|
||||||
|
kf->rotation.x = -fbuf[0];
|
||||||
|
kf->rotation.y = -fbuf[1];
|
||||||
|
kf->rotation.z = -fbuf[2];
|
||||||
|
kf->rotation.w = fbuf[3];
|
||||||
|
kf->translation.x = fbuf[4];
|
||||||
|
kf->translation.y = fbuf[5];
|
||||||
|
kf->translation.z = fbuf[6];
|
||||||
|
kf->deltaTime = fbuf[7]; // absolute time here
|
||||||
|
}
|
||||||
|
}else if(strncmp(info.ident, "KRTS", 4) == 0){
|
||||||
|
seq->SetNumFrames(numFrames, true);
|
||||||
|
KeyFrameTrans *kf = (KeyFrameTrans*)seq->GetKeyFrame(0);
|
||||||
|
for(l = 0; l < numFrames; l++, kf++){
|
||||||
|
CFileMgr::Read(fd, buf, 0x2C);
|
||||||
|
kf->rotation.x = -fbuf[0];
|
||||||
|
kf->rotation.y = -fbuf[1];
|
||||||
|
kf->rotation.z = -fbuf[2];
|
||||||
|
kf->rotation.w = fbuf[3];
|
||||||
|
kf->translation.x = fbuf[4];
|
||||||
|
kf->translation.y = fbuf[5];
|
||||||
|
kf->translation.z = fbuf[6];
|
||||||
|
// scaling ignored
|
||||||
|
kf->deltaTime = fbuf[10]; // absolute time here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert absolute time to deltas
|
||||||
|
for(l = seq->numFrames-1; l > 0; l--){
|
||||||
|
KeyFrame *kf1 = seq->GetKeyFrame(l);
|
||||||
|
KeyFrame *kf2 = seq->GetKeyFrame(l-1);
|
||||||
|
kf1->deltaTime -= kf2->deltaTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hier->RemoveQuaternionFlips();
|
||||||
|
if(compress)
|
||||||
|
hier->RemoveUncompressedData();
|
||||||
|
else
|
||||||
|
hier->CalcTotalTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CAnimManager::RemoveLastAnimFile(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
ms_numAnimBlocks--;
|
||||||
|
ms_numAnimations = ms_aAnimBlocks[ms_numAnimBlocks].firstIndex;
|
||||||
|
for(i = 0; i < ms_aAnimBlocks[ms_numAnimBlocks].numAnims; i++)
|
||||||
|
ms_aAnimations[ms_aAnimBlocks[ms_numAnimBlocks].firstIndex + i].RemoveAnimSequences();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x403380, CAnimManager::Initialise, PATCH_JUMP);
|
||||||
|
InjectHook(0x4033B0, CAnimManager::Shutdown, PATCH_JUMP);
|
||||||
|
InjectHook(0x403410, CAnimManager::UncompressAnimation, PATCH_JUMP);
|
||||||
|
InjectHook(0x4034A0, CAnimManager::GetAnimationBlock, PATCH_JUMP);
|
||||||
|
InjectHook(0x4034F0, (CAnimBlendHierarchy *(*)(const char*, CAnimBlock*))CAnimManager::GetAnimation, PATCH_JUMP);
|
||||||
|
InjectHook(0x4035B0, CAnimManager::GetAnimGroupName, PATCH_JUMP);
|
||||||
|
InjectHook(0x4035C0, CAnimManager::CreateAnimAssociation, PATCH_JUMP);
|
||||||
|
InjectHook(0x4035E0, (CAnimBlendAssociation *(*)(AssocGroupId, AnimationId))CAnimManager::GetAnimAssociation, PATCH_JUMP);
|
||||||
|
InjectHook(0x403600, (CAnimBlendAssociation *(*)(AssocGroupId, const char*))CAnimManager::GetAnimAssociation, PATCH_JUMP);
|
||||||
|
InjectHook(0x403620, CAnimManager::AddAnimation, PATCH_JUMP);
|
||||||
|
InjectHook(0x4036A0, CAnimManager::AddAnimationAndSync, PATCH_JUMP);
|
||||||
|
InjectHook(0x403710, CAnimManager::BlendAnimation, PATCH_JUMP);
|
||||||
|
InjectHook(0x4038F0, CAnimManager::LoadAnimFiles, PATCH_JUMP);
|
||||||
|
InjectHook(0x403A10, (void (*)(const char *))CAnimManager::LoadAnimFile, PATCH_JUMP);
|
||||||
|
InjectHook(0x403A40, (void (*)(int, bool))CAnimManager::LoadAnimFile, PATCH_JUMP);
|
||||||
|
InjectHook(0x404320, CAnimManager::RemoveLastAnimFile, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
268
src/animation/AnimManager.h
Normal file
268
src/animation/AnimManager.h
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AnimBlendHierarchy.h"
|
||||||
|
|
||||||
|
enum AssocGroupId
|
||||||
|
{
|
||||||
|
ASSOCGRP_STD,
|
||||||
|
ASSOCGRP_PLAYER,
|
||||||
|
ASSOCGRP_PLAYERROCKET,
|
||||||
|
ASSOCGRP_PLAYER1ARMED,
|
||||||
|
ASSOCGRP_PLAYER2ARMED,
|
||||||
|
ASSOCGRP_PLAYERBBBAT,
|
||||||
|
ASSOCGRP_SHUFFLE,
|
||||||
|
ASSOCGRP_OLD,
|
||||||
|
ASSOCGRP_GANG1,
|
||||||
|
ASSOCGRP_GANG2,
|
||||||
|
ASSOCGRP_FAT,
|
||||||
|
ASSOCGRP_OLDFAT,
|
||||||
|
ASSOCGRP_WOMAN,
|
||||||
|
ASSOCGRP_WOMANSHOP,
|
||||||
|
ASSOCGRP_BUSYWOMAN,
|
||||||
|
ASSOCGRP_SEXYWOMAN,
|
||||||
|
ASSOCGRP_OLDWOMAN,
|
||||||
|
ASSOCGRP_FARWOMAN,
|
||||||
|
ASSOCGRP_PANICCHUNKY,
|
||||||
|
ASSOCGRP_PLAYERBACK,
|
||||||
|
ASSOCGRP_PLAYERLEFT,
|
||||||
|
ASSOCGRP_PLAYERRIGHT,
|
||||||
|
ASSOCGRP_ROCKETBACK,
|
||||||
|
ASSOCGRP_ROCKETLEFT,
|
||||||
|
ASSOCGRP_ROCKETRIGHT,
|
||||||
|
|
||||||
|
NUM_ANIM_ASSOC_GROUPS
|
||||||
|
};
|
||||||
|
|
||||||
|
enum AnimationId
|
||||||
|
{
|
||||||
|
ANIM_WALK,
|
||||||
|
ANIM_RUN,
|
||||||
|
ANIM_SPRINT,
|
||||||
|
ANIM_IDLE_STANCE,
|
||||||
|
ANIM_WALK_START,
|
||||||
|
ANIM_RUN_STOP,
|
||||||
|
ANIM_RUN_STOP_R,
|
||||||
|
ANIM_IDLE_CAM,
|
||||||
|
ANIM_IDLE_HBHB,
|
||||||
|
ANIM_IDLE_TIRED,
|
||||||
|
ANIM_IDLE_ARMED,
|
||||||
|
ANIM_IDLE_CHAT,
|
||||||
|
ANIM_IDLE_TAXI,
|
||||||
|
ANIM_KO_SHOT_FRONT1,
|
||||||
|
ANIM_KO_SHOT_FRONT2,
|
||||||
|
ANIM_KO_SHOT_FRONT3,
|
||||||
|
ANIM_KO_SHOT_FRONT4,
|
||||||
|
ANIM_KO_SHOT_FACE,
|
||||||
|
ANIM_KO_SHOT_STOM,
|
||||||
|
ANIM_KO_SHOT_ARML,
|
||||||
|
ANIM_KO_SHOT_ARMR,
|
||||||
|
ANIM_KO_SHOT_LEGL,
|
||||||
|
ANIM_KO_SHOT_LEGR,
|
||||||
|
ANIM_KD_LEFT,
|
||||||
|
ANIM_KD_RIGHT,
|
||||||
|
ANIM_KO_SKID_FRONT,
|
||||||
|
ANIM_KO_SPIN_R,
|
||||||
|
ANIM_KO_SKID_BACK,
|
||||||
|
ANIM_KO_SPIN_L,
|
||||||
|
ANIM_SHOT_FRONT_PARTIAL,
|
||||||
|
ANIM_SHOT_LEFT_PARTIAL,
|
||||||
|
ANIM_SHOT_BACK_PARTIAL,
|
||||||
|
ANIM_SHOT_RIGHT_PARTIAL,
|
||||||
|
ANIM_HIT_FRONT,
|
||||||
|
ANIM_HIT_LEFT,
|
||||||
|
ANIM_HIT_BACK,
|
||||||
|
ANIM_HIT_RIGHT,
|
||||||
|
ANIM_FLOOR_HIT,
|
||||||
|
ANIM_HIT_BODYBLOW,
|
||||||
|
ANIM_HIT_CHEST,
|
||||||
|
ANIM_HIT_HEAD,
|
||||||
|
ANIM_HIT_WALK,
|
||||||
|
ANIM_HIT_WALL,
|
||||||
|
ANIM_FLOOR_HIT_F,
|
||||||
|
ANIM_HIT_BEHIND,
|
||||||
|
ANIM_PUNCH_R,
|
||||||
|
ANIM_KICK_FLOOR,
|
||||||
|
ANIM_WEAPON_BAT_H,
|
||||||
|
ANIM_WEAPON_BAT_V,
|
||||||
|
ANIM_WEAPON_HGUN_BODY,
|
||||||
|
ANIM_WEAPON_AK_BODY,
|
||||||
|
ANIM_WEAPON_PUMP,
|
||||||
|
ANIM_WEAPON_SNIPER,
|
||||||
|
ANIM_WEAPON_THROW,
|
||||||
|
ANIM_WEAPON_THROWU,
|
||||||
|
ANIM_WEAPON_START_THROW,
|
||||||
|
ANIM_BOMBER,
|
||||||
|
ANIM_HGUN_RELOAD,
|
||||||
|
ANIM_AK_RELOAD,
|
||||||
|
ANIM_FPS_PUNCH,
|
||||||
|
ANIM_FPS_BAT,
|
||||||
|
ANIM_FPS_UZI,
|
||||||
|
ANIM_FPS_PUMP,
|
||||||
|
ANIM_FPS_AK,
|
||||||
|
ANIM_FPS_M16,
|
||||||
|
ANIM_FPS_ROCKET,
|
||||||
|
ANIM_FIGHT_IDLE,
|
||||||
|
ANIM_FIGHT2_IDLE,
|
||||||
|
ANIM_FIGHT_SH_F,
|
||||||
|
ANIM_FIGHT_BODYBLOW,
|
||||||
|
ANIM_FIGHT_HEAD,
|
||||||
|
ANIM_FIGHT_KICK,
|
||||||
|
ANIM_FIGHT_KNEE,
|
||||||
|
ANIM_FIGHT_LHOOK,
|
||||||
|
ANIM_FIGHT_PUNCH,
|
||||||
|
ANIM_FIGHT_ROUNDHOUSE,
|
||||||
|
ANIM_FIGHT_LONGKICK,
|
||||||
|
ANIM_FIGHT_PPUNCH,
|
||||||
|
ANIM_CAR_JACKED_RHS,
|
||||||
|
ANIM_CAR_LJACKED_RHS,
|
||||||
|
ANIM_CAR_JACKED_LHS,
|
||||||
|
ANIM_CAR_LJACKED_LHS,
|
||||||
|
ANIM_CAR_QJACK,
|
||||||
|
ANIM_CAR_QJACKED,
|
||||||
|
ANIM_CAR_ALIGN_LHS,
|
||||||
|
ANIM_CAR_ALIGNHI_LHS,
|
||||||
|
ANIM_CAR_OPEN_LHS,
|
||||||
|
ANIM_CAR_DOORLOCKED_LHS,
|
||||||
|
ANIM_CAR_PULLOUT_LHS,
|
||||||
|
ANIM_CAR_PULLOUT_LOW_LHS,
|
||||||
|
ANIM_CAR_GETIN_LHS,
|
||||||
|
ANIM_CAR_GETIN_LOW_LHS,
|
||||||
|
ANIM_CAR_CLOSEDOOR_LHS,
|
||||||
|
ANIM_CAR_CLOSEDOOR_LOW_LHS,
|
||||||
|
ANIM_CAR_ROLLDOOR,
|
||||||
|
ANIM_CAR_ROLLDOOR_LOW,
|
||||||
|
ANIM_CAR_GETOUT_LHS,
|
||||||
|
ANIM_CAR_GETOUT_LOW_LHS,
|
||||||
|
ANIM_CAR_CLOSE_LHS,
|
||||||
|
ANIM_CAR_ALIGN_RHS,
|
||||||
|
ANIM_CAR_ALIGNHI_RHS,
|
||||||
|
ANIM_CAR_OPEN_RHS,
|
||||||
|
ANIM_CAR_DOORLOCKED_RHS,
|
||||||
|
ANIM_CAR_PULLOUT_RHS,
|
||||||
|
ANIM_CAR_PULLOUT_LOW_RHS,
|
||||||
|
ANIM_CAR_GETIN_RHS,
|
||||||
|
ANIM_CAR_GETIN_LOW_RHS,
|
||||||
|
ANIM_CAR_CLOSEDOOR_RHS,
|
||||||
|
ANIM_CAR_CLOSEDOOR_LOW_RHS,
|
||||||
|
ANIM_CAR_SHUFFLE_RHS,
|
||||||
|
ANIM_CAR_LSHUFFLE_RHS,
|
||||||
|
ANIM_CAR_SIT,
|
||||||
|
ANIM_CAR_LSIT,
|
||||||
|
ANIM_CAR_SITP,
|
||||||
|
ANIM_CAR_SITPLO,
|
||||||
|
ANIM_DRIVE_L,
|
||||||
|
ANIM_DRIVE_R,
|
||||||
|
ANIM_DRIVE_LOW_L,
|
||||||
|
ANIM_DRIVE_LOW_R,
|
||||||
|
ANIM_DRIVEBY_L,
|
||||||
|
ANIM_DRIVEBY_R,
|
||||||
|
ANIM_CAR_LB,
|
||||||
|
ANIM_DRIVE_BOAT,
|
||||||
|
ANIM_CAR_GETOUT_RHS,
|
||||||
|
ANIM_CAR_GETOUT_LOW_RHS,
|
||||||
|
ANIM_CAR_CLOSE_RHS,
|
||||||
|
ANIM_CAR_HOOKERTALK,
|
||||||
|
ANIM_COACH_OPEN_L,
|
||||||
|
ANIM_COACH_OPEN_R,
|
||||||
|
ANIM_COACH_IN_L,
|
||||||
|
ANIM_COACH_IN_R,
|
||||||
|
ANIM_COACH_OUT_L,
|
||||||
|
ANIM_TRAIN_GETIN,
|
||||||
|
ANIM_TRAIN_GETOUT,
|
||||||
|
ANIM_CAR_CRAWLOUT_RHS,
|
||||||
|
ANIM_CAR_CRAWLOUT_RHS2,
|
||||||
|
ANIM_VAN_OPEN_L,
|
||||||
|
ANIM_VAN_GETIN_L,
|
||||||
|
ANIM_VAN_CLOSE_L,
|
||||||
|
ANIM_VAN_GETOUT_L,
|
||||||
|
ANIM_VAN_OPEN,
|
||||||
|
ANIM_VAN_GETIN,
|
||||||
|
ANIM_VAN_CLOSE,
|
||||||
|
ANIM_VAN_GETOUT,
|
||||||
|
ANIM_GETUP1,
|
||||||
|
ANIM_GETUP2,
|
||||||
|
ANIM_GETUP3,
|
||||||
|
ANIM_GETUP_FRONT,
|
||||||
|
ANIM_JUMP_LAUNCH,
|
||||||
|
ANIM_JUMP_GLIDE,
|
||||||
|
ANIM_JUMP_LAND,
|
||||||
|
ANIM_FALL_FALL,
|
||||||
|
ANIM_FALL_GLIDE,
|
||||||
|
ANIM_FALL_LAND,
|
||||||
|
ANIM_FALL_COLLAPSE,
|
||||||
|
ANIM_EV_STEP,
|
||||||
|
ANIM_EV_DIVE,
|
||||||
|
ANIM_XPRESS_SCRATCH,
|
||||||
|
ANIM_ROAD_CROSS,
|
||||||
|
ANIM_TURN_180,
|
||||||
|
ANIM_ARREST_GUN,
|
||||||
|
ANIM_DROWN,
|
||||||
|
ANIM_CPR,
|
||||||
|
ANIM_DUCK_DOWN,
|
||||||
|
ANIM_DUCK_LOW,
|
||||||
|
ANIM_RBLOCK_CSHOOT,
|
||||||
|
ANIM_WEAPON_THROWU2,
|
||||||
|
ANIM_HANDSUP,
|
||||||
|
ANIM_HANDSCOWER,
|
||||||
|
ANIM_FUCKU,
|
||||||
|
ANIM_PHONE_IN,
|
||||||
|
ANIM_PHONE_OUT,
|
||||||
|
ANIM_PHONE_TALK,
|
||||||
|
};
|
||||||
|
|
||||||
|
class CAnimBlendAssociation;
|
||||||
|
class CAnimBlendAssocGroup;
|
||||||
|
|
||||||
|
// A block of hierarchies
|
||||||
|
struct CAnimBlock
|
||||||
|
{
|
||||||
|
char name[24];
|
||||||
|
int32 firstIndex;
|
||||||
|
int32 numAnims;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AnimAssocDesc
|
||||||
|
{
|
||||||
|
int32 animId;
|
||||||
|
int32 flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AnimAssocDefinition
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
char *blockName;
|
||||||
|
int32 modelIndex;
|
||||||
|
int32 numAnims;
|
||||||
|
char **animNames;
|
||||||
|
AnimAssocDesc *animDescs;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CAnimManager
|
||||||
|
{
|
||||||
|
static AnimAssocDefinition ms_aAnimAssocDefinitions[NUM_ANIM_ASSOC_GROUPS];
|
||||||
|
static CAnimBlock *ms_aAnimBlocks; //[2]
|
||||||
|
static CAnimBlendHierarchy *ms_aAnimations; //[250]
|
||||||
|
static int32 &ms_numAnimBlocks;
|
||||||
|
static int32 &ms_numAnimations;
|
||||||
|
static CAnimBlendAssocGroup *&ms_aAnimAssocGroups;
|
||||||
|
static CLinkList<CAnimBlendHierarchy*> &ms_animCache;
|
||||||
|
public:
|
||||||
|
|
||||||
|
static void Initialise(void);
|
||||||
|
static void Shutdown(void);
|
||||||
|
static void UncompressAnimation(CAnimBlendHierarchy *anim);
|
||||||
|
static CAnimBlock *GetAnimationBlock(const char *name);
|
||||||
|
static CAnimBlendHierarchy *GetAnimation(const char *name, CAnimBlock *animBlock);
|
||||||
|
static CAnimBlendHierarchy *GetAnimation(int32 n) { return &ms_aAnimations[n]; }
|
||||||
|
static const char *GetAnimGroupName(AssocGroupId groupId);
|
||||||
|
static CAnimBlendAssociation *CreateAnimAssociation(AssocGroupId groupId, AnimationId animId);
|
||||||
|
static CAnimBlendAssociation *GetAnimAssociation(AssocGroupId groupId, AnimationId animId);
|
||||||
|
static CAnimBlendAssociation *GetAnimAssociation(AssocGroupId groupId, const char *name);
|
||||||
|
static CAnimBlendAssociation *AddAnimation(RpClump *clump, AssocGroupId groupId, AnimationId animId);
|
||||||
|
static CAnimBlendAssociation *AddAnimationAndSync(RpClump *clump, CAnimBlendAssociation *syncanim, AssocGroupId groupId, AnimationId animId);
|
||||||
|
static CAnimBlendAssociation *BlendAnimation(RpClump *clump, AssocGroupId groupId, AnimationId animId, float delta);
|
||||||
|
static void LoadAnimFiles(void);
|
||||||
|
static void LoadAnimFile(const char *filename);
|
||||||
|
static void LoadAnimFile(int fd, bool compress);
|
||||||
|
static void RemoveLastAnimFile(void);
|
||||||
|
};
|
228
src/animation/FrameUpdate.cpp
Normal file
228
src/animation/FrameUpdate.cpp
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "NodeName.h"
|
||||||
|
#include "VisibilityPlugins.h"
|
||||||
|
#include "AnimBlendClumpData.h"
|
||||||
|
#include "AnimBlendAssociation.h"
|
||||||
|
#include "RpAnimBlend.h"
|
||||||
|
|
||||||
|
CAnimBlendClumpData *&gpAnimBlendClump = *(CAnimBlendClumpData**)0x621000;
|
||||||
|
|
||||||
|
void FrameUpdateCallBack(AnimBlendFrameData *frame, void *arg);
|
||||||
|
void FrameUpdateCallBackWithVelocityExtraction(AnimBlendFrameData *frame, void *arg);
|
||||||
|
void FrameUpdateCallBackWith3dVelocityExtraction(AnimBlendFrameData *frame, void *arg);
|
||||||
|
|
||||||
|
void
|
||||||
|
FrameUpdateCallBack(AnimBlendFrameData *frame, void *arg)
|
||||||
|
{
|
||||||
|
CVector vec, pos(0.0f, 0.0f, 0.0f);
|
||||||
|
CQuaternion q, rot(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
float totalBlendAmount = 0.0f;
|
||||||
|
RwMatrix *mat = RwFrameGetMatrix(frame->frame);
|
||||||
|
CAnimBlendNode **node;
|
||||||
|
AnimBlendFrameUpdateData *updateData = (AnimBlendFrameUpdateData*)arg;
|
||||||
|
|
||||||
|
if(frame->flag & AnimBlendFrameData::VELOCITY_EXTRACTION &&
|
||||||
|
gpAnimBlendClump->pedPosition){
|
||||||
|
if(frame->flag & AnimBlendFrameData::VELOCITY_EXTRACTION_3D)
|
||||||
|
FrameUpdateCallBackWith3dVelocityExtraction(frame, arg);
|
||||||
|
else
|
||||||
|
FrameUpdateCallBackWithVelocityExtraction(frame, arg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(updateData->foobar)
|
||||||
|
for(node = updateData->nodes; *node; node++)
|
||||||
|
if((*node)->sequence && (*node)->association->IsPartial())
|
||||||
|
totalBlendAmount += (*node)->association->blendAmount;
|
||||||
|
|
||||||
|
for(node = updateData->nodes; *node; node++){
|
||||||
|
if((*node)->sequence){
|
||||||
|
(*node)->Update(vec, q, 1.0f-totalBlendAmount);
|
||||||
|
if((*node)->sequence->HasTranslation())
|
||||||
|
pos += vec;
|
||||||
|
rot += q;
|
||||||
|
}
|
||||||
|
++*node;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((frame->flag & AnimBlendFrameData::IGNORE_ROTATION) == 0){
|
||||||
|
RwMatrixSetIdentity(mat);
|
||||||
|
|
||||||
|
float norm = rot.MagnitudeSqr();
|
||||||
|
if(norm == 0.0f)
|
||||||
|
rot.w = 1.0f;
|
||||||
|
else
|
||||||
|
rot *= 1.0f/sqrt(norm);
|
||||||
|
rot.Get(mat);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((frame->flag & AnimBlendFrameData::IGNORE_TRANSLATION) == 0){
|
||||||
|
mat->pos.x = pos.x;
|
||||||
|
mat->pos.y = pos.y;
|
||||||
|
mat->pos.z = pos.z;
|
||||||
|
mat->pos.x += frame->resetPos.x;
|
||||||
|
mat->pos.y += frame->resetPos.y;
|
||||||
|
mat->pos.z += frame->resetPos.z;
|
||||||
|
}
|
||||||
|
RwMatrixUpdate(mat);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FrameUpdateCallBackWithVelocityExtraction(AnimBlendFrameData *frame, void *arg)
|
||||||
|
{
|
||||||
|
CVector vec, pos(0.0f, 0.0f, 0.0f);
|
||||||
|
CQuaternion q, rot(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
float totalBlendAmount = 0.0f;
|
||||||
|
float transx = 0.0f, transy = 0.0f;
|
||||||
|
float curx = 0.0f, cury = 0.0f;
|
||||||
|
float endx = 0.0f, endy = 0.0f;
|
||||||
|
bool looped = false;
|
||||||
|
RwMatrix *mat = RwFrameGetMatrix(frame->frame);
|
||||||
|
CAnimBlendNode **node;
|
||||||
|
AnimBlendFrameUpdateData *updateData = (AnimBlendFrameUpdateData*)arg;
|
||||||
|
|
||||||
|
if(updateData->foobar)
|
||||||
|
for(node = updateData->nodes; *node; node++)
|
||||||
|
if((*node)->sequence && (*node)->association->IsPartial())
|
||||||
|
totalBlendAmount += (*node)->association->blendAmount;
|
||||||
|
|
||||||
|
for(node = updateData->nodes; *node; node++)
|
||||||
|
if((*node)->sequence && (*node)->sequence->HasTranslation()){
|
||||||
|
if((*node)->association->HasTranslation()){
|
||||||
|
(*node)->GetCurrentTranslation(vec, 1.0f-totalBlendAmount);
|
||||||
|
cury += vec.y;
|
||||||
|
if((*node)->association->HasXTranslation())
|
||||||
|
curx += vec.x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(node = updateData->nodes; *node; node++){
|
||||||
|
if((*node)->sequence){
|
||||||
|
bool nodelooped = (*node)->Update(vec, q, 1.0f-totalBlendAmount);
|
||||||
|
rot += q;
|
||||||
|
if((*node)->sequence->HasTranslation()){
|
||||||
|
pos += vec;
|
||||||
|
if((*node)->association->HasTranslation()){
|
||||||
|
transy += vec.y;
|
||||||
|
if((*node)->association->HasXTranslation())
|
||||||
|
transx += vec.x;
|
||||||
|
looped |= nodelooped;
|
||||||
|
if(nodelooped){
|
||||||
|
(*node)->GetEndTranslation(vec, 1.0f-totalBlendAmount);
|
||||||
|
endy += vec.y;
|
||||||
|
if((*node)->association->HasXTranslation())
|
||||||
|
endx += vec.x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++*node;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((frame->flag & AnimBlendFrameData::IGNORE_ROTATION) == 0){
|
||||||
|
RwMatrixSetIdentity(mat);
|
||||||
|
|
||||||
|
float norm = rot.MagnitudeSqr();
|
||||||
|
if(norm == 0.0f)
|
||||||
|
rot.w = 1.0f;
|
||||||
|
else
|
||||||
|
rot *= 1.0f/sqrt(norm);
|
||||||
|
rot.Get(mat);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((frame->flag & AnimBlendFrameData::IGNORE_TRANSLATION) == 0){
|
||||||
|
gpAnimBlendClump->pedPosition->x = transx - curx;
|
||||||
|
gpAnimBlendClump->pedPosition->y = transy - cury;
|
||||||
|
if(looped){
|
||||||
|
gpAnimBlendClump->pedPosition->x += endx;
|
||||||
|
gpAnimBlendClump->pedPosition->y += endy;
|
||||||
|
}
|
||||||
|
mat->pos.x = pos.x - transx;
|
||||||
|
mat->pos.y = pos.y - transy;
|
||||||
|
mat->pos.z = pos.z;
|
||||||
|
if(mat->pos.z >= -0.8f)
|
||||||
|
if(mat->pos.z < -0.4f)
|
||||||
|
mat->pos.z += (2.5f * mat->pos.z + 2.0f) * frame->resetPos.z;
|
||||||
|
else
|
||||||
|
mat->pos.z += frame->resetPos.z;
|
||||||
|
mat->pos.x += frame->resetPos.x;
|
||||||
|
mat->pos.y += frame->resetPos.y;
|
||||||
|
}
|
||||||
|
RwMatrixUpdate(mat);
|
||||||
|
}
|
||||||
|
|
||||||
|
// original code uses do loops?
|
||||||
|
void
|
||||||
|
FrameUpdateCallBackWith3dVelocityExtraction(AnimBlendFrameData *frame, void *arg)
|
||||||
|
{
|
||||||
|
CVector vec, pos(0.0f, 0.0f, 0.0f);
|
||||||
|
CQuaternion q, rot(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
float totalBlendAmount = 0.0f;
|
||||||
|
CVector trans(0.0f, 0.0f, 0.0f);
|
||||||
|
CVector cur(0.0f, 0.0f, 0.0f);
|
||||||
|
CVector end(0.0f, 0.0f, 0.0f);
|
||||||
|
bool looped = false;
|
||||||
|
RwMatrix *mat = RwFrameGetMatrix(frame->frame);
|
||||||
|
CAnimBlendNode **node;
|
||||||
|
AnimBlendFrameUpdateData *updateData = (AnimBlendFrameUpdateData*)arg;
|
||||||
|
|
||||||
|
if(updateData->foobar)
|
||||||
|
for(node = updateData->nodes; *node; node++)
|
||||||
|
if((*node)->sequence && (*node)->association->IsPartial())
|
||||||
|
totalBlendAmount += (*node)->association->blendAmount;
|
||||||
|
|
||||||
|
for(node = updateData->nodes; *node; node++)
|
||||||
|
if((*node)->sequence && (*node)->sequence->HasTranslation()){
|
||||||
|
if((*node)->association->HasTranslation()){
|
||||||
|
(*node)->GetCurrentTranslation(vec, 1.0f-totalBlendAmount);
|
||||||
|
cur += vec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(node = updateData->nodes; *node; node++){
|
||||||
|
if((*node)->sequence){
|
||||||
|
bool nodelooped = (*node)->Update(vec, q, 1.0f-totalBlendAmount);
|
||||||
|
rot += q;
|
||||||
|
if((*node)->sequence->HasTranslation()){
|
||||||
|
pos += vec;
|
||||||
|
if((*node)->association->HasTranslation()){
|
||||||
|
trans += vec;
|
||||||
|
looped |= nodelooped;
|
||||||
|
if(nodelooped){
|
||||||
|
(*node)->GetEndTranslation(vec, 1.0f-totalBlendAmount);
|
||||||
|
end += vec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++*node;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((frame->flag & AnimBlendFrameData::IGNORE_ROTATION) == 0){
|
||||||
|
RwMatrixSetIdentity(mat);
|
||||||
|
|
||||||
|
float norm = rot.MagnitudeSqr();
|
||||||
|
if(norm == 0.0f)
|
||||||
|
rot.w = 1.0f;
|
||||||
|
else
|
||||||
|
rot *= 1.0f/sqrt(norm);
|
||||||
|
rot.Get(mat);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((frame->flag & AnimBlendFrameData::IGNORE_TRANSLATION) == 0){
|
||||||
|
*gpAnimBlendClump->pedPosition = trans - cur;
|
||||||
|
if(looped)
|
||||||
|
*gpAnimBlendClump->pedPosition += end;
|
||||||
|
mat->pos.x = (pos - trans).x + frame->resetPos.x;
|
||||||
|
mat->pos.y = (pos - trans).y + frame->resetPos.y;
|
||||||
|
mat->pos.z = (pos - trans).z + frame->resetPos.z;
|
||||||
|
}
|
||||||
|
RwMatrixUpdate(mat);
|
||||||
|
}
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x4025F0, FrameUpdateCallBack, PATCH_JUMP);
|
||||||
|
InjectHook(0x4028B0, FrameUpdateCallBackWithVelocityExtraction, PATCH_JUMP);
|
||||||
|
InjectHook(0x402D40, FrameUpdateCallBackWith3dVelocityExtraction, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
402
src/animation/RpAnimBlend.cpp
Normal file
402
src/animation/RpAnimBlend.cpp
Normal file
@ -0,0 +1,402 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "NodeName.h"
|
||||||
|
#include "VisibilityPlugins.h"
|
||||||
|
#include "AnimBlendClumpData.h"
|
||||||
|
#include "AnimBlendHierarchy.h"
|
||||||
|
#include "AnimBlendAssociation.h"
|
||||||
|
#include "RpAnimBlend.h"
|
||||||
|
|
||||||
|
RwInt32 &ClumpOffset = *(RwInt32*)0x8F1B84;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
ID_RPANIMBLEND = MAKECHUNKID(rwVENDORID_ROCKSTAR, 0xFD),
|
||||||
|
};
|
||||||
|
|
||||||
|
void*
|
||||||
|
AnimBlendClumpCreate(void *object, RwInt32 offsetInObject, RwInt32 sizeInObject)
|
||||||
|
{
|
||||||
|
*RWPLUGINOFFSET(CAnimBlendClumpData*, object, offsetInObject) = nil;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
AnimBlendClumpDestroy(void *object, RwInt32 offsetInObject, RwInt32 sizeInObject)
|
||||||
|
{
|
||||||
|
CAnimBlendClumpData *data;
|
||||||
|
data = *RPANIMBLENDCLUMPDATA(object);
|
||||||
|
if(data){
|
||||||
|
RpAnimBlendClumpRemoveAllAssociations((RpClump*)object);
|
||||||
|
delete data;
|
||||||
|
*RPANIMBLENDCLUMPDATA(object) = nil;
|
||||||
|
}
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *AnimBlendClumpCopy(void *dstObject, const void *srcObject, RwInt32 offsetInObject, RwInt32 sizeInObject) { return nil; }
|
||||||
|
|
||||||
|
bool
|
||||||
|
RpAnimBlendPluginAttach(void)
|
||||||
|
{
|
||||||
|
ClumpOffset = RpClumpRegisterPlugin(sizeof(CAnimBlendClumpData*), ID_RPANIMBLEND,
|
||||||
|
AnimBlendClumpCreate, AnimBlendClumpDestroy, AnimBlendClumpCopy);
|
||||||
|
return ClumpOffset >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlendAssociation*
|
||||||
|
RpAnimBlendGetNextAssociation(CAnimBlendAssociation *assoc)
|
||||||
|
{
|
||||||
|
if(assoc->link.next)
|
||||||
|
CAnimBlendAssociation::FromLink(assoc->link.next);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlendAssociation*
|
||||||
|
RpAnimBlendGetNextAssociation(CAnimBlendAssociation *assoc, uint32 mask)
|
||||||
|
{
|
||||||
|
CAnimBlendLink *link;
|
||||||
|
for(link = assoc->link.next; link; link = link->next){
|
||||||
|
assoc = CAnimBlendAssociation::FromLink(link);
|
||||||
|
if(assoc->flags & mask)
|
||||||
|
return assoc;
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RpAnimBlendAllocateData(RpClump *clump)
|
||||||
|
{
|
||||||
|
*RPANIMBLENDCLUMPDATA(clump) = new CAnimBlendClumpData;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
RpAnimBlendClumpSetBlendDeltas(RpClump *clump, uint32 mask, float delta)
|
||||||
|
{
|
||||||
|
CAnimBlendClumpData *clumpData = *RPANIMBLENDCLUMPDATA(clump);
|
||||||
|
for(CAnimBlendLink *link = clumpData->link.next; link; link = link->next){
|
||||||
|
CAnimBlendAssociation *assoc = CAnimBlendAssociation::FromLink(link);
|
||||||
|
if(mask == 0 || (assoc->flags & mask))
|
||||||
|
assoc->blendDelta = delta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RpAnimBlendClumpRemoveAllAssociations(RpClump *clump)
|
||||||
|
{
|
||||||
|
RpAnimBlendClumpRemoveAssociations(clump, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RpAnimBlendClumpRemoveAssociations(RpClump *clump, uint32 mask)
|
||||||
|
{
|
||||||
|
CAnimBlendClumpData *clumpData = *RPANIMBLENDCLUMPDATA(clump);
|
||||||
|
CAnimBlendLink *next;
|
||||||
|
for(CAnimBlendLink *link = clumpData->link.next; link; link = next){
|
||||||
|
next = link->next;
|
||||||
|
CAnimBlendAssociation *assoc = CAnimBlendAssociation::FromLink(link);
|
||||||
|
if(mask == 0 || (assoc->flags & mask))
|
||||||
|
if(assoc)
|
||||||
|
delete assoc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RwFrame*
|
||||||
|
FrameForAllChildrenCountCallBack(RwFrame *frame, void *data)
|
||||||
|
{
|
||||||
|
int *numFrames = (int*)data;
|
||||||
|
(*numFrames)++;
|
||||||
|
RwFrameForAllChildren(frame, FrameForAllChildrenCountCallBack, data);
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
RwFrame*
|
||||||
|
FrameForAllChildrenFillFrameArrayCallBack(RwFrame *frame, void *data)
|
||||||
|
{
|
||||||
|
AnimBlendFrameData **frames = (AnimBlendFrameData**)data;
|
||||||
|
(*frames)->frame = frame;
|
||||||
|
(*frames)++;
|
||||||
|
RwFrameForAllChildren(frame, FrameForAllChildrenFillFrameArrayCallBack, frames);
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FrameInitCallBack(AnimBlendFrameData *frameData, void*)
|
||||||
|
{
|
||||||
|
frameData->flag = 0;
|
||||||
|
frameData->resetPos = *RwMatrixGetPos(RwFrameGetMatrix(frameData->frame));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RpAnimBlendClumpInit(RpClump *clump)
|
||||||
|
{
|
||||||
|
#ifdef PED_SKIN
|
||||||
|
TODO
|
||||||
|
#else
|
||||||
|
int numFrames = 0;
|
||||||
|
CAnimBlendClumpData *clumpData;
|
||||||
|
RwFrame *root;
|
||||||
|
AnimBlendFrameData *frames;
|
||||||
|
|
||||||
|
RpAnimBlendAllocateData(clump);
|
||||||
|
clumpData = *RPANIMBLENDCLUMPDATA(clump);
|
||||||
|
root = RpClumpGetFrame(clump);
|
||||||
|
RwFrameForAllChildren(root, FrameForAllChildrenCountCallBack, &numFrames);
|
||||||
|
clumpData->SetNumberOfFrames(numFrames);
|
||||||
|
frames = clumpData->frames;
|
||||||
|
RwFrameForAllChildren(root, FrameForAllChildrenFillFrameArrayCallBack, &frames);
|
||||||
|
clumpData->ForAllFrames(FrameInitCallBack, nil);
|
||||||
|
clumpData->frames[0].flag |= AnimBlendFrameData::VELOCITY_EXTRACTION;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
RpAnimBlendClumpIsInitialized(RpClump *clump)
|
||||||
|
{
|
||||||
|
CAnimBlendClumpData *clumpData = *RPANIMBLENDCLUMPDATA(clump);
|
||||||
|
return clumpData && clumpData->numFrames != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlendAssociation*
|
||||||
|
RpAnimBlendClumpGetAssociation(RpClump *clump, uint32 id)
|
||||||
|
{
|
||||||
|
CAnimBlendClumpData *clumpData = *RPANIMBLENDCLUMPDATA(clump);
|
||||||
|
|
||||||
|
if(clumpData == nil) return nil;
|
||||||
|
|
||||||
|
for(CAnimBlendLink *link = clumpData->link.next; link; link = link->next){
|
||||||
|
CAnimBlendAssociation *assoc = CAnimBlendAssociation::FromLink(link);
|
||||||
|
if(assoc->animId == id)
|
||||||
|
return assoc;
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlendAssociation*
|
||||||
|
RpAnimBlendClumpGetMainAssociation(RpClump *clump, CAnimBlendAssociation **assocRet, float *blendRet)
|
||||||
|
{
|
||||||
|
CAnimBlendClumpData *clumpData = *RPANIMBLENDCLUMPDATA(clump);
|
||||||
|
|
||||||
|
if(clumpData == nil) return nil;
|
||||||
|
|
||||||
|
CAnimBlendAssociation *mainAssoc = nil;
|
||||||
|
CAnimBlendAssociation *secondAssoc = nil;
|
||||||
|
float mainBlend = 0.0;
|
||||||
|
float secondBlend = 0.0;
|
||||||
|
for(CAnimBlendLink *link = clumpData->link.next; link; link = link->next){
|
||||||
|
CAnimBlendAssociation *assoc = CAnimBlendAssociation::FromLink(link);
|
||||||
|
|
||||||
|
if(assoc->IsPartial())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(assoc->blendAmount > mainBlend){
|
||||||
|
secondBlend = mainBlend;
|
||||||
|
mainBlend = assoc->blendAmount;
|
||||||
|
|
||||||
|
secondAssoc = mainAssoc;
|
||||||
|
mainAssoc = assoc;
|
||||||
|
}else if(assoc->blendAmount > secondBlend){
|
||||||
|
secondBlend = assoc->blendAmount;
|
||||||
|
secondAssoc = assoc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(assocRet) *assocRet = secondAssoc;
|
||||||
|
if(blendRet) *blendRet = secondBlend;
|
||||||
|
return mainAssoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlendAssociation*
|
||||||
|
RpAnimBlendClumpGetMainPartialAssociation(RpClump *clump)
|
||||||
|
{
|
||||||
|
CAnimBlendClumpData *clumpData = *RPANIMBLENDCLUMPDATA(clump);
|
||||||
|
|
||||||
|
if(clumpData == nil) return nil;
|
||||||
|
|
||||||
|
CAnimBlendAssociation *mainAssoc = nil;
|
||||||
|
float mainBlend = 0.0;
|
||||||
|
for(CAnimBlendLink *link = clumpData->link.next; link; link = link->next){
|
||||||
|
CAnimBlendAssociation *assoc = CAnimBlendAssociation::FromLink(link);
|
||||||
|
|
||||||
|
if(!assoc->IsPartial())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(assoc->blendAmount > mainBlend){
|
||||||
|
mainBlend = assoc->blendAmount;
|
||||||
|
mainAssoc = assoc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mainAssoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlendAssociation*
|
||||||
|
RpAnimBlendClumpGetMainAssociation_N(RpClump *clump, int n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
CAnimBlendClumpData *clumpData = *RPANIMBLENDCLUMPDATA(clump);
|
||||||
|
|
||||||
|
if(clumpData == nil) return nil;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
for(CAnimBlendLink *link = clumpData->link.next; link; link = link->next){
|
||||||
|
CAnimBlendAssociation *assoc = CAnimBlendAssociation::FromLink(link);
|
||||||
|
|
||||||
|
if(assoc->IsPartial())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(i == n)
|
||||||
|
return assoc;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlendAssociation*
|
||||||
|
RpAnimBlendClumpGetMainPartialAssociation_N(RpClump *clump, int n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
CAnimBlendClumpData *clumpData = *RPANIMBLENDCLUMPDATA(clump);
|
||||||
|
|
||||||
|
if(clumpData == nil) return nil;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
for(CAnimBlendLink *link = clumpData->link.next; link; link = link->next){
|
||||||
|
CAnimBlendAssociation *assoc = CAnimBlendAssociation::FromLink(link);
|
||||||
|
|
||||||
|
if(!assoc->IsPartial())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(i == n)
|
||||||
|
return assoc;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlendAssociation*
|
||||||
|
RpAnimBlendClumpGetFirstAssociation(RpClump *clump, uint32 mask)
|
||||||
|
{
|
||||||
|
CAnimBlendClumpData *clumpData = *RPANIMBLENDCLUMPDATA(clump);
|
||||||
|
|
||||||
|
if(clumpData == nil) return nil;
|
||||||
|
|
||||||
|
for(CAnimBlendLink *link = clumpData->link.next; link; link = link->next){
|
||||||
|
CAnimBlendAssociation *assoc = CAnimBlendAssociation::FromLink(link);
|
||||||
|
if(assoc->flags & mask)
|
||||||
|
return assoc;
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
CAnimBlendAssociation*
|
||||||
|
RpAnimBlendClumpGetFirstAssociation(RpClump *clump)
|
||||||
|
{
|
||||||
|
CAnimBlendClumpData *clumpData = *RPANIMBLENDCLUMPDATA(clump);
|
||||||
|
if(clumpData == nil) return nil;
|
||||||
|
if(clumpData->link.next == nil) return nil;
|
||||||
|
return CAnimBlendAssociation::FromLink(clumpData->link.next);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FillFrameArrayCallBack(AnimBlendFrameData *frame, void *arg)
|
||||||
|
{
|
||||||
|
AnimBlendFrameData **frames = (AnimBlendFrameData**)arg;
|
||||||
|
frames[CVisibilityPlugins::GetFrameHierarchyId(frame->frame)] = frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RpAnimBlendClumpFillFrameArray(RpClump *clump, AnimBlendFrameData **frames)
|
||||||
|
{
|
||||||
|
#ifdef PED_SKIN
|
||||||
|
TODO
|
||||||
|
#else
|
||||||
|
(*RPANIMBLENDCLUMPDATA(clump))->ForAllFrames(FillFrameArrayCallBack, frames);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimBlendFrameData *pFrameDataFound;
|
||||||
|
|
||||||
|
void
|
||||||
|
FrameFindCallBack(AnimBlendFrameData *frame, void *arg)
|
||||||
|
{
|
||||||
|
char *nodename = GetFrameNodeName(frame->frame);
|
||||||
|
if(strcmpi(nodename, (char*)arg) == 0)
|
||||||
|
pFrameDataFound = frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimBlendFrameData*
|
||||||
|
RpAnimBlendClumpFindFrame(RpClump *clump, const char *name)
|
||||||
|
{
|
||||||
|
pFrameDataFound = nil;
|
||||||
|
#ifdef PED_SKIN
|
||||||
|
TODO
|
||||||
|
#else
|
||||||
|
(*RPANIMBLENDCLUMPDATA(clump))->ForAllFrames(FrameFindCallBack, (void*)name);
|
||||||
|
#endif
|
||||||
|
return pFrameDataFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RpAnimBlendClumpUpdateAnimations(RpClump *clump, float timeDelta)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
AnimBlendFrameUpdateData updateData;
|
||||||
|
float totalLength = 0.0f;
|
||||||
|
float totalBlend = 0.0f;
|
||||||
|
CAnimBlendLink *link, *next;
|
||||||
|
CAnimBlendClumpData *clumpData = *RPANIMBLENDCLUMPDATA(clump);
|
||||||
|
gpAnimBlendClump = clumpData;
|
||||||
|
|
||||||
|
if(clumpData->link.next == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Update blend and get node array
|
||||||
|
i = 0;
|
||||||
|
updateData.foobar = 0;
|
||||||
|
for(link = clumpData->link.next; link; link = next){
|
||||||
|
next = link->next;
|
||||||
|
CAnimBlendAssociation *assoc = CAnimBlendAssociation::FromLink(link);
|
||||||
|
if(assoc->UpdateBlend(timeDelta)){
|
||||||
|
// CAnimManager::UncompressAnimation(v6->hierarchy)
|
||||||
|
updateData.nodes[i++] = assoc->GetNode(0);
|
||||||
|
if(assoc->flags & ASSOC_MOVEMENT){
|
||||||
|
totalLength += assoc->hierarchy->totalLength/assoc->speed * assoc->blendAmount;
|
||||||
|
totalBlend += assoc->blendAmount;
|
||||||
|
}else
|
||||||
|
updateData.foobar = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateData.nodes[i] = 0;
|
||||||
|
|
||||||
|
clumpData->ForAllFrames(FrameUpdateCallBack, &updateData);
|
||||||
|
|
||||||
|
for(link = clumpData->link.next; link; link = link->next){
|
||||||
|
CAnimBlendAssociation *assoc = CAnimBlendAssociation::FromLink(link);
|
||||||
|
float relSpeed = totalLength == 0.0f ? 1.0f : totalBlend/totalLength;
|
||||||
|
assoc->UpdateTime(timeDelta, relSpeed);
|
||||||
|
}
|
||||||
|
RwFrameUpdateObjects(RpClumpGetFrame(clump));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x4052D0, RpAnimBlendPluginAttach, PATCH_JUMP);
|
||||||
|
InjectHook(0x4052A0, RpAnimBlendAllocateData, PATCH_JUMP);
|
||||||
|
InjectHook(0x405780, (CAnimBlendAssociation *(*)(CAnimBlendAssociation*))RpAnimBlendGetNextAssociation, PATCH_JUMP);
|
||||||
|
InjectHook(0x4057A0, (CAnimBlendAssociation *(*)(CAnimBlendAssociation*,uint32))RpAnimBlendGetNextAssociation, PATCH_JUMP);
|
||||||
|
|
||||||
|
InjectHook(0x405520, RpAnimBlendClumpSetBlendDeltas, PATCH_JUMP);
|
||||||
|
InjectHook(0x405560, RpAnimBlendClumpRemoveAllAssociations, PATCH_JUMP);
|
||||||
|
InjectHook(0x405570, RpAnimBlendClumpRemoveAssociations, PATCH_JUMP);
|
||||||
|
InjectHook(0x405480, RpAnimBlendClumpInit, PATCH_JUMP);
|
||||||
|
InjectHook(0x405500, RpAnimBlendClumpIsInitialized, PATCH_JUMP);
|
||||||
|
InjectHook(0x4055C0, RpAnimBlendClumpGetAssociation, PATCH_JUMP);
|
||||||
|
InjectHook(0x4055F0, RpAnimBlendClumpGetMainAssociation, PATCH_JUMP);
|
||||||
|
InjectHook(0x405680, RpAnimBlendClumpGetMainPartialAssociation, PATCH_JUMP);
|
||||||
|
InjectHook(0x4056D0, RpAnimBlendClumpGetMainAssociation_N, PATCH_JUMP);
|
||||||
|
InjectHook(0x405710, RpAnimBlendClumpGetMainPartialAssociation_N, PATCH_JUMP);
|
||||||
|
InjectHook(0x405750, (CAnimBlendAssociation *(*)(RpClump*, uint32))RpAnimBlendClumpGetFirstAssociation, PATCH_JUMP);
|
||||||
|
InjectHook(0x4031B0, (CAnimBlendAssociation *(*)(RpClump*))RpAnimBlendClumpGetFirstAssociation, PATCH_JUMP);
|
||||||
|
InjectHook(0x405460, RpAnimBlendClumpFillFrameArray, PATCH_JUMP);
|
||||||
|
InjectHook(0x4024B0, RpAnimBlendClumpUpdateAnimations, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
39
src/animation/RpAnimBlend.h
Normal file
39
src/animation/RpAnimBlend.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class CAnimBlendNode;
|
||||||
|
class CAnimBlendAssociation;
|
||||||
|
class CAnimBlendClumpData;
|
||||||
|
struct AnimBlendFrameData;
|
||||||
|
|
||||||
|
struct AnimBlendFrameUpdateData
|
||||||
|
{
|
||||||
|
int foobar;
|
||||||
|
CAnimBlendNode *nodes[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
extern RwInt32 &ClumpOffset;
|
||||||
|
#define RPANIMBLENDCLUMPDATA(o) (RWPLUGINOFFSET(CAnimBlendClumpData*, o, ClumpOffset))
|
||||||
|
|
||||||
|
bool RpAnimBlendPluginAttach(void);
|
||||||
|
CAnimBlendAssociation *RpAnimBlendGetNextAssociation(CAnimBlendAssociation *assoc);
|
||||||
|
CAnimBlendAssociation *RpAnimBlendGetNextAssociation(CAnimBlendAssociation *assoc, uint32 mask);
|
||||||
|
void RpAnimBlendAllocateData(RpClump *clump);
|
||||||
|
|
||||||
|
void RpAnimBlendClumpSetBlendDeltas(RpClump *clump, uint32 mask, float delta);
|
||||||
|
void RpAnimBlendClumpRemoveAllAssociations(RpClump *clump);
|
||||||
|
void RpAnimBlendClumpRemoveAssociations(RpClump *clump, uint32 mask);
|
||||||
|
void RpAnimBlendClumpInit(RpClump *clump);
|
||||||
|
bool RpAnimBlendClumpIsInitialized(RpClump *clump);
|
||||||
|
AnimBlendFrameData *RpAnimBlendClumpFindFrame(RpClump *clump, const char *name);
|
||||||
|
void FillFrameArrayCallBack(AnimBlendFrameData *frame, void *arg);
|
||||||
|
CAnimBlendAssociation *RpAnimBlendClumpGetAssociation(RpClump *clump, uint32 id);
|
||||||
|
CAnimBlendAssociation *RpAnimBlendClumpGetMainAssociation(RpClump *clump, CAnimBlendAssociation **assocRet, float *blendRet);
|
||||||
|
CAnimBlendAssociation *RpAnimBlendClumpGetMainPartialAssociation(RpClump *clump);
|
||||||
|
CAnimBlendAssociation *RpAnimBlendClumpGetMainAssociation_N(RpClump *clump, int n);
|
||||||
|
CAnimBlendAssociation *RpAnimBlendClumpGetMainPartialAssociation_N(RpClump *clump, int n);
|
||||||
|
CAnimBlendAssociation *RpAnimBlendClumpGetFirstAssociation(RpClump *clump, uint32 mask);
|
||||||
|
CAnimBlendAssociation *RpAnimBlendClumpGetFirstAssociation(RpClump *clump);
|
||||||
|
|
||||||
|
|
||||||
|
extern CAnimBlendClumpData *&gpAnimBlendClump;
|
||||||
|
void FrameUpdateCallBack(AnimBlendFrameData *frame, void *arg);
|
@ -42,6 +42,7 @@
|
|||||||
#include "TxdStore.h"
|
#include "TxdStore.h"
|
||||||
#include "FileMgr.h"
|
#include "FileMgr.h"
|
||||||
#include "Text.h"
|
#include "Text.h"
|
||||||
|
#include "RpAnimBlend.h"
|
||||||
#include "Frontend.h"
|
#include "Frontend.h"
|
||||||
|
|
||||||
#define DEFAULT_VIEWWINDOW (tan(CDraw::GetFOV() * (360.0f / PI)))
|
#define DEFAULT_VIEWWINDOW (tan(CDraw::GetFOV() * (360.0f / PI)))
|
||||||
@ -54,7 +55,7 @@
|
|||||||
|
|
||||||
WRAPPER void CameraSize(RwCamera *camera, void *rect, float viewWindow, float aspectRatio) { EAXJMP(0x527170); }
|
WRAPPER void CameraSize(RwCamera *camera, void *rect, float viewWindow, float aspectRatio) { EAXJMP(0x527170); }
|
||||||
|
|
||||||
WRAPPER RwBool RpAnimBlendPluginAttach() { EAXJMP(0x4052D0); }
|
//WRAPPER RwBool RpAnimBlendPluginAttach() { EAXJMP(0x4052D0); }
|
||||||
WRAPPER RwBool NodeNamePluginAttach() { EAXJMP(0x527100); }
|
WRAPPER RwBool NodeNamePluginAttach() { EAXJMP(0x527100); }
|
||||||
|
|
||||||
|
|
||||||
|
83
src/math/Quaternion.h
Normal file
83
src/math/Quaternion.h
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// TODO: actually implement this
|
||||||
|
class CQuaternion
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
float x, y, z, w;
|
||||||
|
CQuaternion(void) {}
|
||||||
|
CQuaternion(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {}
|
||||||
|
|
||||||
|
float Magnitude(void) const { return sqrt(x*x + y*y + z*z + w*w); }
|
||||||
|
float MagnitudeSqr(void) const { return x*x + y*y + z*z + w*w; }
|
||||||
|
|
||||||
|
const CQuaternion &operator+=(CQuaternion const &right) {
|
||||||
|
x += right.x;
|
||||||
|
y += right.y;
|
||||||
|
z += right.z;
|
||||||
|
w += right.w;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CQuaternion &operator-=(CQuaternion const &right) {
|
||||||
|
x -= right.x;
|
||||||
|
y -= right.y;
|
||||||
|
z -= right.z;
|
||||||
|
w -= right.w;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CQuaternion &operator*=(float right) {
|
||||||
|
x *= right;
|
||||||
|
y *= right;
|
||||||
|
z *= right;
|
||||||
|
w *= right;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CQuaternion &operator/=(float right) {
|
||||||
|
x /= right;
|
||||||
|
y /= right;
|
||||||
|
z /= right;
|
||||||
|
w /= right;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CQuaternion operator-() const {
|
||||||
|
return CQuaternion(-x, -y, -z, -w);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Slerp(const CQuaternion &q1, const CQuaternion &q2, float theta, float invSin, float t);
|
||||||
|
void Get(RwMatrix *matrix);
|
||||||
|
};
|
||||||
|
|
||||||
|
inline float
|
||||||
|
DotProduct(const CQuaternion &q1, const CQuaternion &q2)
|
||||||
|
{
|
||||||
|
return q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CQuaternion operator+(const CQuaternion &left, const CQuaternion &right)
|
||||||
|
{
|
||||||
|
return CQuaternion(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CQuaternion operator-(const CQuaternion &left, const CQuaternion &right)
|
||||||
|
{
|
||||||
|
return CQuaternion(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CQuaternion operator*(const CQuaternion &left, float right)
|
||||||
|
{
|
||||||
|
return CQuaternion(left.x * right, left.y * right, left.z * right, left.w * right);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CQuaternion operator*(float left, const CQuaternion &right)
|
||||||
|
{
|
||||||
|
return CQuaternion(left * right.x, left * right.y, left * right.z, left * right.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CQuaternion operator/(const CQuaternion &left, float right)
|
||||||
|
{
|
||||||
|
return CQuaternion(left.x / right, left.y / right, left.z / right, left.w / right);
|
||||||
|
}
|
57
src/math/math.cpp
Normal file
57
src/math/math.cpp
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patcher.h"
|
||||||
|
#include "Quaternion.h"
|
||||||
|
|
||||||
|
// TODO: move more stuff into here
|
||||||
|
|
||||||
|
void
|
||||||
|
CQuaternion::Slerp(const CQuaternion &q1, const CQuaternion &q2, float theta, float invSin, float t)
|
||||||
|
{
|
||||||
|
if(theta == 0.0f)
|
||||||
|
*this = q2;
|
||||||
|
else{
|
||||||
|
float w1, w2;
|
||||||
|
if(theta > PI/2){
|
||||||
|
theta = PI - theta;
|
||||||
|
w1 = sin((1.0f - t) * theta) * invSin;
|
||||||
|
w2 = -sin(t * theta) * invSin;
|
||||||
|
}else{
|
||||||
|
w1 = sin((1.0f - t) * theta) * invSin;
|
||||||
|
w2 = sin(t * theta) * invSin;
|
||||||
|
}
|
||||||
|
*this = w1*q1 + w2*q2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CQuaternion::Get(RwMatrix *matrix)
|
||||||
|
{
|
||||||
|
float x2 = x+x;
|
||||||
|
float y2 = y+y;
|
||||||
|
float z2 = z+z;
|
||||||
|
|
||||||
|
float x_2x = x * x2;
|
||||||
|
float x_2y = x * y2;
|
||||||
|
float x_2z = x * z2;
|
||||||
|
float y_2y = y * y2;
|
||||||
|
float y_2z = y * z2;
|
||||||
|
float z_2z = z * z2;
|
||||||
|
float w_2x = w * x2;
|
||||||
|
float w_2y = w * y2;
|
||||||
|
float w_2z = w * z2;
|
||||||
|
|
||||||
|
matrix->right.x = 1.0f - (y_2y + z_2z);
|
||||||
|
matrix->up.x = x_2y - w_2z;
|
||||||
|
matrix->at.x = x_2z + w_2y;
|
||||||
|
matrix->right.y = x_2y + w_2z;
|
||||||
|
matrix->up.y = 1.0f - (x_2x + z_2z);
|
||||||
|
matrix->at.y = y_2z - w_2x;
|
||||||
|
matrix->right.z = x_2z - w_2y;
|
||||||
|
matrix->up.z = y_2z + w_2x;
|
||||||
|
matrix->at.z = 1.0f - (x_2x + y_2y);
|
||||||
|
}
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x4BA1C0, &CQuaternion::Slerp, PATCH_JUMP);
|
||||||
|
InjectHook(0x4BA0D0, &CQuaternion::Get, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
@ -138,7 +138,10 @@ public:
|
|||||||
while(n--)
|
while(n--)
|
||||||
freeHead.Insert(&links[n]);
|
freeHead.Insert(&links[n]);
|
||||||
}
|
}
|
||||||
// Shutdown
|
void Shutdown(void){
|
||||||
|
delete[] links;
|
||||||
|
links = nil;
|
||||||
|
}
|
||||||
void Clear(void){
|
void Clear(void){
|
||||||
while(head.next != &tail)
|
while(head.next != &tail)
|
||||||
Remove(head.next);
|
Remove(head.next);
|
||||||
|
Loading…
Reference in New Issue
Block a user