mirror of
https://gitlab.com/shinovon/re3-symbian.git
synced 2026-05-23 01:57:21 +03:00
Initial commit
This commit is contained in:
commit
77cdaaf97e
827 changed files with 418745 additions and 0 deletions
174
src/animation/AnimBlendAssocGroup.cpp
Normal file
174
src/animation/AnimBlendAssocGroup.cpp
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
#include "common.h"
|
||||
|
||||
#if defined _WIN32 && !defined __MINGW32__
|
||||
#if defined __MWERKS__
|
||||
#include <wctype.h>
|
||||
#else
|
||||
#include "ctype.h"
|
||||
#endif
|
||||
#else
|
||||
#include <cwctype>
|
||||
#endif
|
||||
|
||||
#include "General.h"
|
||||
#include "RwHelper.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(!CGeneral::faststricmp(assocList[i].hierarchy->name, name))
|
||||
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);
|
||||
}
|
||||
|
||||
bool
|
||||
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 true;
|
||||
#ifndef ASCII_STRCMP
|
||||
if(iswdigit(c1) && iswdigit(c2))
|
||||
#else
|
||||
if(__ascii_iswdigit(c1) && __ascii_iswdigit(c2))
|
||||
#endif
|
||||
continue;
|
||||
#ifndef ASCII_STRCMP
|
||||
c1 = toupper(c1);
|
||||
c2 = toupper(c2);
|
||||
#else
|
||||
c1 = __ascii_toupper(c1);
|
||||
c2 = __ascii_toupper(c2);
|
||||
#endif
|
||||
|
||||
if(c1 != c2)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
CBaseModelInfo*
|
||||
GetModelFromName(const char *name)
|
||||
{
|
||||
int i;
|
||||
CBaseModelInfo *mi;
|
||||
|
||||
for(i = 0; i < MODELINFOSIZE; i++){
|
||||
mi = CModelInfo::GetModelInfo(i);
|
||||
if(mi && mi->GetRwObject() && RwObjectGetType(mi->GetRwObject()) == rpCLUMP &&
|
||||
strcmpIgnoringDigits(mi->GetModelName(), 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);
|
||||
assert(model);
|
||||
printf("Associated anim %s with model %s\n", anim->name, model->GetModelName());
|
||||
RpClump *clump = (RpClump*)model->CreateInstance();
|
||||
#ifdef PED_SKIN
|
||||
if(IsClumpSkinned(clump))
|
||||
RpClumpForAllAtomics(clump, AtomicRemoveAnimFromSkinCB, nil);
|
||||
#endif
|
||||
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, const char **animNames, int numAssocs)
|
||||
{
|
||||
int i;
|
||||
CAnimBlock *animBlock;
|
||||
|
||||
if(assocList)
|
||||
DestroyAssociations();
|
||||
|
||||
animBlock = CAnimManager::GetAnimationBlock(blockName);
|
||||
assocList = new CAnimBlendAssociation[numAssocs];
|
||||
|
||||
numAssociations = 0;
|
||||
for(i = 0; i < numAssocs; i++){
|
||||
assocList[i].Init(clump, CAnimManager::GetAnimation(animNames[i], animBlock));
|
||||
assocList[i].animId = i;
|
||||
}
|
||||
numAssociations = numAssocs;
|
||||
}
|
||||
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, const char **animNames, int numAssocs);
|
||||
};
|
||||
205
src/animation/AnimBlendAssociation.cpp
Normal file
205
src/animation/AnimBlendAssociation.cpp
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
#include "common.h"
|
||||
|
||||
#include "AnimBlendHierarchy.h"
|
||||
#include "AnimBlendClumpData.h"
|
||||
#include "RpAnimBlend.h"
|
||||
#include "AnimManager.h"
|
||||
#include "AnimBlendAssociation.h"
|
||||
#include "MemoryMgr.h"
|
||||
|
||||
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)
|
||||
{
|
||||
assert(nodes != nil);
|
||||
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);
|
||||
}
|
||||
|
||||
bool
|
||||
CAnimBlendAssociation::UpdateTime(float timeDelta, float relSpeed)
|
||||
{
|
||||
if(!IsRunning())
|
||||
return true;
|
||||
|
||||
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 true;
|
||||
}
|
||||
|
||||
// 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.0f, 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.0f, blendDelta);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
91
src/animation/AnimBlendAssociation.h
Normal file
91
src/animation/AnimBlendAssociation.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#pragma once
|
||||
|
||||
#include "AnimBlendList.h"
|
||||
#include "AnimBlendNode.h"
|
||||
#include "AnimBlendHierarchy.h"
|
||||
|
||||
enum {
|
||||
ASSOC_RUNNING = 1,
|
||||
ASSOC_REPEAT = 2,
|
||||
ASSOC_DELETEFADEDOUT = 4,
|
||||
ASSOC_FADEOUTWHENDONE = 8,
|
||||
ASSOC_PARTIAL = 0x10,
|
||||
ASSOC_MOVEMENT = 0x20, // ???
|
||||
ASSOC_HAS_TRANSLATION = 0x40,
|
||||
ASSOC_WALK = 0x80, // for CPed::PlayFootSteps(void)
|
||||
ASSOC_IDLE = 0x100, // only used by xpress scratch, see CPed::Chat(void)
|
||||
ASSOC_NOWALK = 0x200, // see CPed::PlayFootSteps(void)
|
||||
ASSOC_BLOCK = 0x400, // unused in assoc description, blocks other anims from being played
|
||||
ASSOC_FRONTAL = 0x800, // anims that we fall to front
|
||||
ASSOC_HAS_X_TRANSLATION = 0x1000, // for 2d velocity extraction
|
||||
};
|
||||
|
||||
// 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;
|
||||
|
||||
int32 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);
|
||||
#ifndef FIX_BUGS
|
||||
virtual
|
||||
#endif
|
||||
~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);
|
||||
bool UpdateTime(float timeDelta, float relSpeed);
|
||||
bool UpdateBlend(float timeDelta);
|
||||
|
||||
void SetRun(void) { flags |= ASSOC_RUNNING; }
|
||||
|
||||
inline float GetTimeLeft() { return hierarchy->totalLength - currentTime; }
|
||||
|
||||
static CAnimBlendAssociation *FromLink(CAnimBlendLink *l) {
|
||||
return (CAnimBlendAssociation*)((uint8*)l - offsetof(CAnimBlendAssociation, link));
|
||||
}
|
||||
};
|
||||
|
||||
VALIDATE_SIZE(CAnimBlendAssociation, 0x40);
|
||||
36
src/animation/AnimBlendClumpData.cpp
Normal file
36
src/animation/AnimBlendClumpData.cpp
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#include "common.h"
|
||||
|
||||
#include "AnimBlendClumpData.h"
|
||||
#include "MemoryMgr.h"
|
||||
|
||||
CAnimBlendClumpData::CAnimBlendClumpData(void)
|
||||
{
|
||||
numFrames = 0;
|
||||
velocity2d = 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);
|
||||
}
|
||||
57
src/animation/AnimBlendClumpData.h
Normal file
57
src/animation/AnimBlendClumpData.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#pragma once
|
||||
|
||||
#include "AnimBlendList.h"
|
||||
|
||||
|
||||
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;
|
||||
RpHAnimStdInterpFrame *hanimFrame;
|
||||
};
|
||||
int32 nodeID;
|
||||
#else
|
||||
RwFrame *frame;
|
||||
#endif
|
||||
};
|
||||
#ifndef PED_SKIN
|
||||
VALIDATE_SIZE(AnimBlendFrameData, 0x14);
|
||||
#endif
|
||||
|
||||
|
||||
class CAnimBlendClumpData
|
||||
{
|
||||
public:
|
||||
CAnimBlendLink link;
|
||||
int32 numFrames;
|
||||
#ifdef PED_SKIN
|
||||
int32 modelNumber; // doesn't seem to be used
|
||||
#endif
|
||||
union {
|
||||
CVector2D *velocity2d;
|
||||
CVector *velocity3d;
|
||||
};
|
||||
// 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);
|
||||
};
|
||||
#ifndef PED_SKIN
|
||||
VALIDATE_SIZE(CAnimBlendClumpData, 0x14);
|
||||
#endif
|
||||
94
src/animation/AnimBlendHierarchy.cpp
Normal file
94
src/animation/AnimBlendHierarchy.cpp
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
#include "common.h"
|
||||
|
||||
#include "AnimBlendSequence.h"
|
||||
#include "AnimBlendHierarchy.h"
|
||||
|
||||
CAnimBlendHierarchy::CAnimBlendHierarchy(void)
|
||||
{
|
||||
sequences = nil;
|
||||
numSequences = 0;
|
||||
compressed = 0;
|
||||
totalLength = 0.0f;
|
||||
linkPtr = nil;
|
||||
}
|
||||
|
||||
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;
|
||||
totalLength = 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;
|
||||
totalLength = Max(totalLength, seqTime);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CAnimBlendHierarchy::RemoveQuaternionFlips(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < numSequences; i++)
|
||||
sequences[i].RemoveQuaternionFlips();
|
||||
}
|
||||
|
||||
void
|
||||
CAnimBlendHierarchy::RemoveAnimSequences(void)
|
||||
{
|
||||
delete[] sequences;
|
||||
numSequences = 0;
|
||||
}
|
||||
|
||||
void
|
||||
CAnimBlendHierarchy::Uncompress(void)
|
||||
{
|
||||
#ifdef ANIM_COMPRESSION
|
||||
int i;
|
||||
assert(compressed);
|
||||
for(i = 0; i < numSequences; i++)
|
||||
sequences[i].Uncompress();
|
||||
#endif
|
||||
if(totalLength == 0.0f)
|
||||
CalcTotalTime();
|
||||
compressed = 0;
|
||||
}
|
||||
|
||||
void
|
||||
CAnimBlendHierarchy::RemoveUncompressedData(void)
|
||||
{
|
||||
#ifdef ANIM_COMPRESSION
|
||||
int i;
|
||||
assert(!compressed);
|
||||
for(i = 0; i < numSequences; i++)
|
||||
sequences[i].RemoveUncompressedData();
|
||||
#endif
|
||||
compressed = 1;
|
||||
}
|
||||
|
||||
#ifdef USE_CUSTOM_ALLOCATOR
|
||||
void
|
||||
CAnimBlendHierarchy::MoveMemory(bool onlyone)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < numSequences; i++)
|
||||
if(sequences[i].MoveMemory() && onlyone)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
33
src/animation/AnimBlendHierarchy.h
Normal file
33
src/animation/AnimBlendHierarchy.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
#include "templates.h"
|
||||
|
||||
#ifdef MoveMemory
|
||||
#undef MoveMemory // windows shit
|
||||
#endif
|
||||
|
||||
class CAnimBlendSequence;
|
||||
|
||||
// A collection of sequences
|
||||
class CAnimBlendHierarchy
|
||||
{
|
||||
public:
|
||||
char name[24];
|
||||
CAnimBlendSequence *sequences;
|
||||
int16 numSequences;
|
||||
int16 compressed;
|
||||
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);
|
||||
void MoveMemory(bool onlyone = false);
|
||||
};
|
||||
|
||||
VALIDATE_SIZE(CAnimBlendHierarchy, 0x28);
|
||||
28
src/animation/AnimBlendList.h
Normal file
28
src/animation/AnimBlendList.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#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;
|
||||
Init();
|
||||
}
|
||||
};
|
||||
160
src/animation/AnimBlendNode.cpp
Normal file
160
src/animation/AnimBlendNode.cpp
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
#include "common.h"
|
||||
|
||||
#include "AnimBlendAssociation.h"
|
||||
#include "AnimBlendNode.h"
|
||||
|
||||
void
|
||||
CAnimBlendNode::Init(void)
|
||||
{
|
||||
frameA = -1;
|
||||
frameB = -1;
|
||||
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;
|
||||
}
|
||||
}
|
||||
31
src/animation/AnimBlendNode.h
Normal file
31
src/animation/AnimBlendNode.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#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);
|
||||
};
|
||||
|
||||
|
||||
VALIDATE_SIZE(CAnimBlendNode, 0x1C);
|
||||
200
src/animation/AnimBlendSequence.cpp
Normal file
200
src/animation/AnimBlendSequence.cpp
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
#include "common.h"
|
||||
|
||||
#include "AnimBlendSequence.h"
|
||||
#include "MemoryHeap.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);
|
||||
if(keyFramesCompressed)
|
||||
RwFree(keyFramesCompressed);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CAnimBlendSequence::Uncompress(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(numFrames == 0)
|
||||
return;
|
||||
|
||||
PUSH_MEMID(MEMID_ANIMATION);
|
||||
|
||||
float rotScale = 1.0f/4096.0f;
|
||||
float timeScale = 1.0f/60.0f;
|
||||
float transScale = 1.0f/128.0f;
|
||||
if(type & KF_TRANS){
|
||||
void *newKfs = RwMalloc(numFrames * sizeof(KeyFrameTrans));
|
||||
KeyFrameTransCompressed *ckf = (KeyFrameTransCompressed*)keyFramesCompressed;
|
||||
KeyFrameTrans *kf = (KeyFrameTrans*)newKfs;
|
||||
for(i = 0; i < numFrames; i++){
|
||||
kf->rotation.x = ckf->rot[0]*rotScale;
|
||||
kf->rotation.y = ckf->rot[1]*rotScale;
|
||||
kf->rotation.z = ckf->rot[2]*rotScale;
|
||||
kf->rotation.w = ckf->rot[3]*rotScale;
|
||||
kf->deltaTime = ckf->deltaTime*timeScale;
|
||||
kf->translation.x = ckf->trans[0]*transScale;
|
||||
kf->translation.y = ckf->trans[1]*transScale;
|
||||
kf->translation.z = ckf->trans[2]*transScale;
|
||||
kf++;
|
||||
ckf++;
|
||||
}
|
||||
keyFrames = newKfs;
|
||||
}else{
|
||||
void *newKfs = RwMalloc(numFrames * sizeof(KeyFrame));
|
||||
KeyFrameCompressed *ckf = (KeyFrameCompressed*)keyFramesCompressed;
|
||||
KeyFrame *kf = (KeyFrame*)newKfs;
|
||||
for(i = 0; i < numFrames; i++){
|
||||
kf->rotation.x = ckf->rot[0]*rotScale;
|
||||
kf->rotation.y = ckf->rot[1]*rotScale;
|
||||
kf->rotation.z = ckf->rot[2]*rotScale;
|
||||
kf->rotation.w = ckf->rot[3]*rotScale;
|
||||
kf->deltaTime = ckf->deltaTime*timeScale;
|
||||
kf++;
|
||||
ckf++;
|
||||
}
|
||||
keyFrames = newKfs;
|
||||
}
|
||||
REGISTER_MEMPTR(&keyFrames);
|
||||
|
||||
RwFree(keyFramesCompressed);
|
||||
keyFramesCompressed = nil;
|
||||
|
||||
POP_MEMID();
|
||||
}
|
||||
|
||||
void
|
||||
CAnimBlendSequence::CompressKeyframes(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(numFrames == 0)
|
||||
return;
|
||||
|
||||
PUSH_MEMID(MEMID_ANIMATION);
|
||||
|
||||
float rotScale = 4096.0f;
|
||||
float timeScale = 60.0f;
|
||||
float transScale = 128.0f;
|
||||
if(type & KF_TRANS){
|
||||
void *newKfs = RwMalloc(numFrames * sizeof(KeyFrameTransCompressed));
|
||||
KeyFrameTransCompressed *ckf = (KeyFrameTransCompressed*)newKfs;
|
||||
KeyFrameTrans *kf = (KeyFrameTrans*)keyFrames;
|
||||
for(i = 0; i < numFrames; i++){
|
||||
ckf->rot[0] = kf->rotation.x*rotScale;
|
||||
ckf->rot[1] = kf->rotation.y*rotScale;
|
||||
ckf->rot[2] = kf->rotation.z*rotScale;
|
||||
ckf->rot[3] = kf->rotation.w*rotScale;
|
||||
ckf->deltaTime = kf->deltaTime*timeScale + 0.5f;
|
||||
ckf->trans[0] = kf->translation.x*transScale;
|
||||
ckf->trans[1] = kf->translation.y*transScale;
|
||||
ckf->trans[2] = kf->translation.z*transScale;
|
||||
kf++;
|
||||
ckf++;
|
||||
}
|
||||
keyFramesCompressed = newKfs;
|
||||
}else{
|
||||
void *newKfs = RwMalloc(numFrames * sizeof(KeyFrameCompressed));
|
||||
KeyFrameCompressed *ckf = (KeyFrameCompressed*)newKfs;
|
||||
KeyFrame *kf = (KeyFrame*)keyFrames;
|
||||
for(i = 0; i < numFrames; i++){
|
||||
ckf->rot[0] = kf->rotation.x*rotScale;
|
||||
ckf->rot[1] = kf->rotation.y*rotScale;
|
||||
ckf->rot[2] = kf->rotation.z*rotScale;
|
||||
ckf->rot[3] = kf->rotation.w*rotScale;
|
||||
ckf->deltaTime = kf->deltaTime*timeScale + 0.5f;
|
||||
kf++;
|
||||
ckf++;
|
||||
}
|
||||
keyFramesCompressed = newKfs;
|
||||
}
|
||||
REGISTER_MEMPTR(&keyFramesCompressed);
|
||||
|
||||
POP_MEMID();
|
||||
}
|
||||
|
||||
void
|
||||
CAnimBlendSequence::RemoveUncompressedData(void)
|
||||
{
|
||||
if(numFrames == 0)
|
||||
return;
|
||||
CompressKeyframes();
|
||||
RwFree(keyFrames);
|
||||
keyFrames = nil;
|
||||
}
|
||||
|
||||
#ifdef USE_CUSTOM_ALLOCATOR
|
||||
bool
|
||||
CAnimBlendSequence::MoveMemory(void)
|
||||
{
|
||||
if(keyFrames){
|
||||
void *newaddr = gMainHeap.MoveMemory(keyFrames);
|
||||
if(newaddr != keyFrames){
|
||||
keyFrames = newaddr;
|
||||
return true;
|
||||
}
|
||||
}else if(keyFramesCompressed){
|
||||
void *newaddr = gMainHeap.MoveMemory(keyFramesCompressed);
|
||||
if(newaddr != keyFramesCompressed){
|
||||
keyFramesCompressed = newaddr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
68
src/animation/AnimBlendSequence.h
Normal file
68
src/animation/AnimBlendSequence.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#pragma once
|
||||
|
||||
#include "Quaternion.h"
|
||||
|
||||
#ifdef MoveMemory
|
||||
#undef MoveMemory // windows shit
|
||||
#endif
|
||||
|
||||
// TODO: put them somewhere else?
|
||||
struct KeyFrame {
|
||||
CQuaternion rotation;
|
||||
float deltaTime; // relative to previous key frame
|
||||
};
|
||||
|
||||
struct KeyFrameTrans : KeyFrame {
|
||||
CVector translation;
|
||||
};
|
||||
|
||||
struct KeyFrameCompressed {
|
||||
int16 rot[4]; // 4096
|
||||
int16 deltaTime; // 60
|
||||
};
|
||||
|
||||
struct KeyFrameTransCompressed : KeyFrameCompressed {
|
||||
int16 trans[3]; // 128
|
||||
};
|
||||
|
||||
|
||||
// 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); }
|
||||
void Uncompress(void);
|
||||
void CompressKeyframes(void);
|
||||
void RemoveUncompressedData(void);
|
||||
bool MoveMemory(void);
|
||||
|
||||
#ifdef PED_SKIN
|
||||
void SetBoneTag(int tag) { boneTag = tag; }
|
||||
#endif
|
||||
};
|
||||
#ifndef PED_SKIN
|
||||
VALIDATE_SIZE(CAnimBlendSequence, 0x2C);
|
||||
#endif
|
||||
941
src/animation/AnimManager.cpp
Normal file
941
src/animation/AnimManager.cpp
Normal file
|
|
@ -0,0 +1,941 @@
|
|||
#include "common.h"
|
||||
|
||||
#include "General.h"
|
||||
#include "RwHelper.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[NUMANIMBLOCKS];
|
||||
CAnimBlendHierarchy CAnimManager::ms_aAnimations[NUMANIMATIONS];
|
||||
int32 CAnimManager::ms_numAnimBlocks;
|
||||
int32 CAnimManager::ms_numAnimations;
|
||||
CAnimBlendAssocGroup *CAnimManager::ms_aAnimAssocGroups;
|
||||
CLinkList<CAnimBlendHierarchy*> CAnimManager::ms_animCache;
|
||||
|
||||
AnimAssocDesc aStdAnimDescs[] = {
|
||||
{ ANIM_STD_WALK, ASSOC_REPEAT | ASSOC_MOVEMENT | ASSOC_HAS_TRANSLATION | ASSOC_WALK },
|
||||
{ ANIM_STD_RUN, ASSOC_REPEAT | ASSOC_MOVEMENT | ASSOC_HAS_TRANSLATION | ASSOC_WALK },
|
||||
{ ANIM_STD_RUNFAST, ASSOC_REPEAT | ASSOC_MOVEMENT | ASSOC_HAS_TRANSLATION | ASSOC_WALK },
|
||||
{ ANIM_STD_IDLE, ASSOC_REPEAT },
|
||||
{ ANIM_STD_STARTWALK, ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_RUNSTOP1, ASSOC_DELETEFADEDOUT | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_RUNSTOP2, ASSOC_DELETEFADEDOUT | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_IDLE_CAM, ASSOC_REPEAT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_IDLE_HBHB, ASSOC_REPEAT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_IDLE_TIRED, ASSOC_REPEAT },
|
||||
{ ANIM_STD_IDLE_BIGGUN, ASSOC_REPEAT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CHAT, ASSOC_REPEAT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_HAILTAXI, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_KO_FRONT, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION | ASSOC_FRONTAL },
|
||||
{ ANIM_STD_KO_LEFT, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION | ASSOC_FRONTAL },
|
||||
{ ANIM_STD_KO_BACK, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION | ASSOC_FRONTAL },
|
||||
{ ANIM_STD_KO_RIGHT, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION | ASSOC_FRONTAL },
|
||||
{ ANIM_STD_KO_SHOT_FACE, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION | ASSOC_FRONTAL },
|
||||
{ ANIM_STD_KO_SHOT_STOMACH, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_KO_SHOT_ARM_L, ASSOC_PARTIAL | ASSOC_FRONTAL },
|
||||
{ ANIM_STD_KO_SHOT_ARM_R, ASSOC_PARTIAL | ASSOC_FRONTAL },
|
||||
{ ANIM_STD_KO_SHOT_LEG_L, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_KO_SHOT_LEG_R, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_SPINFORWARD_LEFT, ASSOC_PARTIAL | ASSOC_FRONTAL },
|
||||
{ ANIM_STD_SPINFORWARD_RIGHT, ASSOC_PARTIAL | ASSOC_FRONTAL },
|
||||
{ ANIM_STD_HIGHIMPACT_FRONT, ASSOC_PARTIAL },
|
||||
{ ANIM_STD_HIGHIMPACT_LEFT, ASSOC_PARTIAL },
|
||||
{ ANIM_STD_HIGHIMPACT_BACK, ASSOC_PARTIAL | ASSOC_FRONTAL },
|
||||
{ ANIM_STD_HIGHIMPACT_RIGHT, ASSOC_PARTIAL },
|
||||
{ ANIM_STD_HITBYGUN_FRONT, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_NOWALK },
|
||||
{ ANIM_STD_HITBYGUN_LEFT, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_NOWALK },
|
||||
{ ANIM_STD_HITBYGUN_BACK, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_NOWALK },
|
||||
{ ANIM_STD_HITBYGUN_RIGHT, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_NOWALK },
|
||||
{ ANIM_STD_HIT_FRONT, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_HIT_LEFT, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_HIT_BACK, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_HIT_RIGHT, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_HIT_FLOOR, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||
#if GTA_VERSION <= GTA3_PS2_160
|
||||
{ ANIM_STD_HIT_BODY, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
#endif
|
||||
{ ANIM_STD_HIT_BODYBLOW, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_HIT_CHEST, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_HIT_HEAD, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_HIT_WALK, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_HIT_WALL, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_HIT_FLOOR_FRONT, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL | ASSOC_FRONTAL },
|
||||
{ ANIM_STD_HIT_BEHIND, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_PUNCH, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_KICKGROUND, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_WEAPON_BAT_H, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_WEAPON_BAT_V, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_WEAPON_HGUN_BODY, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_NOWALK },
|
||||
{ ANIM_STD_WEAPON_AK_BODY, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_WEAPON_PUMP, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_WEAPON_SNIPER, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_WEAPON_THROW, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_THROW_UNDER, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_START_THROW, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_DETONATE, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_NOWALK },
|
||||
{ ANIM_STD_HGUN_RELOAD, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_NOWALK },
|
||||
{ ANIM_STD_AK_RELOAD, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_NOWALK },
|
||||
#ifdef PC_PLAYER_CONTROLS
|
||||
// maybe wrong define, but unused anyway
|
||||
{ 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 },
|
||||
#endif
|
||||
{ ANIM_STD_FIGHT_IDLE, ASSOC_REPEAT },
|
||||
{ ANIM_STD_FIGHT_2IDLE, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_FIGHT_SHUFFLE_F, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_FIGHT_BODYBLOW, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_FIGHT_HEAD, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_FIGHT_KICK, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_FIGHT_KNEE, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_FIGHT_LHOOK, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_FIGHT_PUNCH, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_FIGHT_ROUNDHOUSE, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_FIGHT_LONGKICK, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_PARTIAL_PUNCH, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL | ASSOC_NOWALK },
|
||||
{ ANIM_STD_JACKEDCAR_RHS, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_JACKEDCAR_LO_RHS, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_JACKEDCAR_LHS, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_JACKEDCAR_LO_LHS, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_QUICKJACK, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_QUICKJACKED, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_ALIGN_DOOR_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_ALIGNHI_DOOR_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_OPEN_DOOR_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CARDOOR_LOCKED_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_PULL_OUT_PED_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_PULL_OUT_PED_LO_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_GET_IN_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_GET_IN_LO_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_CLOSE_DOOR_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_CLOSE_DOOR_LO_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_CLOSE_DOOR_ROLLING_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_CLOSE_DOOR_ROLLING_LO_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_GETOUT_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_GETOUT_LO_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_CLOSE_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_ALIGN_DOOR_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_ALIGNHI_DOOR_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_OPEN_DOOR_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CARDOOR_LOCKED_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_PULL_OUT_PED_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_PULL_OUT_PED_LO_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_GET_IN_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_GET_IN_LO_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_CLOSE_DOOR_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_CLOSE_DOOR_LO_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_SHUFFLE_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_SHUFFLE_LO_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_SIT, ASSOC_DELETEFADEDOUT },
|
||||
{ ANIM_STD_CAR_SIT_LO, ASSOC_DELETEFADEDOUT },
|
||||
{ ANIM_STD_CAR_SIT_P, ASSOC_DELETEFADEDOUT },
|
||||
{ ANIM_STD_CAR_SIT_P_LO, ASSOC_DELETEFADEDOUT },
|
||||
{ ANIM_STD_CAR_DRIVE_LEFT, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_DRIVE_RIGHT, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_DRIVE_LEFT_LO, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_DRIVE_RIGHT_LO, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_DRIVEBY_LEFT, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_DRIVEBY_RIGHT, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_LOOKBEHIND, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_BOAT_DRIVE, ASSOC_DELETEFADEDOUT },
|
||||
{ ANIM_STD_GETOUT_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_GETOUT_LO_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_CLOSE_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CAR_HOOKERTALK, ASSOC_REPEAT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_COACH_OPEN_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_COACH_OPEN_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_COACH_GET_IN_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_COACH_GET_IN_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_COACH_GET_OUT_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_TRAIN_GETIN, ASSOC_PARTIAL },
|
||||
{ ANIM_STD_TRAIN_GETOUT, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CRAWLOUT_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_CRAWLOUT_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_VAN_OPEN_DOOR_REAR_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_VAN_GET_IN_REAR_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_VAN_CLOSE_DOOR_REAR_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_VAN_GET_OUT_REAR_LHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_VAN_OPEN_DOOR_REAR_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_VAN_GET_IN_REAR_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_VAN_CLOSE_DOOR_REAR_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_VAN_GET_OUT_REAR_RHS, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_GET_UP, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_GET_UP_LEFT, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_GET_UP_RIGHT, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_GET_UP_FRONT, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_JUMP_LAUNCH, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_JUMP_GLIDE, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_JUMP_LAND, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_FALL, ASSOC_REPEAT | ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_FALL_GLIDE, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_FALL_LAND, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_FALL_COLLAPSE, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_EVADE_STEP, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_EVADE_DIVE, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION | ASSOC_FRONTAL },
|
||||
{ ANIM_STD_XPRESS_SCRATCH, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_IDLE },
|
||||
{ ANIM_STD_ROADCROSS, ASSOC_REPEAT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_TURN180, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_ARREST, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_DROWN, ASSOC_PARTIAL },
|
||||
{ ANIM_MEDIC_CPR, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_DUCK_DOWN, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_DUCK_LOW, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_RBLOCK_SHOOT, ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_THROW_UNDER2, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_HANDSUP, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_HANDSCOWER, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION },
|
||||
{ ANIM_STD_PARTIAL_FUCKU, ASSOC_DELETEFADEDOUT | ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_NOWALK },
|
||||
{ ANIM_STD_PHONE_IN, ASSOC_PARTIAL },
|
||||
{ ANIM_STD_PHONE_OUT, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL },
|
||||
{ ANIM_STD_PHONE_TALK, ASSOC_REPEAT | ASSOC_DELETEFADEDOUT | ASSOC_PARTIAL },
|
||||
};
|
||||
#ifdef PC_PLAYER_CONTROLS
|
||||
AnimAssocDesc aStdAnimDescsSide[] = {
|
||||
{ ANIM_STD_WALK, ASSOC_REPEAT | ASSOC_MOVEMENT | ASSOC_HAS_TRANSLATION | ASSOC_WALK | ASSOC_HAS_X_TRANSLATION },
|
||||
{ ANIM_STD_RUN, ASSOC_REPEAT | ASSOC_MOVEMENT | ASSOC_HAS_TRANSLATION | ASSOC_WALK | ASSOC_HAS_X_TRANSLATION },
|
||||
{ ANIM_STD_RUNFAST, ASSOC_REPEAT | ASSOC_MOVEMENT | ASSOC_HAS_TRANSLATION | ASSOC_WALK | ASSOC_HAS_X_TRANSLATION },
|
||||
{ ANIM_STD_IDLE, ASSOC_REPEAT },
|
||||
{ ANIM_STD_STARTWALK, ASSOC_HAS_TRANSLATION | ASSOC_HAS_X_TRANSLATION },
|
||||
};
|
||||
#endif
|
||||
char const *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",
|
||||
#if GTA_VERSION <= GTA3_PS2_160
|
||||
"HIT_body",
|
||||
#endif
|
||||
"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",
|
||||
#ifdef PC_PLAYER_CONTROLS
|
||||
// maybe wrong define, but unused anyway
|
||||
"FPS_PUNCH",
|
||||
"FPS_BAT",
|
||||
"FPS_UZI",
|
||||
"FPS_PUMP",
|
||||
"FPS_AK",
|
||||
"FPS_M16",
|
||||
"FPS_ROCKET",
|
||||
#endif
|
||||
"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 const *aPlayerAnimations[] = {
|
||||
"walk_player",
|
||||
"run_player",
|
||||
"SPRINT_civi",
|
||||
"IDLE_STANCE",
|
||||
"walk_start",
|
||||
};
|
||||
char const *aPlayerWithRocketAnimations[] = {
|
||||
"walk_rocket",
|
||||
"run_rocket",
|
||||
"run_rocket",
|
||||
"idle_rocket",
|
||||
"walk_start_rocket",
|
||||
};
|
||||
char const *aPlayer1ArmedAnimations[] = {
|
||||
"walk_player",
|
||||
"run_1armed",
|
||||
"SPRINT_civi",
|
||||
"IDLE_STANCE",
|
||||
"walk_start",
|
||||
};
|
||||
char const *aPlayer2ArmedAnimations[] = {
|
||||
"walk_player",
|
||||
"run_armed",
|
||||
"run_armed",
|
||||
"idle_stance",
|
||||
"walk_start",
|
||||
};
|
||||
char const *aPlayerBBBatAnimations[] = {
|
||||
"walk_player",
|
||||
"run_player",
|
||||
"run_player",
|
||||
"IDLE_STANCE",
|
||||
"walk_start",
|
||||
};
|
||||
char const *aShuffleAnimations[] = {
|
||||
"WALK_shuffle",
|
||||
"RUN_civi",
|
||||
"SPRINT_civi",
|
||||
"IDLE_STANCE",
|
||||
};
|
||||
char const *aOldAnimations[] = {
|
||||
"walk_old",
|
||||
"run_civi",
|
||||
"sprint_civi",
|
||||
"idle_stance",
|
||||
};
|
||||
char const *aGang1Animations[] = {
|
||||
"walk_gang1",
|
||||
"run_gang1",
|
||||
"sprint_civi",
|
||||
"idle_stance",
|
||||
};
|
||||
char const *aGang2Animations[] = {
|
||||
"walk_gang2",
|
||||
"run_gang1",
|
||||
"sprint_civi",
|
||||
"idle_stance",
|
||||
};
|
||||
char const *aFatAnimations[] = {
|
||||
"walk_fat",
|
||||
"run_civi",
|
||||
"woman_runpanic",
|
||||
"idle_stance",
|
||||
};
|
||||
char const *aOldFatAnimations[] = {
|
||||
"walk_fatold",
|
||||
"run_fatold",
|
||||
"woman_runpanic",
|
||||
"idle_stance",
|
||||
};
|
||||
char const *aStdWomanAnimations[] = {
|
||||
"woman_walknorm",
|
||||
"woman_run",
|
||||
"woman_runpanic",
|
||||
"woman_idlestance",
|
||||
};
|
||||
char const *aWomanShopAnimations[] = {
|
||||
"woman_walkshop",
|
||||
"woman_run",
|
||||
"woman_run",
|
||||
"woman_idlestance",
|
||||
};
|
||||
char const *aBusyWomanAnimations[] = {
|
||||
"woman_walkbusy",
|
||||
"woman_run",
|
||||
"woman_runpanic",
|
||||
"woman_idlestance",
|
||||
};
|
||||
char const *aSexyWomanAnimations[] = {
|
||||
"woman_walksexy",
|
||||
"woman_run",
|
||||
"woman_runpanic",
|
||||
"woman_idlestance",
|
||||
};
|
||||
char const *aOldWomanAnimations[] = {
|
||||
"woman_walkold",
|
||||
"woman_run",
|
||||
"woman_runpanic",
|
||||
"woman_idlestance",
|
||||
};
|
||||
char const *aFatWomanAnimations[] = {
|
||||
"walk_fat",
|
||||
"woman_run",
|
||||
"woman_runpanic",
|
||||
"woman_idlestance",
|
||||
};
|
||||
char const *aPanicChunkyAnimations[] = {
|
||||
"run_fatold",
|
||||
"woman_runpanic",
|
||||
"woman_runpanic",
|
||||
"idle_stance",
|
||||
};
|
||||
#ifdef PC_PLAYER_CONTROLS
|
||||
char const *aPlayerStrafeBackAnimations[] = {
|
||||
"walk_player_back",
|
||||
"run_player_back",
|
||||
"run_player_back",
|
||||
"IDLE_STANCE",
|
||||
"walk_start_back",
|
||||
};
|
||||
char const *aPlayerStrafeLeftAnimations[] = {
|
||||
"walk_player_left",
|
||||
"run_left",
|
||||
"run_left",
|
||||
"IDLE_STANCE",
|
||||
"walk_start_left",
|
||||
};
|
||||
char const *aPlayerStrafeRightAnimations[] = {
|
||||
"walk_player_right",
|
||||
"run_right",
|
||||
"run_right",
|
||||
"IDLE_STANCE",
|
||||
"walk_start_right",
|
||||
};
|
||||
char const *aRocketStrafeBackAnimations[] = {
|
||||
"walk_rocket_back",
|
||||
"run_rocket_back",
|
||||
"run_rocket_back",
|
||||
"idle_rocket",
|
||||
"walkst_rocket_back",
|
||||
};
|
||||
char const *aRocketStrafeLeftAnimations[] = {
|
||||
"walk_rocket_left",
|
||||
"run_rocket_left",
|
||||
"run_rocket_left",
|
||||
"idle_rocket",
|
||||
"walkst_rocket_left",
|
||||
};
|
||||
char const *aRocketStrafeRightAnimations[] = {
|
||||
"walk_rocket_right",
|
||||
"run_rocket_right",
|
||||
"run_rocket_right",
|
||||
"idle_rocket",
|
||||
"walkst_rocket_right",
|
||||
};
|
||||
#endif
|
||||
|
||||
#define awc(a) ARRAY_SIZE(a), a
|
||||
const AnimAssocDefinition CAnimManager::ms_aAnimAssocDefinitions[NUM_ANIM_ASSOC_GROUPS] = {
|
||||
{ "man", "ped", MI_COP, awc(aStdAnimations), aStdAnimDescs },
|
||||
{ "player", "ped", MI_COP, awc(aPlayerAnimations), aStdAnimDescs },
|
||||
{ "playerrocket", "ped", MI_COP, awc(aPlayerWithRocketAnimations), aStdAnimDescs },
|
||||
{ "player1armed", "ped", MI_COP, awc(aPlayer1ArmedAnimations), aStdAnimDescs },
|
||||
{ "player2armed", "ped", MI_COP, awc(aPlayer2ArmedAnimations), aStdAnimDescs },
|
||||
{ "playerBBBat", "ped", MI_COP, awc(aPlayerBBBatAnimations), aStdAnimDescs },
|
||||
{ "shuffle", "ped", MI_COP, awc(aShuffleAnimations), aStdAnimDescs },
|
||||
{ "oldman", "ped", MI_COP, awc(aOldAnimations), aStdAnimDescs },
|
||||
{ "gang1", "ped", MI_COP, awc(aGang1Animations), aStdAnimDescs },
|
||||
{ "gang2", "ped", MI_COP, awc(aGang2Animations), aStdAnimDescs },
|
||||
{ "fatman", "ped", MI_COP, awc(aFatAnimations), aStdAnimDescs },
|
||||
{ "oldfatman", "ped", MI_COP, awc(aOldFatAnimations), aStdAnimDescs },
|
||||
{ "woman", "ped", MI_COP, awc(aStdWomanAnimations), aStdAnimDescs },
|
||||
{ "shopping", "ped", MI_COP, awc(aWomanShopAnimations), aStdAnimDescs },
|
||||
{ "busywoman", "ped", MI_COP, awc(aBusyWomanAnimations), aStdAnimDescs },
|
||||
{ "sexywoman", "ped", MI_COP, awc(aSexyWomanAnimations), aStdAnimDescs },
|
||||
{ "oldwoman", "ped", MI_COP, awc(aOldWomanAnimations), aStdAnimDescs },
|
||||
{ "fatwoman", "ped", MI_COP, awc(aFatWomanAnimations), aStdAnimDescs },
|
||||
{ "panicchunky", "ped", MI_COP, awc(aPanicChunkyAnimations), aStdAnimDescs },
|
||||
#ifdef PC_PLAYER_CONTROLS
|
||||
{ "playerback", "ped", MI_COP, awc(aPlayerStrafeBackAnimations), aStdAnimDescs },
|
||||
{ "playerleft", "ped", MI_COP, awc(aPlayerStrafeLeftAnimations), aStdAnimDescsSide },
|
||||
{ "playerright", "ped", MI_COP, awc(aPlayerStrafeRightAnimations), aStdAnimDescsSide },
|
||||
{ "rocketback", "ped", MI_COP, awc(aRocketStrafeBackAnimations), aStdAnimDescs },
|
||||
{ "rocketleft", "ped", MI_COP, awc(aRocketStrafeLeftAnimations), aStdAnimDescsSide },
|
||||
{ "rocketright", "ped", MI_COP, awc(aRocketStrafeRightAnimations), aStdAnimDescsSide },
|
||||
#endif
|
||||
};
|
||||
#undef awc
|
||||
|
||||
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(strcasecmp(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(!CGeneral::faststricmp(hier->name, name))
|
||||
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 = &ms_aAnimAssocGroups[i];
|
||||
const AnimAssocDefinition *def = &ms_aAnimAssocDefinitions[i];
|
||||
group->CreateAssociations(def->blockName, clump, def->animNames, def->numAnims);
|
||||
for(j = 0; j < group->numAssociations; j++)
|
||||
group->GetAnimation(j)->flags |= def->animDescs[j].flags;
|
||||
#ifdef PED_SKIN
|
||||
// forgot on xbox/android
|
||||
if(IsClumpSkinned(clump))
|
||||
RpClumpForAllAtomics(clump, AtomicRemoveAnimFromSkinCB, nil);
|
||||
#endif
|
||||
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(!CGeneral::faststrncmp(anpk.ident, "ANLF", 4)) {
|
||||
ROUNDSIZE(anpk.size);
|
||||
CFileMgr::Read(fd, buf, anpk.size);
|
||||
numANPK = *(int*)buf;
|
||||
} else if(!CGeneral::faststrncmp(anpk.ident, "ANPK", 4)) {
|
||||
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);
|
||||
seq->SetName(buf);
|
||||
#ifdef PED_SKIN
|
||||
if(anim.size == 44)
|
||||
seq->SetBoneTag(*(int*)(buf+40));
|
||||
#endif
|
||||
if(numFrames == 0)
|
||||
continue;
|
||||
|
||||
bool hasScale = false;
|
||||
bool hasTranslation = false;
|
||||
CFileMgr::Read(fd, (char*)&info, sizeof(info));
|
||||
if(!CGeneral::faststrncmp(info.ident, "KRTS", 4)) {
|
||||
hasScale = true;
|
||||
seq->SetNumFrames(numFrames, true);
|
||||
}else if(!CGeneral::faststrncmp(info.ident, "KRT0", 4)) {
|
||||
hasTranslation = true;
|
||||
seq->SetNumFrames(numFrames, true);
|
||||
}else if(!CGeneral::faststrncmp(info.ident, "KR00", 4)){
|
||||
seq->SetNumFrames(numFrames, false);
|
||||
}
|
||||
|
||||
for(l = 0; l < numFrames; l++){
|
||||
if(hasScale){
|
||||
CFileMgr::Read(fd, buf, 0x2C);
|
||||
CQuaternion rot(fbuf[0], fbuf[1], fbuf[2], fbuf[3]);
|
||||
rot.Invert();
|
||||
CVector trans(fbuf[4], fbuf[5], fbuf[6]);
|
||||
|
||||
KeyFrameTrans *kf = (KeyFrameTrans*)seq->GetKeyFrame(l);
|
||||
kf->rotation = rot;
|
||||
kf->translation = trans;
|
||||
// scaling ignored
|
||||
kf->deltaTime = fbuf[10]; // absolute time here
|
||||
}else if(hasTranslation){
|
||||
CFileMgr::Read(fd, buf, 0x20);
|
||||
CQuaternion rot(fbuf[0], fbuf[1], fbuf[2], fbuf[3]);
|
||||
rot.Invert();
|
||||
CVector trans(fbuf[4], fbuf[5], fbuf[6]);
|
||||
|
||||
KeyFrameTrans *kf = (KeyFrameTrans*)seq->GetKeyFrame(l);
|
||||
kf->rotation = rot;
|
||||
kf->translation = trans;
|
||||
kf->deltaTime = fbuf[7]; // absolute time here
|
||||
}else{
|
||||
CFileMgr::Read(fd, buf, 0x14);
|
||||
CQuaternion rot(fbuf[0], fbuf[1], fbuf[2], fbuf[3]);
|
||||
rot.Invert();
|
||||
|
||||
KeyFrame *kf = (KeyFrame*)seq->GetKeyFrame(l);
|
||||
kf->rotation = rot;
|
||||
kf->deltaTime = fbuf[4]; // 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();
|
||||
}
|
||||
94
src/animation/AnimManager.h
Normal file
94
src/animation/AnimManager.h
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
#pragma once
|
||||
|
||||
#include "AnimBlendHierarchy.h"
|
||||
#include "AnimationId.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_FATWOMAN,
|
||||
ASSOCGRP_PANICCHUNKY,
|
||||
#ifdef PC_PLAYER_CONTROLS
|
||||
ASSOCGRP_PLAYERBACK,
|
||||
ASSOCGRP_PLAYERLEFT,
|
||||
ASSOCGRP_PLAYERRIGHT,
|
||||
ASSOCGRP_ROCKETBACK,
|
||||
ASSOCGRP_ROCKETLEFT,
|
||||
ASSOCGRP_ROCKETRIGHT,
|
||||
#endif
|
||||
|
||||
NUM_ANIM_ASSOC_GROUPS
|
||||
};
|
||||
|
||||
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 const *name;
|
||||
char const *blockName;
|
||||
int32 modelIndex;
|
||||
int32 numAnims;
|
||||
char const **animNames;
|
||||
AnimAssocDesc *animDescs;
|
||||
};
|
||||
|
||||
class CAnimManager
|
||||
{
|
||||
static const AnimAssocDefinition ms_aAnimAssocDefinitions[NUM_ANIM_ASSOC_GROUPS];
|
||||
static CAnimBlock ms_aAnimBlocks[NUMANIMBLOCKS];
|
||||
static CAnimBlendHierarchy ms_aAnimations[NUMANIMATIONS];
|
||||
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);
|
||||
};
|
||||
210
src/animation/AnimationId.h
Normal file
210
src/animation/AnimationId.h
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
#pragma once
|
||||
|
||||
enum AnimationId
|
||||
{
|
||||
ANIM_STD_WALK,
|
||||
ANIM_STD_RUN,
|
||||
ANIM_STD_RUNFAST,
|
||||
ANIM_STD_IDLE,
|
||||
ANIM_STD_STARTWALK,
|
||||
ANIM_STD_RUNSTOP1,
|
||||
ANIM_STD_RUNSTOP2,
|
||||
ANIM_STD_IDLE_CAM,
|
||||
ANIM_STD_IDLE_HBHB,
|
||||
ANIM_STD_IDLE_TIRED,
|
||||
ANIM_STD_IDLE_BIGGUN,
|
||||
ANIM_STD_CHAT,
|
||||
ANIM_STD_HAILTAXI,
|
||||
ANIM_STD_KO_FRONT,
|
||||
ANIM_STD_KO_LEFT,
|
||||
ANIM_STD_KO_BACK,
|
||||
ANIM_STD_KO_RIGHT,
|
||||
ANIM_STD_KO_SHOT_FACE,
|
||||
ANIM_STD_KO_SHOT_STOMACH,
|
||||
ANIM_STD_KO_SHOT_ARM_L,
|
||||
ANIM_STD_KO_SHOT_ARM_R,
|
||||
ANIM_STD_KO_SHOT_LEG_L,
|
||||
ANIM_STD_KO_SHOT_LEG_R,
|
||||
ANIM_STD_SPINFORWARD_LEFT,
|
||||
ANIM_STD_SPINFORWARD_RIGHT,
|
||||
ANIM_STD_HIGHIMPACT_FRONT,
|
||||
ANIM_STD_HIGHIMPACT_LEFT,
|
||||
ANIM_STD_HIGHIMPACT_BACK,
|
||||
ANIM_STD_HIGHIMPACT_RIGHT,
|
||||
ANIM_STD_HITBYGUN_FRONT,
|
||||
ANIM_STD_HITBYGUN_LEFT,
|
||||
ANIM_STD_HITBYGUN_BACK,
|
||||
ANIM_STD_HITBYGUN_RIGHT,
|
||||
ANIM_STD_HIT_FRONT,
|
||||
ANIM_STD_HIT_LEFT,
|
||||
ANIM_STD_HIT_BACK,
|
||||
ANIM_STD_HIT_RIGHT,
|
||||
ANIM_STD_HIT_FLOOR,
|
||||
|
||||
/* names made up */
|
||||
#if GTA_VERSION <= GTA3_PS2_160
|
||||
ANIM_STD_HIT_BODY,
|
||||
#endif
|
||||
ANIM_STD_HIT_BODYBLOW,
|
||||
ANIM_STD_HIT_CHEST,
|
||||
ANIM_STD_HIT_HEAD,
|
||||
ANIM_STD_HIT_WALK,
|
||||
/**/
|
||||
|
||||
ANIM_STD_HIT_WALL,
|
||||
ANIM_STD_HIT_FLOOR_FRONT,
|
||||
ANIM_STD_HIT_BEHIND,
|
||||
ANIM_STD_PUNCH,
|
||||
ANIM_STD_KICKGROUND,
|
||||
|
||||
/* names made up */
|
||||
ANIM_STD_WEAPON_BAT_H,
|
||||
ANIM_STD_WEAPON_BAT_V,
|
||||
ANIM_STD_WEAPON_HGUN_BODY,
|
||||
ANIM_STD_WEAPON_AK_BODY,
|
||||
ANIM_STD_WEAPON_PUMP,
|
||||
ANIM_STD_WEAPON_SNIPER,
|
||||
ANIM_STD_WEAPON_THROW,
|
||||
/**/
|
||||
|
||||
ANIM_STD_THROW_UNDER,
|
||||
|
||||
/* names made up */
|
||||
ANIM_STD_START_THROW,
|
||||
/**/
|
||||
|
||||
ANIM_STD_DETONATE,
|
||||
|
||||
/* names made up */
|
||||
ANIM_STD_HGUN_RELOAD,
|
||||
ANIM_STD_AK_RELOAD,
|
||||
#ifdef PC_PLAYER_CONTROLS
|
||||
// maybe wrong define, but unused anyway
|
||||
ANIM_FPS_PUNCH,
|
||||
ANIM_FPS_BAT,
|
||||
ANIM_FPS_UZI,
|
||||
ANIM_FPS_PUMP,
|
||||
ANIM_FPS_AK,
|
||||
ANIM_FPS_M16,
|
||||
ANIM_FPS_ROCKET,
|
||||
#endif
|
||||
/**/
|
||||
|
||||
ANIM_STD_FIGHT_IDLE,
|
||||
ANIM_STD_FIGHT_2IDLE,
|
||||
ANIM_STD_FIGHT_SHUFFLE_F,
|
||||
|
||||
/* names made up */
|
||||
ANIM_STD_FIGHT_BODYBLOW,
|
||||
ANIM_STD_FIGHT_HEAD,
|
||||
ANIM_STD_FIGHT_KICK,
|
||||
ANIM_STD_FIGHT_KNEE,
|
||||
ANIM_STD_FIGHT_LHOOK,
|
||||
ANIM_STD_FIGHT_PUNCH,
|
||||
ANIM_STD_FIGHT_ROUNDHOUSE,
|
||||
ANIM_STD_FIGHT_LONGKICK,
|
||||
/**/
|
||||
|
||||
ANIM_STD_PARTIAL_PUNCH,
|
||||
ANIM_STD_JACKEDCAR_RHS,
|
||||
ANIM_STD_JACKEDCAR_LO_RHS,
|
||||
ANIM_STD_JACKEDCAR_LHS,
|
||||
ANIM_STD_JACKEDCAR_LO_LHS,
|
||||
ANIM_STD_QUICKJACK,
|
||||
ANIM_STD_QUICKJACKED,
|
||||
ANIM_STD_CAR_ALIGN_DOOR_LHS,
|
||||
ANIM_STD_CAR_ALIGNHI_DOOR_LHS,
|
||||
ANIM_STD_CAR_OPEN_DOOR_LHS,
|
||||
ANIM_STD_CARDOOR_LOCKED_LHS,
|
||||
ANIM_STD_CAR_PULL_OUT_PED_LHS,
|
||||
ANIM_STD_CAR_PULL_OUT_PED_LO_LHS,
|
||||
ANIM_STD_CAR_GET_IN_LHS,
|
||||
ANIM_STD_CAR_GET_IN_LO_LHS,
|
||||
ANIM_STD_CAR_CLOSE_DOOR_LHS,
|
||||
ANIM_STD_CAR_CLOSE_DOOR_LO_LHS,
|
||||
ANIM_STD_CAR_CLOSE_DOOR_ROLLING_LHS,
|
||||
ANIM_STD_CAR_CLOSE_DOOR_ROLLING_LO_LHS,
|
||||
ANIM_STD_GETOUT_LHS,
|
||||
ANIM_STD_GETOUT_LO_LHS,
|
||||
ANIM_STD_CAR_CLOSE_LHS,
|
||||
ANIM_STD_CAR_ALIGN_DOOR_RHS,
|
||||
ANIM_STD_CAR_ALIGNHI_DOOR_RHS,
|
||||
ANIM_STD_CAR_OPEN_DOOR_RHS,
|
||||
ANIM_STD_CARDOOR_LOCKED_RHS,
|
||||
ANIM_STD_CAR_PULL_OUT_PED_RHS,
|
||||
ANIM_STD_CAR_PULL_OUT_PED_LO_RHS,
|
||||
ANIM_STD_CAR_GET_IN_RHS,
|
||||
ANIM_STD_CAR_GET_IN_LO_RHS,
|
||||
ANIM_STD_CAR_CLOSE_DOOR_RHS,
|
||||
ANIM_STD_CAR_CLOSE_DOOR_LO_RHS,
|
||||
ANIM_STD_CAR_SHUFFLE_RHS,
|
||||
ANIM_STD_CAR_SHUFFLE_LO_RHS,
|
||||
ANIM_STD_CAR_SIT,
|
||||
ANIM_STD_CAR_SIT_LO,
|
||||
ANIM_STD_CAR_SIT_P,
|
||||
ANIM_STD_CAR_SIT_P_LO,
|
||||
ANIM_STD_CAR_DRIVE_LEFT,
|
||||
ANIM_STD_CAR_DRIVE_RIGHT,
|
||||
ANIM_STD_CAR_DRIVE_LEFT_LO,
|
||||
ANIM_STD_CAR_DRIVE_RIGHT_LO,
|
||||
ANIM_STD_CAR_DRIVEBY_LEFT,
|
||||
ANIM_STD_CAR_DRIVEBY_RIGHT,
|
||||
ANIM_STD_CAR_LOOKBEHIND,
|
||||
ANIM_STD_BOAT_DRIVE,
|
||||
ANIM_STD_GETOUT_RHS,
|
||||
ANIM_STD_GETOUT_LO_RHS,
|
||||
ANIM_STD_CAR_CLOSE_RHS,
|
||||
ANIM_STD_CAR_HOOKERTALK,
|
||||
ANIM_STD_COACH_OPEN_LHS,
|
||||
ANIM_STD_COACH_OPEN_RHS,
|
||||
ANIM_STD_COACH_GET_IN_LHS,
|
||||
ANIM_STD_COACH_GET_IN_RHS,
|
||||
ANIM_STD_COACH_GET_OUT_LHS,
|
||||
ANIM_STD_TRAIN_GETIN,
|
||||
ANIM_STD_TRAIN_GETOUT,
|
||||
ANIM_STD_CRAWLOUT_LHS,
|
||||
ANIM_STD_CRAWLOUT_RHS,
|
||||
ANIM_STD_VAN_OPEN_DOOR_REAR_LHS,
|
||||
ANIM_STD_VAN_GET_IN_REAR_LHS,
|
||||
ANIM_STD_VAN_CLOSE_DOOR_REAR_LHS,
|
||||
ANIM_STD_VAN_GET_OUT_REAR_LHS,
|
||||
ANIM_STD_VAN_OPEN_DOOR_REAR_RHS,
|
||||
ANIM_STD_VAN_GET_IN_REAR_RHS,
|
||||
ANIM_STD_VAN_CLOSE_DOOR_REAR_RHS,
|
||||
ANIM_STD_VAN_GET_OUT_REAR_RHS,
|
||||
ANIM_STD_GET_UP,
|
||||
ANIM_STD_GET_UP_LEFT,
|
||||
ANIM_STD_GET_UP_RIGHT,
|
||||
ANIM_STD_GET_UP_FRONT,
|
||||
ANIM_STD_JUMP_LAUNCH,
|
||||
ANIM_STD_JUMP_GLIDE,
|
||||
ANIM_STD_JUMP_LAND,
|
||||
ANIM_STD_FALL,
|
||||
ANIM_STD_FALL_GLIDE,
|
||||
ANIM_STD_FALL_LAND,
|
||||
ANIM_STD_FALL_COLLAPSE,
|
||||
ANIM_STD_EVADE_STEP,
|
||||
ANIM_STD_EVADE_DIVE,
|
||||
ANIM_STD_XPRESS_SCRATCH,
|
||||
ANIM_STD_ROADCROSS,
|
||||
ANIM_STD_TURN180,
|
||||
ANIM_STD_ARREST,
|
||||
ANIM_STD_DROWN,
|
||||
ANIM_MEDIC_CPR,
|
||||
ANIM_STD_DUCK_DOWN,
|
||||
ANIM_STD_DUCK_LOW,
|
||||
ANIM_STD_RBLOCK_SHOOT,
|
||||
|
||||
/* names made up */
|
||||
ANIM_STD_THROW_UNDER2,
|
||||
/**/
|
||||
|
||||
ANIM_STD_HANDSUP,
|
||||
ANIM_STD_HANDSCOWER,
|
||||
ANIM_STD_PARTIAL_FUCKU,
|
||||
ANIM_STD_PHONE_IN,
|
||||
ANIM_STD_PHONE_OUT,
|
||||
ANIM_STD_PHONE_TALK,
|
||||
|
||||
ANIM_STD_NUM
|
||||
};
|
||||
52
src/animation/Bones.cpp
Normal file
52
src/animation/Bones.cpp
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
#include "common.h"
|
||||
#include "PedModelInfo.h"
|
||||
#include "Bones.h"
|
||||
|
||||
#ifdef PED_SKIN
|
||||
|
||||
int
|
||||
ConvertPedNode2BoneTag(int node)
|
||||
{
|
||||
switch(node){
|
||||
case PED_TORSO: return BONE_waist;
|
||||
case PED_MID: return BONE_torso; // this is what Xbox/Mobile use
|
||||
// return BONE_mid; // this is what PS2/PC use
|
||||
case PED_HEAD: return BONE_head;
|
||||
case PED_UPPERARML: return BONE_upperarml;
|
||||
case PED_UPPERARMR: return BONE_upperarmr;
|
||||
case PED_HANDL: return BONE_Lhand;
|
||||
case PED_HANDR: return BONE_Rhand;
|
||||
case PED_UPPERLEGL: return BONE_upperlegl;
|
||||
case PED_UPPERLEGR: return BONE_upperlegr;
|
||||
case PED_FOOTL: return BONE_footl;
|
||||
case PED_FOOTR: return BONE_footr;
|
||||
case PED_LOWERLEGR: return BONE_lowerlegl;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char*
|
||||
ConvertBoneTag2BoneName(int tag)
|
||||
{
|
||||
switch(tag){
|
||||
case BONE_waist: return "Swaist";
|
||||
case BONE_upperlegr: return "Supperlegr";
|
||||
case BONE_lowerlegr: return "Slowerlegr";
|
||||
case BONE_footr: return "Sfootr";
|
||||
case BONE_upperlegl: return "Supperlegl";
|
||||
case BONE_lowerlegl: return "Slowerlegl";
|
||||
case BONE_footl: return "Sfootl";
|
||||
case BONE_mid: return "Smid";
|
||||
case BONE_torso: return "Storso";
|
||||
case BONE_head: return "Shead";
|
||||
case BONE_upperarmr: return "Supperarmr";
|
||||
case BONE_lowerarmr: return "Slowerarmr";
|
||||
case BONE_Rhand: return "SRhand";
|
||||
case BONE_upperarml: return "Supperarml";
|
||||
case BONE_lowerarml: return "Slowerarml";
|
||||
case BONE_Lhand: return "SLhand";
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
#endif
|
||||
24
src/animation/Bones.h
Normal file
24
src/animation/Bones.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
enum BoneTag
|
||||
{
|
||||
BONE_waist,
|
||||
BONE_upperlegr,
|
||||
BONE_lowerlegr,
|
||||
BONE_footr,
|
||||
BONE_upperlegl,
|
||||
BONE_lowerlegl,
|
||||
BONE_footl,
|
||||
BONE_mid,
|
||||
BONE_torso,
|
||||
BONE_head,
|
||||
BONE_upperarmr,
|
||||
BONE_lowerarmr,
|
||||
BONE_Rhand,
|
||||
BONE_upperarml,
|
||||
BONE_lowerarml,
|
||||
BONE_Lhand,
|
||||
};
|
||||
|
||||
int ConvertPedNode2BoneTag(int node);
|
||||
const char *ConvertBoneTag2BoneName(int tag);
|
||||
424
src/animation/CutsceneMgr.cpp
Normal file
424
src/animation/CutsceneMgr.cpp
Normal file
|
|
@ -0,0 +1,424 @@
|
|||
#include "common.h"
|
||||
|
||||
#include "General.h"
|
||||
#include "CutsceneMgr.h"
|
||||
#include "Directory.h"
|
||||
#include "Camera.h"
|
||||
#include "Streaming.h"
|
||||
#include "FileMgr.h"
|
||||
#include "main.h"
|
||||
#include "AnimManager.h"
|
||||
#include "AnimBlendAssociation.h"
|
||||
#include "AnimBlendAssocGroup.h"
|
||||
#include "AnimBlendClumpData.h"
|
||||
#include "Pad.h"
|
||||
#include "DMAudio.h"
|
||||
#include "World.h"
|
||||
#include "PlayerPed.h"
|
||||
#include "Wanted.h"
|
||||
#include "CutsceneHead.h"
|
||||
#include "RpAnimBlend.h"
|
||||
#include "ModelIndices.h"
|
||||
#include "TempColModels.h"
|
||||
|
||||
const struct {
|
||||
const char *szTrackName;
|
||||
int iTrackId;
|
||||
} musicNameIdAssoc[] = {
|
||||
{ "JB", STREAMED_SOUND_NEWS_INTRO },
|
||||
{ "BET", STREAMED_SOUND_BANK_INTRO },
|
||||
{ "L1_LG", STREAMED_SOUND_CUTSCENE_LUIGI1_LG },
|
||||
{ "L2_DSB", STREAMED_SOUND_CUTSCENE_LUIGI2_DSB },
|
||||
{ "L3_DM", STREAMED_SOUND_CUTSCENE_LUIGI3_DM },
|
||||
{ "L4_PAP", STREAMED_SOUND_CUTSCENE_LUIGI4_PAP },
|
||||
{ "L5_TFB", STREAMED_SOUND_CUTSCENE_LUIGI5_TFB },
|
||||
{ "J0_DM2", STREAMED_SOUND_CUTSCENE_JOEY0_DM2 },
|
||||
{ "J1_LFL", STREAMED_SOUND_CUTSCENE_JOEY1_LFL },
|
||||
{ "J2_KCL", STREAMED_SOUND_CUTSCENE_JOEY2_KCL },
|
||||
{ "J3_VH", STREAMED_SOUND_CUTSCENE_JOEY3_VH },
|
||||
{ "J4_ETH", STREAMED_SOUND_CUTSCENE_JOEY4_ETH },
|
||||
{ "J5_DST", STREAMED_SOUND_CUTSCENE_JOEY5_DST },
|
||||
{ "J6_TBJ", STREAMED_SOUND_CUTSCENE_JOEY6_TBJ },
|
||||
{ "T1_TOL", STREAMED_SOUND_CUTSCENE_TONI1_TOL },
|
||||
{ "T2_TPU", STREAMED_SOUND_CUTSCENE_TONI2_TPU },
|
||||
{ "T3_MAS", STREAMED_SOUND_CUTSCENE_TONI3_MAS },
|
||||
{ "T4_TAT", STREAMED_SOUND_CUTSCENE_TONI4_TAT },
|
||||
{ "T5_BF", STREAMED_SOUND_CUTSCENE_TONI5_BF },
|
||||
{ "S0_MAS", STREAMED_SOUND_CUTSCENE_SAL0_MAS },
|
||||
{ "S1_PF", STREAMED_SOUND_CUTSCENE_SAL1_PF },
|
||||
{ "S2_CTG", STREAMED_SOUND_CUTSCENE_SAL2_CTG },
|
||||
{ "S3_RTC", STREAMED_SOUND_CUTSCENE_SAL3_RTC },
|
||||
{ "S5_LRQ", STREAMED_SOUND_CUTSCENE_SAL5_LRQ },
|
||||
{ "S4_BDBA", STREAMED_SOUND_CUTSCENE_SAL4_BDBA },
|
||||
{ "S4_BDBB", STREAMED_SOUND_CUTSCENE_SAL4_BDBB },
|
||||
{ "S2_CTG2", STREAMED_SOUND_CUTSCENE_SAL2_CTG2 },
|
||||
{ "S4_BDBD", STREAMED_SOUND_CUTSCENE_SAL4_BDBD },
|
||||
{ "S5_LRQB", STREAMED_SOUND_CUTSCENE_SAL5_LRQB },
|
||||
{ "S5_LRQC", STREAMED_SOUND_CUTSCENE_SAL5_LRQC },
|
||||
{ "A1_SS0", STREAMED_SOUND_CUTSCENE_ASUKA_1_SSO },
|
||||
{ "A2_PP", STREAMED_SOUND_CUTSCENE_ASUKA_2_PP },
|
||||
{ "A3_SS", STREAMED_SOUND_CUTSCENE_ASUKA_3_SS },
|
||||
{ "A4_PDR", STREAMED_SOUND_CUTSCENE_ASUKA_4_PDR },
|
||||
{ "A5_K2FT", STREAMED_SOUND_CUTSCENE_ASUKA_5_K2FT},
|
||||
{ "K1_KBO", STREAMED_SOUND_CUTSCENE_KENJI1_KBO },
|
||||
{ "K2_GIS", STREAMED_SOUND_CUTSCENE_KENJI2_GIS },
|
||||
{ "K3_DS", STREAMED_SOUND_CUTSCENE_KENJI3_DS },
|
||||
{ "K4_SHI", STREAMED_SOUND_CUTSCENE_KENJI4_SHI },
|
||||
{ "K5_SD", STREAMED_SOUND_CUTSCENE_KENJI5_SD },
|
||||
{ "R0_PDR2", STREAMED_SOUND_CUTSCENE_RAY0_PDR2 },
|
||||
{ "R1_SW", STREAMED_SOUND_CUTSCENE_RAY1_SW },
|
||||
{ "R2_AP", STREAMED_SOUND_CUTSCENE_RAY2_AP },
|
||||
{ "R3_ED", STREAMED_SOUND_CUTSCENE_RAY3_ED },
|
||||
{ "R4_GF", STREAMED_SOUND_CUTSCENE_RAY4_GF },
|
||||
{ "R5_PB", STREAMED_SOUND_CUTSCENE_RAY5_PB },
|
||||
{ "R6_MM", STREAMED_SOUND_CUTSCENE_RAY6_MM },
|
||||
{ "D1_STOG", STREAMED_SOUND_CUTSCENE_DONALD1_STOG },
|
||||
{ "D2_KK", STREAMED_SOUND_CUTSCENE_DONALD2_KK },
|
||||
{ "D3_ADO", STREAMED_SOUND_CUTSCENE_DONALD3_ADO },
|
||||
{ "D5_ES", STREAMED_SOUND_CUTSCENE_DONALD5_ES },
|
||||
{ "D7_MLD", STREAMED_SOUND_CUTSCENE_DONALD7_MLD },
|
||||
{ "D4_GTA", STREAMED_SOUND_CUTSCENE_DONALD4_GTA },
|
||||
{ "D4_GTA2", STREAMED_SOUND_CUTSCENE_DONALD4_GTA2 },
|
||||
{ "D6_STS", STREAMED_SOUND_CUTSCENE_DONALD6_STS },
|
||||
{ "A6_BAIT", STREAMED_SOUND_CUTSCENE_ASUKA6_BAIT },
|
||||
{ "A7_ETG", STREAMED_SOUND_CUTSCENE_ASUKA7_ETG },
|
||||
{ "A8_PS", STREAMED_SOUND_CUTSCENE_ASUKA8_PS },
|
||||
{ "A9_ASD", STREAMED_SOUND_CUTSCENE_ASUKA9_ASD },
|
||||
{ "K4_SHI2", STREAMED_SOUND_CUTSCENE_KENJI4_SHI2 },
|
||||
{ "C1_TEX", STREAMED_SOUND_CUTSCENE_CATALINA1_TEX },
|
||||
{ "EL_PH1", STREAMED_SOUND_CUTSCENE_ELBURRO1_PH1 },
|
||||
{ "EL_PH2", STREAMED_SOUND_CUTSCENE_ELBURRO2_PH2 },
|
||||
{ "EL_PH3", STREAMED_SOUND_CUTSCENE_ELBURRO3_PH3 },
|
||||
{ "EL_PH4", STREAMED_SOUND_CUTSCENE_ELBURRO4_PH4 },
|
||||
{ "YD_PH1", STREAMED_SOUND_CUTSCENE_YARDIE_PH1 },
|
||||
{ "YD_PH2", STREAMED_SOUND_CUTSCENE_YARDIE_PH2 },
|
||||
{ "YD_PH3", STREAMED_SOUND_CUTSCENE_YARDIE_PH3 },
|
||||
{ "YD_PH4", STREAMED_SOUND_CUTSCENE_YARDIE_PH4 },
|
||||
{ "HD_PH1", STREAMED_SOUND_CUTSCENE_HOODS_PH1 },
|
||||
{ "HD_PH2", STREAMED_SOUND_CUTSCENE_HOODS_PH2 },
|
||||
{ "HD_PH3", STREAMED_SOUND_CUTSCENE_HOODS_PH3 },
|
||||
{ "HD_PH4", STREAMED_SOUND_CUTSCENE_HOODS_PH4 },
|
||||
{ "HD_PH5", STREAMED_SOUND_CUTSCENE_HOODS_PH5 },
|
||||
{ "MT_PH1", STREAMED_SOUND_CUTSCENE_MARTY_PH1 },
|
||||
{ "MT_PH2", STREAMED_SOUND_CUTSCENE_MARTY_PH2 },
|
||||
{ "MT_PH3", STREAMED_SOUND_CUTSCENE_MARTY_PH3 },
|
||||
{ "MT_PH4", STREAMED_SOUND_CUTSCENE_MARTY_PH4 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
int
|
||||
FindCutsceneAudioTrackId(const char *szCutsceneName)
|
||||
{
|
||||
for (int i = 0; musicNameIdAssoc[i].szTrackName; i++) {
|
||||
if (!CGeneral::faststricmp(musicNameIdAssoc[i].szTrackName, szCutsceneName))
|
||||
return musicNameIdAssoc[i].iTrackId;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool CCutsceneMgr::ms_running;
|
||||
bool CCutsceneMgr::ms_cutsceneProcessing;
|
||||
CDirectory *CCutsceneMgr::ms_pCutsceneDir;
|
||||
CCutsceneObject *CCutsceneMgr::ms_pCutsceneObjects[NUMCUTSCENEOBJECTS];
|
||||
int32 CCutsceneMgr::ms_numCutsceneObjs;
|
||||
bool CCutsceneMgr::ms_loaded;
|
||||
bool CCutsceneMgr::ms_animLoaded;
|
||||
bool CCutsceneMgr::ms_useLodMultiplier;
|
||||
char CCutsceneMgr::ms_cutsceneName[CUTSCENENAMESIZE];
|
||||
CAnimBlendAssocGroup CCutsceneMgr::ms_cutsceneAssociations;
|
||||
CVector CCutsceneMgr::ms_cutsceneOffset;
|
||||
float CCutsceneMgr::ms_cutsceneTimer;
|
||||
uint32 CCutsceneMgr::ms_cutsceneLoadStatus;
|
||||
|
||||
RpAtomic *
|
||||
CalculateBoundingSphereRadiusCB(RpAtomic *atomic, void *data)
|
||||
{
|
||||
float radius = RpAtomicGetBoundingSphere(atomic)->radius;
|
||||
RwV3d center = RpAtomicGetBoundingSphere(atomic)->center;
|
||||
|
||||
for (RwFrame *frame = RpAtomicGetFrame(atomic); RwFrameGetParent(frame); frame = RwFrameGetParent(frame))
|
||||
RwV3dTransformPoints(¢er, ¢er, 1, RwFrameGetMatrix(frame));
|
||||
|
||||
float size = RwV3dLength(¢er) + radius;
|
||||
if (size > *(float *)data)
|
||||
*(float *)data = size;
|
||||
return atomic;
|
||||
}
|
||||
|
||||
void
|
||||
CCutsceneMgr::Initialise(void)
|
||||
{
|
||||
ms_numCutsceneObjs = 0;
|
||||
ms_loaded = false;
|
||||
ms_running = false;
|
||||
ms_animLoaded = false;
|
||||
ms_cutsceneProcessing = false;
|
||||
ms_useLodMultiplier = false;
|
||||
|
||||
ms_pCutsceneDir = new CDirectory(CUTSCENEDIRSIZE);
|
||||
ms_pCutsceneDir->ReadDirFile("ANIM\\CUTS.DIR");
|
||||
}
|
||||
|
||||
void
|
||||
CCutsceneMgr::Shutdown(void)
|
||||
{
|
||||
delete ms_pCutsceneDir;
|
||||
}
|
||||
|
||||
void
|
||||
CCutsceneMgr::LoadCutsceneData(const char *szCutsceneName)
|
||||
{
|
||||
int file;
|
||||
uint32 size;
|
||||
uint32 offset;
|
||||
CPlayerPed *pPlayerPed;
|
||||
|
||||
ms_cutsceneProcessing = true;
|
||||
if (!strcasecmp(szCutsceneName, "jb"))
|
||||
ms_useLodMultiplier = true;
|
||||
CTimer::Stop();
|
||||
|
||||
ms_pCutsceneDir->numEntries = 0;
|
||||
ms_pCutsceneDir->ReadDirFile("ANIM\\CUTS.DIR");
|
||||
|
||||
CStreaming::RemoveUnusedModelsInLoadedList();
|
||||
CGame::DrasticTidyUpMemory(true);
|
||||
|
||||
strcpy(ms_cutsceneName, szCutsceneName);
|
||||
file = CFileMgr::OpenFile("ANIM\\CUTS.IMG", "rb");
|
||||
|
||||
// Load animations
|
||||
sprintf(gString, "%s.IFP", szCutsceneName);
|
||||
if (ms_pCutsceneDir->FindItem(gString, offset, size)) {
|
||||
CStreaming::MakeSpaceFor(size << 11);
|
||||
CStreaming::ImGonnaUseStreamingMemory();
|
||||
CFileMgr::Seek(file, offset << 11, SEEK_SET);
|
||||
CAnimManager::LoadAnimFile(file, false);
|
||||
ms_cutsceneAssociations.CreateAssociations(szCutsceneName);
|
||||
CStreaming::IHaveUsedStreamingMemory();
|
||||
ms_animLoaded = true;
|
||||
} else {
|
||||
ms_animLoaded = false;
|
||||
}
|
||||
|
||||
// Load camera data
|
||||
sprintf(gString, "%s.DAT", szCutsceneName);
|
||||
if (ms_pCutsceneDir->FindItem(gString, offset, size)) {
|
||||
CFileMgr::Seek(file, offset << 11, SEEK_SET);
|
||||
TheCamera.LoadPathSplines(file);
|
||||
}
|
||||
|
||||
CFileMgr::CloseFile(file);
|
||||
|
||||
if (CGeneral::faststricmp(ms_cutsceneName, "end")) {
|
||||
DMAudio.ChangeMusicMode(MUSICMODE_CUTSCENE);
|
||||
int trackId = FindCutsceneAudioTrackId(szCutsceneName);
|
||||
if (trackId != -1) {
|
||||
printf("Start preload audio %s\n", szCutsceneName);
|
||||
DMAudio.PreloadCutSceneMusic(trackId);
|
||||
printf("End preload audio %s\n", szCutsceneName);
|
||||
}
|
||||
}
|
||||
|
||||
ms_cutsceneTimer = 0.0f;
|
||||
ms_loaded = true;
|
||||
ms_cutsceneOffset = CVector(0.0f, 0.0f, 0.0f);
|
||||
|
||||
pPlayerPed = FindPlayerPed();
|
||||
CTimer::Update();
|
||||
|
||||
pPlayerPed->m_pWanted->ClearQdCrimes();
|
||||
pPlayerPed->bIsVisible = false;
|
||||
pPlayerPed->m_fCurrentStamina = pPlayerPed->m_fMaxStamina;
|
||||
CPad::GetPad(0)->SetDisablePlayerControls(PLAYERCONTROL_CUTSCENE);
|
||||
CWorld::Players[CWorld::PlayerInFocus].MakePlayerSafe(true);
|
||||
}
|
||||
|
||||
void
|
||||
CCutsceneMgr::SetHeadAnim(const char *animName, CObject *pObject)
|
||||
{
|
||||
CCutsceneHead *pCutsceneHead = (CCutsceneHead*)pObject;
|
||||
char szAnim[CUTSCENENAMESIZE * 2];
|
||||
|
||||
sprintf(szAnim, "%s_%s", ms_cutsceneName, animName);
|
||||
pCutsceneHead->PlayAnimation(szAnim);
|
||||
}
|
||||
|
||||
void
|
||||
CCutsceneMgr::FinishCutscene()
|
||||
{
|
||||
CCutsceneMgr::ms_cutsceneTimer = TheCamera.GetCutSceneFinishTime() * 0.001f;
|
||||
TheCamera.FinishCutscene();
|
||||
|
||||
FindPlayerPed()->bIsVisible = true;
|
||||
CWorld::Players[CWorld::PlayerInFocus].MakePlayerSafe(false);
|
||||
}
|
||||
|
||||
void
|
||||
CCutsceneMgr::SetupCutsceneToStart(void)
|
||||
{
|
||||
TheCamera.SetCamCutSceneOffSet(ms_cutsceneOffset);
|
||||
TheCamera.TakeControlWithSpline(JUMP_CUT);
|
||||
TheCamera.SetWideScreenOn();
|
||||
|
||||
ms_cutsceneOffset.z++;
|
||||
|
||||
for (int i = ms_numCutsceneObjs - 1; i >= 0; i--) {
|
||||
assert(RwObjectGetType(ms_pCutsceneObjects[i]->m_rwObject) == rpCLUMP);
|
||||
if (CAnimBlendAssociation *pAnimBlendAssoc = RpAnimBlendClumpGetFirstAssociation((RpClump*)ms_pCutsceneObjects[i]->m_rwObject)) {
|
||||
assert(pAnimBlendAssoc->hierarchy->sequences[0].HasTranslation());
|
||||
ms_pCutsceneObjects[i]->SetPosition(ms_cutsceneOffset + ((KeyFrameTrans*)pAnimBlendAssoc->hierarchy->sequences[0].GetKeyFrame(0))->translation);
|
||||
CWorld::Add(ms_pCutsceneObjects[i]);
|
||||
pAnimBlendAssoc->SetRun();
|
||||
} else {
|
||||
ms_pCutsceneObjects[i]->SetPosition(ms_cutsceneOffset);
|
||||
}
|
||||
}
|
||||
|
||||
CTimer::Update();
|
||||
CTimer::Update();
|
||||
ms_running = true;
|
||||
ms_cutsceneTimer = 0.0f;
|
||||
}
|
||||
|
||||
void
|
||||
CCutsceneMgr::SetCutsceneAnim(const char *animName, CObject *pObject)
|
||||
{
|
||||
CAnimBlendAssociation *pNewAnim;
|
||||
CAnimBlendClumpData *pAnimBlendClumpData;
|
||||
|
||||
assert(RwObjectGetType(pObject->m_rwObject) == rpCLUMP);
|
||||
RpAnimBlendClumpRemoveAllAssociations((RpClump*)pObject->m_rwObject);
|
||||
|
||||
pNewAnim = ms_cutsceneAssociations.CopyAnimation(animName);
|
||||
pNewAnim->SetCurrentTime(0.0f);
|
||||
pNewAnim->flags |= ASSOC_HAS_TRANSLATION;
|
||||
pNewAnim->flags &= ~ASSOC_RUNNING;
|
||||
|
||||
pAnimBlendClumpData = *RPANIMBLENDCLUMPDATA(pObject->m_rwObject);
|
||||
pAnimBlendClumpData->link.Prepend(&pNewAnim->link);
|
||||
}
|
||||
|
||||
CCutsceneHead *
|
||||
CCutsceneMgr::AddCutsceneHead(CObject *pObject, int modelId)
|
||||
{
|
||||
CCutsceneHead *pHead = new CCutsceneHead(pObject);
|
||||
pHead->SetModelIndex(modelId);
|
||||
CWorld::Add(pHead);
|
||||
ms_pCutsceneObjects[ms_numCutsceneObjs++] = pHead;
|
||||
return pHead;
|
||||
}
|
||||
|
||||
CCutsceneObject *
|
||||
CCutsceneMgr::CreateCutsceneObject(int modelId)
|
||||
{
|
||||
CBaseModelInfo *pModelInfo;
|
||||
CColModel *pColModel;
|
||||
float radius;
|
||||
RpClump *clump;
|
||||
CCutsceneObject *pCutsceneObject;
|
||||
|
||||
if (modelId >= MI_CUTOBJ01 && modelId <= MI_CUTOBJ05) {
|
||||
pModelInfo = CModelInfo::GetModelInfo(modelId);
|
||||
pColModel = &CTempColModels::ms_colModelCutObj[modelId - MI_CUTOBJ01];
|
||||
radius = 0.0f;
|
||||
|
||||
pModelInfo->SetColModel(pColModel);
|
||||
clump = (RpClump*)pModelInfo->GetRwObject();
|
||||
assert(RwObjectGetType((RwObject*)clump) == rpCLUMP);
|
||||
RpClumpForAllAtomics(clump, CalculateBoundingSphereRadiusCB, &radius);
|
||||
|
||||
pColModel->boundingSphere.radius = radius;
|
||||
pColModel->boundingBox.min = CVector(-radius, -radius, -radius);
|
||||
pColModel->boundingBox.max = CVector(radius, radius, radius);
|
||||
}
|
||||
|
||||
pCutsceneObject = new CCutsceneObject();
|
||||
pCutsceneObject->SetModelIndex(modelId);
|
||||
ms_pCutsceneObjects[ms_numCutsceneObjs++] = pCutsceneObject;
|
||||
return pCutsceneObject;
|
||||
}
|
||||
|
||||
void
|
||||
CCutsceneMgr::DeleteCutsceneData(void)
|
||||
{
|
||||
if (!ms_loaded) return;
|
||||
|
||||
ms_cutsceneProcessing = false;
|
||||
ms_useLodMultiplier = false;
|
||||
|
||||
for (--ms_numCutsceneObjs; ms_numCutsceneObjs >= 0; ms_numCutsceneObjs--) {
|
||||
CWorld::Remove(ms_pCutsceneObjects[ms_numCutsceneObjs]);
|
||||
ms_pCutsceneObjects[ms_numCutsceneObjs]->DeleteRwObject();
|
||||
delete ms_pCutsceneObjects[ms_numCutsceneObjs];
|
||||
ms_pCutsceneObjects[ms_numCutsceneObjs] = nil;
|
||||
}
|
||||
ms_numCutsceneObjs = 0;
|
||||
|
||||
if (ms_animLoaded)
|
||||
CAnimManager::RemoveLastAnimFile();
|
||||
|
||||
ms_animLoaded = false;
|
||||
TheCamera.RestoreWithJumpCut();
|
||||
TheCamera.SetWideScreenOff();
|
||||
ms_running = false;
|
||||
ms_loaded = false;
|
||||
|
||||
FindPlayerPed()->bIsVisible = true;
|
||||
CPad::GetPad(0)->SetEnablePlayerControls(PLAYERCONTROL_CUTSCENE);
|
||||
CWorld::Players[CWorld::PlayerInFocus].MakePlayerSafe(false);
|
||||
|
||||
if (CGeneral::faststricmp(ms_cutsceneName, "end")) {
|
||||
DMAudio.StopCutSceneMusic();
|
||||
if (CGeneral::faststricmp(ms_cutsceneName, "bet"))
|
||||
DMAudio.ChangeMusicMode(MUSICMODE_GAME);
|
||||
}
|
||||
CTimer::Stop();
|
||||
CGame::DrasticTidyUpMemory(TheCamera.GetScreenFadeStatus() == FADE_2);
|
||||
CTimer::Update();
|
||||
}
|
||||
|
||||
void
|
||||
CCutsceneMgr::Update(void)
|
||||
{
|
||||
enum {
|
||||
CUTSCENE_LOADING_0 = 0,
|
||||
CUTSCENE_LOADING_AUDIO,
|
||||
CUTSCENE_LOADING_2,
|
||||
CUTSCENE_LOADING_3,
|
||||
CUTSCENE_LOADING_4
|
||||
};
|
||||
|
||||
switch (ms_cutsceneLoadStatus) {
|
||||
case CUTSCENE_LOADING_AUDIO:
|
||||
SetupCutsceneToStart();
|
||||
if (CGeneral::faststricmp(ms_cutsceneName, "end"))
|
||||
DMAudio.PlayPreloadedCutSceneMusic();
|
||||
ms_cutsceneLoadStatus++;
|
||||
break;
|
||||
case CUTSCENE_LOADING_2:
|
||||
case CUTSCENE_LOADING_3:
|
||||
ms_cutsceneLoadStatus++;
|
||||
break;
|
||||
case CUTSCENE_LOADING_4:
|
||||
ms_cutsceneLoadStatus = CUTSCENE_LOADING_0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ms_running) return;
|
||||
|
||||
ms_cutsceneTimer += CTimer::GetTimeStepNonClippedInSeconds();
|
||||
if (CGeneral::faststricmp(ms_cutsceneName, "end") && TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FLYBY && ms_cutsceneLoadStatus == CUTSCENE_LOADING_0) {
|
||||
if (CPad::GetPad(0)->GetCrossJustDown()
|
||||
|| (CGame::playingIntro && CPad::GetPad(0)->GetStartJustDown())
|
||||
|| CPad::GetPad(0)->GetLeftMouseJustDown()
|
||||
|| CPad::GetPad(0)->GetEnterJustDown()
|
||||
|| CPad::GetPad(0)->GetCharJustDown(' '))
|
||||
FinishCutscene();
|
||||
}
|
||||
}
|
||||
|
||||
bool CCutsceneMgr::HasCutsceneFinished(void) { return TheCamera.GetPositionAlongSpline() == 1.0f; }
|
||||
|
||||
51
src/animation/CutsceneMgr.h
Normal file
51
src/animation/CutsceneMgr.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#pragma once
|
||||
#include "CutsceneObject.h"
|
||||
|
||||
#define CUTSCENENAMESIZE 8
|
||||
|
||||
class CDirectory;
|
||||
class CAnimBlendAssocGroup;
|
||||
class CCutsceneHead;
|
||||
|
||||
class CCutsceneMgr
|
||||
{
|
||||
static bool ms_running;
|
||||
static CCutsceneObject *ms_pCutsceneObjects[NUMCUTSCENEOBJECTS];
|
||||
|
||||
static int32 ms_numCutsceneObjs;
|
||||
static bool ms_loaded;
|
||||
static bool ms_animLoaded;
|
||||
static bool ms_useLodMultiplier;
|
||||
|
||||
static char ms_cutsceneName[CUTSCENENAMESIZE];
|
||||
static CAnimBlendAssocGroup ms_cutsceneAssociations;
|
||||
static CVector ms_cutsceneOffset;
|
||||
static float ms_cutsceneTimer;
|
||||
static bool ms_cutsceneProcessing;
|
||||
public:
|
||||
static CDirectory *ms_pCutsceneDir;
|
||||
static uint32 ms_cutsceneLoadStatus;
|
||||
|
||||
static void StartCutsceneProcessing() { ms_cutsceneProcessing = true; }
|
||||
static bool IsRunning(void) { return ms_running; }
|
||||
static bool HasLoaded(void) { return ms_loaded; }
|
||||
static bool IsCutsceneProcessing(void) { return ms_cutsceneProcessing; }
|
||||
static bool UseLodMultiplier(void) { return ms_useLodMultiplier; }
|
||||
static CCutsceneObject* GetCutsceneObject(int id) { return ms_pCutsceneObjects[id]; }
|
||||
static int GetCutsceneTimeInMilleseconds(void) { return 1000.0f * ms_cutsceneTimer; }
|
||||
static char *GetCutsceneName(void) { return ms_cutsceneName; }
|
||||
static void SetCutsceneOffset(const CVector& vec) { ms_cutsceneOffset = vec; }
|
||||
static bool HasCutsceneFinished(void);
|
||||
|
||||
static void Initialise(void);
|
||||
static void Shutdown(void);
|
||||
static void LoadCutsceneData(const char *szCutsceneName);
|
||||
static void FinishCutscene(void);
|
||||
static void SetHeadAnim(const char *animName, CObject *pObject);
|
||||
static void SetupCutsceneToStart(void);
|
||||
static void SetCutsceneAnim(const char *animName, CObject *pObject);
|
||||
static CCutsceneHead *AddCutsceneHead(CObject *pObject, int modelId);
|
||||
static CCutsceneObject *CreateCutsceneObject(int modelId);
|
||||
static void DeleteCutsceneData(void);
|
||||
static void Update(void);
|
||||
};
|
||||
445
src/animation/FrameUpdate.cpp
Normal file
445
src/animation/FrameUpdate.cpp
Normal file
|
|
@ -0,0 +1,445 @@
|
|||
#include "common.h"
|
||||
|
||||
#include "NodeName.h"
|
||||
#include "VisibilityPlugins.h"
|
||||
#include "AnimBlendClumpData.h"
|
||||
#include "AnimBlendAssociation.h"
|
||||
#include "RpAnimBlend.h"
|
||||
|
||||
CAnimBlendClumpData *gpAnimBlendClump;
|
||||
|
||||
// PS2 names without "NonSkinned"
|
||||
void FrameUpdateCallBackNonSkinned(AnimBlendFrameData *frame, void *arg);
|
||||
void FrameUpdateCallBackWithVelocityExtractionNonSkinned(AnimBlendFrameData *frame, void *arg);
|
||||
void FrameUpdateCallBackWith3dVelocityExtractionNonSkinned(AnimBlendFrameData *frame, void *arg);
|
||||
|
||||
void FrameUpdateCallBackSkinned(AnimBlendFrameData *frame, void *arg);
|
||||
void FrameUpdateCallBackWithVelocityExtractionSkinned(AnimBlendFrameData *frame, void *arg);
|
||||
void FrameUpdateCallBackWith3dVelocityExtractionSkinned(AnimBlendFrameData *frame, void *arg);
|
||||
|
||||
|
||||
void
|
||||
FrameUpdateCallBackNonSkinned(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->velocity2d){
|
||||
if(frame->flag & AnimBlendFrameData::VELOCITY_EXTRACTION_3D)
|
||||
FrameUpdateCallBackWith3dVelocityExtractionNonSkinned(frame, arg);
|
||||
else
|
||||
FrameUpdateCallBackWithVelocityExtractionNonSkinned(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;
|
||||
#ifdef FIX_BUGS
|
||||
if(DotProduct(rot, q) < 0.0f)
|
||||
rot -= q;
|
||||
else
|
||||
#endif
|
||||
rot += q;
|
||||
}
|
||||
++*node;
|
||||
}
|
||||
|
||||
if((frame->flag & AnimBlendFrameData::IGNORE_ROTATION) == 0){
|
||||
RwMatrixSetIdentity(mat);
|
||||
rot.Normalise();
|
||||
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
|
||||
FrameUpdateCallBackWithVelocityExtractionNonSkinned(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);
|
||||
#ifdef FIX_BUGS
|
||||
if(DotProduct(rot, q) < 0.0f)
|
||||
rot -= q;
|
||||
else
|
||||
#endif
|
||||
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);
|
||||
rot.Normalise();
|
||||
rot.Get(mat);
|
||||
}
|
||||
|
||||
if((frame->flag & AnimBlendFrameData::IGNORE_TRANSLATION) == 0){
|
||||
gpAnimBlendClump->velocity2d->x = transx - curx;
|
||||
gpAnimBlendClump->velocity2d->y = transy - cury;
|
||||
if(looped){
|
||||
gpAnimBlendClump->velocity2d->x += endx;
|
||||
gpAnimBlendClump->velocity2d->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
|
||||
FrameUpdateCallBackWith3dVelocityExtractionNonSkinned(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);
|
||||
#ifdef FIX_BUGS
|
||||
if(DotProduct(rot, q) < 0.0f)
|
||||
rot -= q;
|
||||
else
|
||||
#endif
|
||||
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);
|
||||
rot.Normalise();
|
||||
rot.Get(mat);
|
||||
}
|
||||
|
||||
if((frame->flag & AnimBlendFrameData::IGNORE_TRANSLATION) == 0){
|
||||
*gpAnimBlendClump->velocity3d = trans - cur;
|
||||
if(looped)
|
||||
*gpAnimBlendClump->velocity3d += 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);
|
||||
}
|
||||
|
||||
#ifdef PED_SKIN
|
||||
|
||||
void
|
||||
FrameUpdateCallBackSkinned(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;
|
||||
RpHAnimStdInterpFrame *xform = frame->hanimFrame;
|
||||
CAnimBlendNode **node;
|
||||
AnimBlendFrameUpdateData *updateData = (AnimBlendFrameUpdateData*)arg;
|
||||
|
||||
if(frame->flag & AnimBlendFrameData::VELOCITY_EXTRACTION &&
|
||||
gpAnimBlendClump->velocity2d){
|
||||
if(frame->flag & AnimBlendFrameData::VELOCITY_EXTRACTION_3D)
|
||||
FrameUpdateCallBackWith3dVelocityExtractionSkinned(frame, arg);
|
||||
else
|
||||
FrameUpdateCallBackWithVelocityExtractionSkinned(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;
|
||||
#ifdef FIX_BUGS
|
||||
if(DotProduct(rot, q) < 0.0f)
|
||||
rot -= q;
|
||||
else
|
||||
#endif
|
||||
rot += q;
|
||||
}
|
||||
++*node;
|
||||
}
|
||||
|
||||
if((frame->flag & AnimBlendFrameData::IGNORE_ROTATION) == 0){
|
||||
rot.Normalise();
|
||||
xform->q.imag.x = rot.x;
|
||||
xform->q.imag.y = rot.y;
|
||||
xform->q.imag.z = rot.z;
|
||||
xform->q.real = rot.w;
|
||||
}
|
||||
|
||||
if((frame->flag & AnimBlendFrameData::IGNORE_TRANSLATION) == 0){
|
||||
xform->t.x = pos.x;
|
||||
xform->t.y = pos.y;
|
||||
xform->t.z = pos.z;
|
||||
xform->t.x += frame->resetPos.x;
|
||||
xform->t.y += frame->resetPos.y;
|
||||
xform->t.z += frame->resetPos.z;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FrameUpdateCallBackWithVelocityExtractionSkinned(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;
|
||||
RpHAnimStdInterpFrame *xform = frame->hanimFrame;
|
||||
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);
|
||||
#ifdef FIX_BUGS
|
||||
if(DotProduct(rot, q) < 0.0f)
|
||||
rot -= q;
|
||||
else
|
||||
#endif
|
||||
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){
|
||||
rot.Normalise();
|
||||
xform->q.imag.x = rot.x;
|
||||
xform->q.imag.y = rot.y;
|
||||
xform->q.imag.z = rot.z;
|
||||
xform->q.real = rot.w;
|
||||
}
|
||||
|
||||
if((frame->flag & AnimBlendFrameData::IGNORE_TRANSLATION) == 0){
|
||||
gpAnimBlendClump->velocity2d->x = transx - curx;
|
||||
gpAnimBlendClump->velocity2d->y = transy - cury;
|
||||
if(looped){
|
||||
gpAnimBlendClump->velocity2d->x += endx;
|
||||
gpAnimBlendClump->velocity2d->y += endy;
|
||||
}
|
||||
xform->t.x = pos.x - transx;
|
||||
xform->t.y = pos.y - transy;
|
||||
xform->t.z = pos.z;
|
||||
if(xform->t.z >= -0.8f) {
|
||||
if(xform->t.z < -0.4f)
|
||||
xform->t.z += (2.5f * xform->t.z + 2.0f) * frame->resetPos.z;
|
||||
else
|
||||
xform->t.z += frame->resetPos.z;
|
||||
}
|
||||
xform->t.x += frame->resetPos.x;
|
||||
xform->t.y += frame->resetPos.y;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FrameUpdateCallBackWith3dVelocityExtractionSkinned(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;
|
||||
RpHAnimStdInterpFrame *xform = frame->hanimFrame;
|
||||
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);
|
||||
#ifdef FIX_BUGS
|
||||
if(DotProduct(rot, q) < 0.0f)
|
||||
rot -= q;
|
||||
else
|
||||
#endif
|
||||
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){
|
||||
rot.Normalise();
|
||||
xform->q.imag.x = rot.x;
|
||||
xform->q.imag.y = rot.y;
|
||||
xform->q.imag.z = rot.z;
|
||||
xform->q.real = rot.w;
|
||||
}
|
||||
|
||||
if((frame->flag & AnimBlendFrameData::IGNORE_TRANSLATION) == 0){
|
||||
*gpAnimBlendClump->velocity3d = trans - cur;
|
||||
if(looped)
|
||||
*gpAnimBlendClump->velocity3d += end;
|
||||
xform->t.x = (pos - trans).x + frame->resetPos.x;
|
||||
xform->t.y = (pos - trans).y + frame->resetPos.y;
|
||||
xform->t.z = (pos - trans).z + frame->resetPos.z;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
469
src/animation/RpAnimBlend.cpp
Normal file
469
src/animation/RpAnimBlend.cpp
Normal file
|
|
@ -0,0 +1,469 @@
|
|||
#include "common.h"
|
||||
|
||||
#include "RwHelper.h"
|
||||
#include "General.h"
|
||||
#include "NodeName.h"
|
||||
#include "VisibilityPlugins.h"
|
||||
#include "Bones.h"
|
||||
#include "AnimBlendClumpData.h"
|
||||
#include "AnimBlendHierarchy.h"
|
||||
#include "AnimBlendAssociation.h"
|
||||
#include "AnimManager.h"
|
||||
#include "RpAnimBlend.h"
|
||||
#ifdef PED_SKIN
|
||||
#include "PedModelInfo.h"
|
||||
#endif
|
||||
|
||||
RwInt32 ClumpOffset;
|
||||
|
||||
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)
|
||||
return 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;
|
||||
}
|
||||
|
||||
// FrameInitCallBack on PS2
|
||||
void
|
||||
FrameInitCBnonskin(AnimBlendFrameData *frameData, void*)
|
||||
{
|
||||
frameData->flag = 0;
|
||||
frameData->resetPos = *RwMatrixGetPos(RwFrameGetMatrix(frameData->frame));
|
||||
}
|
||||
|
||||
void
|
||||
FrameInitCBskin(AnimBlendFrameData *frameData, void*)
|
||||
{
|
||||
frameData->flag = 0;
|
||||
}
|
||||
|
||||
#ifdef PED_SKIN
|
||||
void
|
||||
RpAnimBlendClumpInitSkinned(RpClump *clump)
|
||||
{
|
||||
int i;
|
||||
RwV3d boneTab[64];
|
||||
CAnimBlendClumpData *clumpData;
|
||||
RpAtomic *atomic;
|
||||
RpSkin *skin;
|
||||
RpHAnimHierarchy *hier;
|
||||
int numBones;
|
||||
|
||||
RpAnimBlendAllocateData(clump);
|
||||
clumpData = *RPANIMBLENDCLUMPDATA(clump);
|
||||
atomic = IsClumpSkinned(clump);
|
||||
assert(atomic);
|
||||
skin = RpSkinGeometryGetSkin(RpAtomicGetGeometry(atomic));
|
||||
assert(skin);
|
||||
numBones = RpSkinGetNumBones(skin);
|
||||
clumpData->SetNumberOfBones(numBones);
|
||||
hier = GetAnimHierarchyFromSkinClump(clump);
|
||||
assert(hier);
|
||||
memset(boneTab, 0, sizeof(boneTab));
|
||||
SkinGetBonePositionsToTable(clump, boneTab);
|
||||
|
||||
AnimBlendFrameData *frames = clumpData->frames;
|
||||
for(i = 0; i < numBones; i++){
|
||||
frames[i].nodeID = HIERNODEID(hier, i);
|
||||
frames[i].resetPos = boneTab[i];
|
||||
frames[i].hanimFrame = (RpHAnimStdInterpFrame*)rpHANIMHIERARCHYGETINTERPFRAME(hier, i);
|
||||
}
|
||||
clumpData->ForAllFrames(FrameInitCBskin, nil);
|
||||
clumpData->frames[0].flag |= AnimBlendFrameData::VELOCITY_EXTRACTION;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
RpAnimBlendClumpInitNotSkinned(RpClump *clump)
|
||||
{
|
||||
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(FrameInitCBnonskin, nil);
|
||||
clumpData->frames[0].flag |= AnimBlendFrameData::VELOCITY_EXTRACTION;
|
||||
}
|
||||
|
||||
void
|
||||
RpAnimBlendClumpInit(RpClump *clump)
|
||||
{
|
||||
#ifdef PED_SKIN
|
||||
if(IsClumpSkinned(clump))
|
||||
RpAnimBlendClumpInitSkinned(clump);
|
||||
else
|
||||
#endif
|
||||
RpAnimBlendClumpInitNotSkinned(clump);
|
||||
}
|
||||
|
||||
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.0f;
|
||||
float secondBlend = 0.0f;
|
||||
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.0f;
|
||||
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(!RpAnimBlendClumpIsInitialized(clump))
|
||||
return nil;
|
||||
if(clumpData->link.next)
|
||||
return CAnimBlendAssociation::FromLink(clumpData->link.next);
|
||||
return nil;
|
||||
}
|
||||
|
||||
// FillFrameArrayCallBack on PS2
|
||||
void
|
||||
FillFrameArrayCBnonskin(AnimBlendFrameData *frame, void *arg)
|
||||
{
|
||||
AnimBlendFrameData **frames = (AnimBlendFrameData**)arg;
|
||||
frames[CVisibilityPlugins::GetFrameHierarchyId(frame->frame)] = frame;
|
||||
}
|
||||
|
||||
#ifdef PED_SKIN
|
||||
void
|
||||
RpAnimBlendClumpFillFrameArraySkin(RpClump *clump, AnimBlendFrameData **frames)
|
||||
{
|
||||
int i;
|
||||
CAnimBlendClumpData *clumpData = *RPANIMBLENDCLUMPDATA(clump);
|
||||
RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(clump);
|
||||
for(i = PED_MID; i < PED_NODE_MAX; i++)
|
||||
frames[i] = &clumpData->frames[RpHAnimIDGetIndex(hier, ConvertPedNode2BoneTag(i))];
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
RpAnimBlendClumpFillFrameArray(RpClump *clump, AnimBlendFrameData **frames)
|
||||
{
|
||||
#ifdef PED_SKIN
|
||||
if(IsClumpSkinned(clump))
|
||||
RpAnimBlendClumpFillFrameArraySkin(clump, frames);
|
||||
else
|
||||
#endif
|
||||
(*RPANIMBLENDCLUMPDATA(clump))->ForAllFrames(FillFrameArrayCBnonskin, frames);
|
||||
}
|
||||
|
||||
AnimBlendFrameData *pFrameDataFound;
|
||||
|
||||
// FrameFindCallBack on PS2
|
||||
void
|
||||
FrameFindByNameCBnonskin(AnimBlendFrameData *frame, void *arg)
|
||||
{
|
||||
char *nodename = GetFrameNodeName(frame->frame);
|
||||
if(!CGeneral::faststricmp(nodename, (char*)arg))
|
||||
pFrameDataFound = frame;
|
||||
}
|
||||
|
||||
#ifdef PED_SKIN
|
||||
void
|
||||
FrameFindByNameCBskin(AnimBlendFrameData *frame, void *arg)
|
||||
{
|
||||
const char *name = ConvertBoneTag2BoneName(frame->nodeID);
|
||||
if(name && CGeneral::faststricmp(name, (char*)arg) == 0)
|
||||
pFrameDataFound = frame;
|
||||
}
|
||||
#endif
|
||||
|
||||
AnimBlendFrameData*
|
||||
RpAnimBlendClumpFindFrame(RpClump *clump, const char *name)
|
||||
{
|
||||
pFrameDataFound = nil;
|
||||
#ifdef PED_SKIN
|
||||
if(IsClumpSkinned(clump))
|
||||
(*RPANIMBLENDCLUMPDATA(clump))->ForAllFrames(FrameFindByNameCBskin, (void*)name);
|
||||
else
|
||||
#endif
|
||||
(*RPANIMBLENDCLUMPDATA(clump))->ForAllFrames(FrameFindByNameCBnonskin, (void*)name);
|
||||
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(assoc->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] = nil;
|
||||
|
||||
#ifdef PED_SKIN
|
||||
if(IsClumpSkinned(clump))
|
||||
clumpData->ForAllFrames(FrameUpdateCallBackSkinned, &updateData);
|
||||
else
|
||||
#endif
|
||||
clumpData->ForAllFrames(FrameUpdateCallBackNonSkinned, &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));
|
||||
}
|
||||
42
src/animation/RpAnimBlend.h
Normal file
42
src/animation/RpAnimBlend.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
|
||||
class CAnimBlendNode;
|
||||
class CAnimBlendAssociation;
|
||||
class CAnimBlendClumpData;
|
||||
struct AnimBlendFrameData;
|
||||
|
||||
struct AnimBlendFrameUpdateData
|
||||
{
|
||||
int foobar; // TODO: figure out what this actually means
|
||||
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);
|
||||
void RpAnimBlendClumpFillFrameArray(RpClump* clump, AnimBlendFrameData** frames);
|
||||
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);
|
||||
void RpAnimBlendClumpUpdateAnimations(RpClump* clump, float timeDelta);
|
||||
|
||||
|
||||
extern CAnimBlendClumpData *gpAnimBlendClump;
|
||||
void FrameUpdateCallBackNonSkinned(AnimBlendFrameData *frame, void *arg);
|
||||
void FrameUpdateCallBackSkinned(AnimBlendFrameData *frame, void *arg);
|
||||
Loading…
Add table
Add a link
Reference in a new issue