Merge remote-tracking branch 'upstream/miami' into miami

This commit is contained in:
Nikolay Korolev 2020-05-08 17:06:25 +03:00
commit 756e4dd068
27 changed files with 497 additions and 229 deletions

View File

@ -3,16 +3,23 @@
#include "ctype.h" #include "ctype.h"
#include "General.h" #include "General.h"
#include "RwHelper.h"
#include "ModelIndices.h"
#include "ModelInfo.h" #include "ModelInfo.h"
#include "AnimManager.h" #include "AnimManager.h"
#include "RpAnimBlend.h" #include "RpAnimBlend.h"
#include "AnimBlendAssociation.h" #include "AnimBlendAssociation.h"
#include "AnimBlendAssocGroup.h" #include "AnimBlendAssocGroup.h"
//--MIAMI: file done
CAnimBlendAssocGroup::CAnimBlendAssocGroup(void) CAnimBlendAssocGroup::CAnimBlendAssocGroup(void)
{ {
animBlock = nil;
assocList = nil; assocList = nil;
numAssociations = 0; numAssociations = 0;
firstAnimId = 0;
groupId = -1;
} }
CAnimBlendAssocGroup::~CAnimBlendAssocGroup(void) CAnimBlendAssocGroup::~CAnimBlendAssocGroup(void)
@ -43,6 +50,7 @@ CAnimBlendAssocGroup::GetAnimation(const char *name)
for(i = 0; i < numAssociations; i++) for(i = 0; i < numAssociations; i++)
if(!CGeneral::faststricmp(assocList[i].hierarchy->name, name)) if(!CGeneral::faststricmp(assocList[i].hierarchy->name, name))
return &assocList[i]; return &assocList[i];
debug("\n\nCan't find the fucking animation %s\n\n\n", name);
return nil; return nil;
} }
@ -102,6 +110,15 @@ GetModelFromName(const char *name)
{ {
int i; int i;
CBaseModelInfo *mi; CBaseModelInfo *mi;
char playername[32];
if(strncasecmp(name, "CSplay", 6) == 0 &&
strncasecmp(CModelInfo::GetModelInfo(MI_PLAYER)->GetName(), "ig", 2) == 0){
strcpy(playername, CModelInfo::GetModelInfo(MI_PLAYER)->GetName());
playername[0] = 'C';
playername[1] = 'S';
name = playername;
}
for(i = 0; i < MODELINFOSIZE; i++){ for(i = 0; i < MODELINFOSIZE; i++){
mi = CModelInfo::GetModelInfo(i); mi = CModelInfo::GetModelInfo(i);
@ -118,8 +135,7 @@ CAnimBlendAssocGroup::CreateAssociations(const char *name)
int i; int i;
CAnimBlock *animBlock; CAnimBlock *animBlock;
if(assocList) DestroyAssociations();
DestroyAssociations();
animBlock = CAnimManager::GetAnimationBlock(name); animBlock = CAnimManager::GetAnimationBlock(name);
assocList = new CAnimBlendAssociation[animBlock->numAnims]; assocList = new CAnimBlendAssociation[animBlock->numAnims];
@ -128,13 +144,18 @@ CAnimBlendAssocGroup::CreateAssociations(const char *name)
for(i = 0; i < animBlock->numAnims; i++){ for(i = 0; i < animBlock->numAnims; i++){
CAnimBlendHierarchy *anim = CAnimManager::GetAnimation(animBlock->firstIndex + i); CAnimBlendHierarchy *anim = CAnimManager::GetAnimation(animBlock->firstIndex + i);
CBaseModelInfo *model = GetModelFromName(anim->name); CBaseModelInfo *model = GetModelFromName(anim->name);
assert(model); if(model){
printf("Associated anim %s with model %s\n", anim->name, model->GetName()); debug("Associated anim %s with model %s\n", anim->name, model->GetName());
RpClump *clump = (RpClump*)model->CreateInstance(); RpClump *clump = (RpClump*)model->CreateInstance();
RpAnimBlendClumpInit(clump); RpAnimBlendClumpInit(clump);
assocList[i].Init(clump, anim); assocList[i].Init(clump, anim);
RpClumpDestroy(clump); if(IsClumpSkinned(clump))
assocList[i].animId = i; RpClumpForAllAtomics(clump, AtomicRemoveAnimFromSkinCB, nil);
RpClumpDestroy(clump);
assocList[i].animId = firstAnimId + i;
assocList[i].groupId = groupId;
}else
debug("\n\nCANNOT FIND MODELINFO WITH NAME %s\n\n\n", anim->name);
} }
numAssociations = animBlock->numAnims; numAssociations = animBlock->numAnims;
} }
@ -144,10 +165,8 @@ void
CAnimBlendAssocGroup::CreateAssociations(const char *blockName, RpClump *clump, const char **animNames, int numAssocs) CAnimBlendAssocGroup::CreateAssociations(const char *blockName, RpClump *clump, const char **animNames, int numAssocs)
{ {
int i; int i;
CAnimBlock *animBlock;
if(assocList) DestroyAssociations();
DestroyAssociations();
animBlock = CAnimManager::GetAnimationBlock(blockName); animBlock = CAnimManager::GetAnimationBlock(blockName);
assocList = new CAnimBlendAssociation[numAssocs]; assocList = new CAnimBlendAssociation[numAssocs];
@ -155,7 +174,8 @@ CAnimBlendAssocGroup::CreateAssociations(const char *blockName, RpClump *clump,
numAssociations = 0; numAssociations = 0;
for(i = 0; i < numAssocs; i++){ for(i = 0; i < numAssocs; i++){
assocList[i].Init(clump, CAnimManager::GetAnimation(animNames[i], animBlock)); assocList[i].Init(clump, CAnimManager::GetAnimation(animNames[i], animBlock));
assocList[i].animId = i; assocList[i].animId = firstAnimId + i;
assocList[i].groupId = groupId;
} }
numAssociations = numAssocs; numAssociations = numAssocs;
} }

View File

@ -1,12 +1,16 @@
#pragma once #pragma once
class CAnimBlendAssociation; class CAnimBlendAssociation;
struct CAnimBlock;
class CAnimBlendAssocGroup class CAnimBlendAssocGroup
{ {
public: public:
CAnimBlock *animBlock;
CAnimBlendAssociation *assocList; CAnimBlendAssociation *assocList;
int32 numAssociations; int32 numAssociations;
int32 firstAnimId;
int32 groupId; // id of self in ms_aAnimAssocGroups
CAnimBlendAssocGroup(void); CAnimBlendAssocGroup(void);
~CAnimBlendAssocGroup(void); ~CAnimBlendAssocGroup(void);

View File

@ -7,8 +7,11 @@
#include "AnimBlendAssociation.h" #include "AnimBlendAssociation.h"
#include "RwHelper.h" #include "RwHelper.h"
//--MIAMI: file done except for one TODO
CAnimBlendAssociation::CAnimBlendAssociation(void) CAnimBlendAssociation::CAnimBlendAssociation(void)
{ {
groupId = -1;
nodes = nil; nodes = nil;
blendAmount = 1.0f; blendAmount = 1.0f;
blendDelta = 0.0f; blendDelta = 0.0f;
@ -54,8 +57,8 @@ CAnimBlendAssociation::AllocateAnimBlendNodeArray(int n)
void void
CAnimBlendAssociation::FreeAnimBlendNodeArray(void) CAnimBlendAssociation::FreeAnimBlendNodeArray(void)
{ {
assert(nodes != nil); if(nodes)
RwFreeAlign(nodes); RwFreeAlign(nodes);
} }
void void
@ -75,7 +78,10 @@ CAnimBlendAssociation::Init(RpClump *clump, CAnimBlendHierarchy *hier)
// NB: This is where the order of nodes is defined // NB: This is where the order of nodes is defined
for(i = 0; i < hier->numSequences; i++){ for(i = 0; i < hier->numSequences; i++){
CAnimBlendSequence *seq = &hier->sequences[i]; CAnimBlendSequence *seq = &hier->sequences[i];
frame = RpAnimBlendClumpFindFrame(clump, seq->name); if(seq->boneTag == -1)
frame = RpAnimBlendClumpFindFrame(clump, seq->name);
else
frame = RpAnimBlendClumpFindBone(clump, seq->boneTag);
if(frame && seq->numFrames > 0) if(frame && seq->numFrames > 0)
nodes[frame - clumpData->frames].sequence = seq; nodes[frame - clumpData->frames].sequence = seq;
} }
@ -90,6 +96,7 @@ CAnimBlendAssociation::Init(CAnimBlendAssociation &assoc)
numNodes = assoc.numNodes; numNodes = assoc.numNodes;
flags = assoc.flags; flags = assoc.flags;
animId = assoc.animId; animId = assoc.animId;
groupId = assoc.groupId;
AllocateAnimBlendNodeArray(numNodes); AllocateAnimBlendNodeArray(numNodes);
for(i = 0; i < numNodes; i++){ for(i = 0; i < numNodes; i++){
nodes[i] = assoc.nodes[i]; nodes[i] = assoc.nodes[i];
@ -129,9 +136,15 @@ CAnimBlendAssociation::SetCurrentTime(float time)
if(!IsRepeating()) if(!IsRepeating())
return; return;
CAnimManager::UncompressAnimation(hierarchy); CAnimManager::UncompressAnimation(hierarchy);
for(i = 0; i < numNodes; i++) if(hierarchy->compressed2){
if(nodes[i].sequence) for(i = 0; i < numNodes; i++)
nodes[i].FindKeyFrame(currentTime); if(nodes[i].sequence)
nodes[i].SetupKeyFrameCompressed();
}else{
for(i = 0; i < numNodes; i++)
if(nodes[i].sequence)
nodes[i].FindKeyFrame(currentTime);
}
} }
void void
@ -146,14 +159,20 @@ CAnimBlendAssociation::Start(float time)
flags |= ASSOC_RUNNING; flags |= ASSOC_RUNNING;
SetCurrentTime(time); SetCurrentTime(time);
} }
bool
void
CAnimBlendAssociation::UpdateTime(float timeDelta, float relSpeed) CAnimBlendAssociation::UpdateTime(float timeDelta, float relSpeed)
{ {
if(!IsRunning()) if(!IsRunning())
return; return true;
if(currentTime >= hierarchy->totalLength){
flags &= ~ASSOC_RUNNING;
return true;
}
// TODO(MIAMI): we still need this for some reason
#ifndef NOT_YET
timeStep = (flags & ASSOC_MOVEMENT ? relSpeed*hierarchy->totalLength : speed) * timeDelta; timeStep = (flags & ASSOC_MOVEMENT ? relSpeed*hierarchy->totalLength : speed) * timeDelta;
#endif
currentTime += timeStep; currentTime += timeStep;
if(currentTime >= hierarchy->totalLength){ if(currentTime >= hierarchy->totalLength){
@ -163,7 +182,6 @@ CAnimBlendAssociation::UpdateTime(float timeDelta, float relSpeed)
currentTime -= hierarchy->totalLength; currentTime -= hierarchy->totalLength;
else{ else{
currentTime = hierarchy->totalLength; currentTime = hierarchy->totalLength;
flags &= ~ASSOC_RUNNING;
if(flags & ASSOC_FADEOUTWHENDONE){ if(flags & ASSOC_FADEOUTWHENDONE){
flags |= ASSOC_DELETEFADEDOUT; flags |= ASSOC_DELETEFADEDOUT;
blendDelta = -4.0f; blendDelta = -4.0f;
@ -174,6 +192,7 @@ CAnimBlendAssociation::UpdateTime(float timeDelta, float relSpeed)
} }
} }
} }
return true;
} }
// return whether we still exist after this function // return whether we still exist after this function

View File

@ -37,7 +37,8 @@ public:
CAnimBlendLink link; CAnimBlendLink link;
int numNodes; // taken from CAnimBlendClumpData::numFrames int16 numNodes; // taken from CAnimBlendClumpData::numFrames
int16 groupId; // ID of CAnimBlendAssocGroup this is in
// NB: Order of these depends on order of nodes in Clump this was built from // NB: Order of these depends on order of nodes in Clump this was built from
CAnimBlendNode *nodes; CAnimBlendNode *nodes;
CAnimBlendHierarchy *hierarchy; CAnimBlendHierarchy *hierarchy;
@ -46,8 +47,8 @@ public:
float currentTime; float currentTime;
float speed; float speed;
float timeStep; float timeStep;
int32 animId; int16 animId;
int32 flags; int16 flags;
int32 callbackType; int32 callbackType;
void (*callback)(CAnimBlendAssociation*, void*); void (*callback)(CAnimBlendAssociation*, void*);
void *callbackArg; void *callbackArg;
@ -75,7 +76,7 @@ public:
void SetCurrentTime(float time); void SetCurrentTime(float time);
void SyncAnimation(CAnimBlendAssociation *other); void SyncAnimation(CAnimBlendAssociation *other);
void Start(float time); void Start(float time);
void UpdateTime(float timeDelta, float relSpeed); bool UpdateTime(float timeDelta, float relSpeed);
bool UpdateBlend(float timeDelta); bool UpdateBlend(float timeDelta);
void SetRun(void) { flags |= ASSOC_RUNNING; } void SetRun(void) { flags |= ASSOC_RUNNING; }
@ -86,4 +87,3 @@ public:
return (CAnimBlendAssociation*)((uint8*)l - offsetof(CAnimBlendAssociation, link)); return (CAnimBlendAssociation*)((uint8*)l - offsetof(CAnimBlendAssociation, link));
} }
}; };
static_assert(sizeof(CAnimBlendAssociation) == 0x40, "CAnimBlendAssociation: error");

View File

@ -3,6 +3,7 @@
#include "AnimBlendClumpData.h" #include "AnimBlendClumpData.h"
#include "RwHelper.h" #include "RwHelper.h"
//--MIAMI: file done
CAnimBlendClumpData::CAnimBlendClumpData(void) CAnimBlendClumpData::CAnimBlendClumpData(void)
{ {

View File

@ -35,9 +35,6 @@ class CAnimBlendClumpData
public: public:
CAnimBlendLink link; CAnimBlendLink link;
int32 numFrames; int32 numFrames;
#ifdef PED_SKIN
int32 modelNumber; // doesn't seem to be used
#endif
CVector *velocity; CVector *velocity;
// order of frames is determined by RW hierarchy // order of frames is determined by RW hierarchy
AnimBlendFrameData *frames; AnimBlendFrameData *frames;
@ -50,6 +47,3 @@ public:
#endif #endif
void ForAllFrames(void (*cb)(AnimBlendFrameData*, void*), void *arg); void ForAllFrames(void (*cb)(AnimBlendFrameData*, void*), void *arg);
}; };
#ifndef PED_SKIN
static_assert(sizeof(CAnimBlendClumpData) == 0x14, "CAnimBlendClumpData: error");
#endif

View File

@ -2,6 +2,9 @@
#include "AnimBlendSequence.h" #include "AnimBlendSequence.h"
#include "AnimBlendHierarchy.h" #include "AnimBlendHierarchy.h"
#include "AnimManager.h"
//--MIAMI: file done
CAnimBlendHierarchy::CAnimBlendHierarchy(void) CAnimBlendHierarchy::CAnimBlendHierarchy(void)
{ {
@ -15,9 +18,10 @@ CAnimBlendHierarchy::CAnimBlendHierarchy(void)
void void
CAnimBlendHierarchy::Shutdown(void) CAnimBlendHierarchy::Shutdown(void)
{ {
CAnimManager::RemoveFromUncompressedCache(this);
RemoveAnimSequences(); RemoveAnimSequences();
totalLength = 0.0f;
compressed = 0; compressed = 0;
linkPtr = nil;
} }
void void
@ -30,15 +34,44 @@ void
CAnimBlendHierarchy::CalcTotalTime(void) CAnimBlendHierarchy::CalcTotalTime(void)
{ {
int i, j; int i, j;
float totalTime = 0.0f;
totalLength = 0.0f;
for(i = 0; i < numSequences; i++){ for(i = 0; i < numSequences; i++){
float seqTime = 0.0f; #ifdef FIX_BUGS
for(j = 0; j < sequences[i].numFrames; j++) if(sequences[i].numFrames == 0)
seqTime += sequences[i].GetKeyFrame(j)->deltaTime; continue;
totalTime = Max(totalTime, seqTime); #endif
totalLength = Max(totalLength, sequences[i].GetKeyFrame(sequences[i].numFrames-1)->deltaTime);
for(j = sequences[i].numFrames-1; j > 0; j--){
KeyFrame *kf1 = sequences[i].GetKeyFrame(j);
KeyFrame *kf2 = sequences[i].GetKeyFrame(j-1);
kf1->deltaTime -= kf2->deltaTime;
}
}
}
void
CAnimBlendHierarchy::CalcTotalTimeCompressed(void)
{
int i, j;
totalLength = 0.0f;
for(i = 0; i < numSequences; i++){
#ifdef FIX_BUGS
if(sequences[i].numFrames == 0)
continue;
#endif
totalLength = Max(totalLength, sequences[i].GetKeyFrameCompressed(sequences[i].numFrames-1)->deltaTime/60.0f);
for(j = sequences[i].numFrames-1; j > 0; j--){
KeyFrame *kf1 = sequences[i].GetKeyFrameCompressed(j);
KeyFrame *kf2 = sequences[i].GetKeyFrameCompressed(j-1);
kf1->deltaTime -= kf2->deltaTime;
}
} }
totalLength = totalTime;
} }
void void
@ -53,17 +86,19 @@ CAnimBlendHierarchy::RemoveQuaternionFlips(void)
void void
CAnimBlendHierarchy::RemoveAnimSequences(void) CAnimBlendHierarchy::RemoveAnimSequences(void)
{ {
if(sequences) delete[] sequences;
delete[] sequences; sequences = nil;
numSequences = 0; numSequences = 0;
} }
void void
CAnimBlendHierarchy::Uncompress(void) CAnimBlendHierarchy::Uncompress(void)
{ {
if(totalLength == 0.0f)
CalcTotalTime();
compressed = 0; compressed = 0;
if(totalLength == 0.0f){
RemoveQuaternionFlips();
CalcTotalTime();
}
} }
void void

View File

@ -11,7 +11,8 @@ public:
char name[24]; char name[24];
CAnimBlendSequence *sequences; CAnimBlendSequence *sequences;
int16 numSequences; int16 numSequences;
int16 compressed; // not really used bool compressed; // not really used
bool compressed2; // not really used
float totalLength; float totalLength;
CLink<CAnimBlendHierarchy*> *linkPtr; CLink<CAnimBlendHierarchy*> *linkPtr;
@ -19,6 +20,7 @@ public:
void Shutdown(void); void Shutdown(void);
void SetName(char *name); void SetName(char *name);
void CalcTotalTime(void); void CalcTotalTime(void);
void CalcTotalTimeCompressed(void);
void RemoveQuaternionFlips(void); void RemoveQuaternionFlips(void);
void RemoveAnimSequences(void); void RemoveAnimSequences(void);
void Uncompress(void); void Uncompress(void);

View File

@ -23,5 +23,6 @@ public:
prev->next = next; prev->next = next;
if(next) if(next)
next->prev = prev; next->prev = prev;
Init();
} }
}; };

View File

@ -3,11 +3,13 @@
#include "AnimBlendAssociation.h" #include "AnimBlendAssociation.h"
#include "AnimBlendNode.h" #include "AnimBlendNode.h"
//--MIAMI: file done
void void
CAnimBlendNode::Init(void) CAnimBlendNode::Init(void)
{ {
frameA = 0; frameA = -1;
frameB = 0; frameB = -1;
remainingTime = 0.0f; remainingTime = 0.0f;
sequence = nil; sequence = nil;
association = nil; association = nil;
@ -92,7 +94,9 @@ CAnimBlendNode::FindKeyFrame(float t)
frameA = 0; frameA = 0;
frameB = frameA; frameB = frameA;
if(sequence->numFrames >= 2){ if(sequence->numFrames == 1){
remainingTime = 0.0f;
}else{
frameA++; frameA++;
// advance until t is between frameB and frameA // advance until t is between frameB and frameA
@ -101,8 +105,11 @@ CAnimBlendNode::FindKeyFrame(float t)
frameB = frameA++; frameB = frameA++;
if(frameA >= sequence->numFrames){ if(frameA >= sequence->numFrames){
// reached end of animation // reached end of animation
if(!association->IsRepeating()) if(!association->IsRepeating()){
CalcDeltas();
remainingTime = 0.0f;
return false; return false;
}
frameA = 0; frameA = 0;
frameB = 0; frameB = 0;
} }
@ -115,6 +122,25 @@ CAnimBlendNode::FindKeyFrame(float t)
return true; return true;
} }
bool
CAnimBlendNode::SetupKeyFrameCompressed(void)
{
if(sequence->numFrames < 1)
return false;
frameA = 1;
frameB = 0;
if(sequence->numFrames == 1){
frameA = 0;
remainingTime = 0.0f;
}else
remainingTime = sequence->GetKeyFrameCompressed(frameA)->deltaTime/60.0f;
CalcDeltasCompressed();
return true;
}
void void
CAnimBlendNode::CalcDeltas(void) CAnimBlendNode::CalcDeltas(void)
{ {
@ -129,6 +155,20 @@ CAnimBlendNode::CalcDeltas(void)
invSin = theta == 0.0f ? 0.0f : 1.0f/Sin(theta); invSin = theta == 0.0f ? 0.0f : 1.0f/Sin(theta);
} }
void
CAnimBlendNode::CalcDeltasCompressed(void)
{
if((sequence->type & CAnimBlendSequence::KF_ROT) == 0)
return;
KeyFrame *kfA = sequence->GetKeyFrameCompressed(frameA);
KeyFrame *kfB = sequence->GetKeyFrameCompressed(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 void
CAnimBlendNode::GetCurrentTranslation(CVector &trans, float weight) CAnimBlendNode::GetCurrentTranslation(CVector &trans, float weight)
{ {
@ -138,7 +178,7 @@ CAnimBlendNode::GetCurrentTranslation(CVector &trans, float weight)
if(blend > 0.0f){ if(blend > 0.0f){
KeyFrameTrans *kfA = (KeyFrameTrans*)sequence->GetKeyFrame(frameA); KeyFrameTrans *kfA = (KeyFrameTrans*)sequence->GetKeyFrame(frameA);
KeyFrameTrans *kfB = (KeyFrameTrans*)sequence->GetKeyFrame(frameB); KeyFrameTrans *kfB = (KeyFrameTrans*)sequence->GetKeyFrame(frameB);
float t = (kfA->deltaTime - remainingTime)/kfA->deltaTime; float t = kfA->deltaTime == 0.0f ? 0.0f : (kfA->deltaTime - remainingTime)/kfA->deltaTime;
if(sequence->type & CAnimBlendSequence::KF_TRANS){ if(sequence->type & CAnimBlendSequence::KF_TRANS){
trans = kfB->translation + t*(kfA->translation - kfB->translation); trans = kfB->translation + t*(kfA->translation - kfB->translation);
trans *= blend; trans *= blend;

View File

@ -22,7 +22,9 @@ public:
bool Update(CVector &trans, CQuaternion &rot, float weight); bool Update(CVector &trans, CQuaternion &rot, float weight);
bool NextKeyFrame(void); bool NextKeyFrame(void);
bool FindKeyFrame(float t); bool FindKeyFrame(float t);
bool SetupKeyFrameCompressed(void);
void CalcDeltas(void); void CalcDeltas(void);
void CalcDeltasCompressed(void);
void GetCurrentTranslation(CVector &trans, float weight); void GetCurrentTranslation(CVector &trans, float weight);
void GetEndTranslation(CVector &trans, float weight); void GetEndTranslation(CVector &trans, float weight);
}; };

View File

@ -2,6 +2,8 @@
#include "AnimBlendSequence.h" #include "AnimBlendSequence.h"
//--MIAMI: file done
CAnimBlendSequence::CAnimBlendSequence(void) CAnimBlendSequence::CAnimBlendSequence(void)
{ {
type = 0; type = 0;
@ -17,6 +19,8 @@ CAnimBlendSequence::~CAnimBlendSequence(void)
{ {
if(keyFrames) if(keyFrames)
RwFree(keyFrames); RwFree(keyFrames);
if(keyFramesCompressed)
RwFree(keyFramesCompressed);
} }
void void
@ -26,18 +30,21 @@ CAnimBlendSequence::SetName(char *name)
} }
void void
CAnimBlendSequence::SetNumFrames(int numFrames, bool translation) CAnimBlendSequence::SetNumFrames(int numFrames, bool translation, bool compressed)
{ {
int sz;
if(translation){ if(translation){
sz = sizeof(KeyFrameTrans);
type |= KF_ROT | KF_TRANS; type |= KF_ROT | KF_TRANS;
if(compressed)
keyFramesCompressed = RwMalloc(sizeof(KeyFrameTrans) * numFrames);
else
keyFrames = RwMalloc(sizeof(KeyFrameTrans) * numFrames);
}else{ }else{
sz = sizeof(KeyFrame);
type |= KF_ROT; type |= KF_ROT;
if(compressed)
keyFramesCompressed = RwMalloc(sizeof(KeyFrame) * numFrames);
else
keyFrames = RwMalloc(sizeof(KeyFrame) * numFrames);
} }
keyFrames = RwMalloc(sz * numFrames);
this->numFrames = numFrames; this->numFrames = numFrames;
} }

View File

@ -33,13 +33,18 @@ public:
CAnimBlendSequence(void); CAnimBlendSequence(void);
virtual ~CAnimBlendSequence(void); virtual ~CAnimBlendSequence(void);
void SetName(char *name); void SetName(char *name);
void SetNumFrames(int numFrames, bool translation); void SetNumFrames(int numFrames, bool translation, bool compressed);
void RemoveQuaternionFlips(void); void RemoveQuaternionFlips(void);
KeyFrame *GetKeyFrame(int n) { KeyFrame *GetKeyFrame(int n) {
return type & KF_TRANS ? return type & KF_TRANS ?
&((KeyFrameTrans*)keyFrames)[n] : &((KeyFrameTrans*)keyFrames)[n] :
&((KeyFrame*)keyFrames)[n]; &((KeyFrame*)keyFrames)[n];
} }
KeyFrame *GetKeyFrameCompressed(int n) {
return type & KF_TRANS ?
&((KeyFrameTrans*)keyFramesCompressed)[n] :
&((KeyFrame*)keyFramesCompressed)[n];
}
bool HasTranslation(void) { return !!(type & KF_TRANS); } bool HasTranslation(void) { return !!(type & KF_TRANS); }
// TODO? these are unused // TODO? these are unused
// void Uncompress(void); // void Uncompress(void);

View File

@ -10,9 +10,12 @@
#include "AnimBlendAssociation.h" #include "AnimBlendAssociation.h"
#include "AnimBlendAssocGroup.h" #include "AnimBlendAssocGroup.h"
#include "AnimManager.h" #include "AnimManager.h"
#include "Streaming.h"
CAnimBlock CAnimManager::ms_aAnimBlocks[2]; //--MIAMI: code done (except for pointless TODO)
CAnimBlendHierarchy CAnimManager::ms_aAnimations[250];
CAnimBlock CAnimManager::ms_aAnimBlocks[NUMANIMBLOCKS];
CAnimBlendHierarchy CAnimManager::ms_aAnimations[NUMANIMATIONS];
int32 CAnimManager::ms_numAnimBlocks; int32 CAnimManager::ms_numAnimBlocks;
int32 CAnimManager::ms_numAnimations; int32 CAnimManager::ms_numAnimations;
CAnimBlendAssocGroup *CAnimManager::ms_aAnimAssocGroups; CAnimBlendAssocGroup *CAnimManager::ms_aAnimAssocGroups;
@ -564,8 +567,6 @@ CAnimManager::Initialise(void)
ms_numAnimations = 0; ms_numAnimations = 0;
ms_numAnimBlocks = 0; ms_numAnimBlocks = 0;
ms_animCache.Init(25); ms_animCache.Init(25);
// dumpanimdata();
} }
void void
@ -573,31 +574,48 @@ CAnimManager::Shutdown(void)
{ {
int i; int i;
ms_animCache.Shutdown(); for(i = 0; i < NUMANIMBLOCKS; i++)
CStreaming::RemoveAnim(i);
for(i = 0; i < ms_numAnimations; i++) for(i = 0; i < ms_numAnimations; i++)
ms_aAnimations[i].Shutdown(); ms_aAnimations[i].Shutdown();
ms_animCache.Shutdown();
delete[] ms_aAnimAssocGroups; delete[] ms_aAnimAssocGroups;
} }
void void
CAnimManager::UncompressAnimation(CAnimBlendHierarchy *hier) CAnimManager::UncompressAnimation(CAnimBlendHierarchy *hier)
{ {
if(!hier->compressed){ if(hier->compressed2){
if(hier->linkPtr){ if(hier->totalLength == 0.0f)
hier->linkPtr->Remove(); hier->CalcTotalTimeCompressed();
ms_animCache.head.Insert(hier->linkPtr);
}
}else{ }else{
CLink<CAnimBlendHierarchy*> *link = ms_animCache.Insert(hier); if(!hier->compressed){
if(link == nil){ if(hier->linkPtr){
ms_animCache.tail.prev->item->RemoveUncompressedData(); hier->linkPtr->Remove();
ms_animCache.Remove(ms_animCache.tail.prev); ms_animCache.head.Insert(hier->linkPtr);
link = ms_animCache.Insert(hier); }
}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();
} }
hier->linkPtr = link; }
hier->Uncompress(); }
void
CAnimManager::RemoveFromUncompressedCache(CAnimBlendHierarchy *hier)
{
if(hier->linkPtr){
ms_animCache.Remove(hier->linkPtr);
hier->linkPtr = nil;
} }
} }
@ -612,6 +630,73 @@ CAnimManager::GetAnimationBlock(const char *name)
return nil; return nil;
} }
int32
CAnimManager::GetAnimationBlockIndex(const char *name)
{
int i;
for(i = 0; i < ms_numAnimBlocks; i++)
if(strcasecmp(ms_aAnimBlocks[i].name, name) == 0)
return i;
return -1;
}
int32
CAnimManager::RegisterAnimBlock(const char *name)
{
CAnimBlock *animBlock = GetAnimationBlock(name);
if(animBlock == nil){
animBlock = &ms_aAnimBlocks[ms_numAnimBlocks++];
strncpy(animBlock->name, name, MAX_ANIMBLOCK_NAME);
animBlock->numAnims = 0;
assert(animBlock->refCount == 0);
}
return animBlock - ms_aAnimBlocks;
}
int32
CAnimManager::GetNumRefsToAnimBlock(int32 block)
{
return ms_aAnimBlocks[block].refCount;
}
void
CAnimManager::AddAnimBlockRef(int32 block)
{
ms_aAnimBlocks[block].refCount++;
}
void
CAnimManager::RemoveAnimBlockRefWithoutDelete(int32 block)
{
ms_aAnimBlocks[block].refCount--;
}
void
CAnimManager::RemoveAnimBlockRef(int32 block)
{
ms_aAnimBlocks[block].refCount--;
if(ms_aAnimBlocks[block].refCount == 0)
CStreaming::RemoveAnim(block);
}
void
CAnimManager::RemoveAnimBlock(int32 block)
{
int i;
CAnimBlock *animblock;
animblock = &ms_aAnimBlocks[block];
debug("Removing ANIMS %s\n", animblock->name);
for(i = 0; i < NUM_ANIM_ASSOC_GROUPS; i++)
if(ms_aAnimAssocGroups[i].animBlock == animblock)
ms_aAnimAssocGroups[i].DestroyAssociations();
for(i = 0; i < animblock->numAnims; i++)
ms_aAnimations[animblock->firstIndex + i].Shutdown();
animblock->isLoaded = false;
animblock->refCount = 0;
}
CAnimBlendHierarchy* CAnimBlendHierarchy*
CAnimManager::GetAnimation(const char *name, CAnimBlock *animBlock) CAnimManager::GetAnimation(const char *name, CAnimBlock *animBlock)
{ {
@ -619,7 +704,7 @@ CAnimManager::GetAnimation(const char *name, CAnimBlock *animBlock)
CAnimBlendHierarchy *hier = &ms_aAnimations[animBlock->firstIndex]; CAnimBlendHierarchy *hier = &ms_aAnimations[animBlock->firstIndex];
for(i = 0; i < animBlock->numAnims; i++){ for(i = 0; i < animBlock->numAnims; i++){
if(!CGeneral::faststricmp(hier->name, name)) if(strcasecmp(hier->name, name) == 0)
return hier; return hier;
hier++; hier++;
} }
@ -739,24 +824,33 @@ CAnimManager::BlendAnimation(RpClump *clump, AssocGroupId groupId, AnimationId a
void void
CAnimManager::LoadAnimFiles(void) CAnimManager::LoadAnimFiles(void)
{
LoadAnimFile("ANIM\\PED.IFP");
ms_aAnimAssocGroups = new CAnimBlendAssocGroup[NUM_ANIM_ASSOC_GROUPS];
CreateAnimAssocGroups();
}
void
CAnimManager::CreateAnimAssocGroups(void)
{ {
int i, j; 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++){ for(i = 0; i < NUM_ANIM_ASSOC_GROUPS; i++){
CAnimBlock *block = GetAnimationBlock(ms_aAnimAssocDefinitions[i].blockName);
if(block == nil || !block->isLoaded || ms_aAnimAssocGroups[i].assocList)
continue;
CBaseModelInfo *mi = CModelInfo::GetModelInfo(ms_aAnimAssocDefinitions[i].modelIndex); CBaseModelInfo *mi = CModelInfo::GetModelInfo(ms_aAnimAssocDefinitions[i].modelIndex);
RpClump *clump = (RpClump*)mi->CreateInstance(); RpClump *clump = (RpClump*)mi->CreateInstance();
RpAnimBlendClumpInit(clump); RpAnimBlendClumpInit(clump);
CAnimBlendAssocGroup *group = &CAnimManager::ms_aAnimAssocGroups[i]; CAnimBlendAssocGroup *group = &ms_aAnimAssocGroups[i];
const AnimAssocDefinition *def = &CAnimManager::ms_aAnimAssocDefinitions[i]; const AnimAssocDefinition *def = &ms_aAnimAssocDefinitions[i];
group->groupId = i;
group->firstAnimId = def->animDescs[0].animId;
group->CreateAssociations(def->blockName, clump, def->animNames, def->numAnims); group->CreateAssociations(def->blockName, clump, def->animNames, def->numAnims);
for(j = 0; j < group->numAssociations; j++) for(j = 0; j < group->numAssociations; j++)
group->GetAnimation(j)->flags |= def->animDescs[j].flags; group->GetAnimation(j)->flags |= def->animDescs[j].flags;
#ifdef PED_SKIN #ifdef PED_SKIN
// forgot on xbox/android
if(IsClumpSkinned(clump)) if(IsClumpSkinned(clump))
RpClumpForAllAtomics(clump, AtomicRemoveAnimFromSkinCB, nil); RpClumpForAllAtomics(clump, AtomicRemoveAnimFromSkinCB, nil);
#endif #endif
@ -767,15 +861,16 @@ CAnimManager::LoadAnimFiles(void)
void void
CAnimManager::LoadAnimFile(const char *filename) CAnimManager::LoadAnimFile(const char *filename)
{ {
int fd; RwStream *stream;
fd = CFileMgr::OpenFile(filename, "rb"); stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename);
assert(fd > 0); assert(stream);
LoadAnimFile(fd, true); LoadAnimFile(stream, true);
CFileMgr::CloseFile(fd); RwStreamClose(stream, nil);
} }
//--MIAMI: done (except maybe implement some unimplemented compression?)
void void
CAnimManager::LoadAnimFile(int fd, bool compress) CAnimManager::LoadAnimFile(RwStream *stream, bool compress, char (*somename)[32])
{ {
#define ROUNDSIZE(x) if((x) & 3) (x) += 4 - ((x)&3) #define ROUNDSIZE(x) if((x) & 3) (x) += 4 - ((x)&3)
struct IfpHeader { struct IfpHeader {
@ -783,127 +878,130 @@ CAnimManager::LoadAnimFile(int fd, bool compress)
uint32 size; uint32 size;
}; };
IfpHeader anpk, info, name, dgan, cpan, anim; IfpHeader anpk, info, name, dgan, cpan, anim;
int numANPK;
char buf[256]; char buf[256];
int i, j, k, l; int j, k, l;
float *fbuf = (float*)buf; float *fbuf = (float*)buf;
CFileMgr::Read(fd, (char*)&anpk, sizeof(IfpHeader)); // block name
if(strncmp(anpk.ident, "ANLF", 4) == 0){ RwStreamRead(stream, &anpk, sizeof(IfpHeader));
ROUNDSIZE(anpk.size); ROUNDSIZE(anpk.size);
CFileMgr::Read(fd, buf, anpk.size); RwStreamRead(stream, &info, sizeof(IfpHeader));
numANPK = *(int*)buf; ROUNDSIZE(info.size);
}else if(strncmp(anpk.ident, "ANPK", 4) == 0){ RwStreamRead(stream, buf, info.size);
CFileMgr::Seek(fd, -8, 1); CAnimBlock *animBlock = GetAnimationBlock(buf+4);
numANPK = 1; if(animBlock){
if(animBlock->numAnims == 0){
animBlock->numAnims = *(int*)buf;
animBlock->firstIndex = ms_numAnimations;
}
}else{
animBlock = &ms_aAnimBlocks[ms_numAnimBlocks++];
strncpy(animBlock->name, buf+4, MAX_ANIMBLOCK_NAME);
animBlock->numAnims = *(int*)buf;
animBlock->firstIndex = ms_numAnimations;
} }
for(i = 0; i < numANPK; i++){ debug("Loading ANIMS %s\n", animBlock->name);
// block name animBlock->isLoaded = true;
CFileMgr::Read(fd, (char*)&anpk, sizeof(IfpHeader));
ROUNDSIZE(anpk.size); int animIndex = animBlock->firstIndex;
CFileMgr::Read(fd, (char*)&info, sizeof(IfpHeader)); for(j = 0; j < animBlock->numAnims; j++){
CAnimBlendHierarchy *hier = &ms_aAnimations[animIndex++];
// animation name
RwStreamRead(stream, &name, sizeof(IfpHeader));
ROUNDSIZE(name.size);
RwStreamRead(stream, buf, name.size);
hier->SetName(buf);
// TODO(MIAMI)? some unused crap here
hier->compressed = false;
hier->compressed2 = false;
// DG info has number of nodes/sequences
RwStreamRead(stream, (char*)&dgan, sizeof(IfpHeader));
ROUNDSIZE(dgan.size);
RwStreamRead(stream, (char*)&info, sizeof(IfpHeader));
ROUNDSIZE(info.size); ROUNDSIZE(info.size);
CFileMgr::Read(fd, buf, info.size); RwStreamRead(stream, buf, info.size);
CAnimBlock *animBlock = &ms_aAnimBlocks[ms_numAnimBlocks++]; hier->numSequences = *(int*)buf;
strncpy(animBlock->name, buf+4, 24); hier->sequences = new CAnimBlendSequence[hier->numSequences];
animBlock->numAnims = *(int*)buf;
animBlock->firstIndex = ms_numAnimations; CAnimBlendSequence *seq = hier->sequences;
for(k = 0; k < hier->numSequences; k++, seq++){
for(j = 0; j < animBlock->numAnims; j++){ // Each node has a name and key frames
CAnimBlendHierarchy *hier = &ms_aAnimations[ms_numAnimations++]; RwStreamRead(stream, &cpan, sizeof(IfpHeader));
// 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); ROUNDSIZE(dgan.size);
CFileMgr::Read(fd, (char*)&info, sizeof(IfpHeader)); RwStreamRead(stream, &anim, sizeof(IfpHeader));
ROUNDSIZE(info.size); ROUNDSIZE(anim.size);
CFileMgr::Read(fd, buf, info.size); RwStreamRead(stream, buf, anim.size);
hier->numSequences = *(int*)buf; int numFrames = *(int*)(buf+28);
hier->sequences = new CAnimBlendSequence[hier->numSequences];
CAnimBlendSequence *seq = hier->sequences;
for(k = 0; k < hier->numSequences; k++, seq++){
// Each node has a name and key frames
CFileMgr::Read(fd, (char*)&cpan, sizeof(IfpHeader));
ROUNDSIZE(dgan.size);
CFileMgr::Read(fd, (char*)&anim, sizeof(IfpHeader));
ROUNDSIZE(anim.size);
CFileMgr::Read(fd, buf, anim.size);
int numFrames = *(int*)(buf+28);
#ifdef PED_SKIN #ifdef PED_SKIN
if(anim.size == 44) if(anim.size == 44)
seq->SetBoneTag(*(int*)(buf+40)); seq->SetBoneTag(*(int*)(buf+40));
#endif #endif
seq->SetName(buf); seq->SetName(buf);
if(numFrames == 0) if(numFrames == 0)
continue; continue;
CFileMgr::Read(fd, (char*)&info, sizeof(info)); RwStreamRead(stream, &info, sizeof(info));
if(strncmp(info.ident, "KR00", 4) == 0){ if(strncmp(info.ident, "KR00", 4) == 0){
seq->SetNumFrames(numFrames, false); seq->SetNumFrames(numFrames, false, false);
KeyFrame *kf = seq->GetKeyFrame(0); KeyFrame *kf = seq->GetKeyFrame(0);
for(l = 0; l < numFrames; l++, kf++){ for(l = 0; l < numFrames; l++, kf++){
CFileMgr::Read(fd, buf, 0x14); RwStreamRead(stream, buf, 0x14);
kf->rotation.x = -fbuf[0]; kf->rotation.x = -fbuf[0];
kf->rotation.y = -fbuf[1]; kf->rotation.y = -fbuf[1];
kf->rotation.z = -fbuf[2]; kf->rotation.z = -fbuf[2];
kf->rotation.w = fbuf[3]; kf->rotation.w = fbuf[3];
kf->deltaTime = fbuf[4]; // absolute time here kf->deltaTime = fbuf[4]; // absolute time here
}
}else if(strncmp(info.ident, "KRT0", 4) == 0){
seq->SetNumFrames(numFrames, true);
KeyFrameTrans *kf = (KeyFrameTrans*)seq->GetKeyFrame(0);
for(l = 0; l < numFrames; l++, kf++){
CFileMgr::Read(fd, buf, 0x20);
kf->rotation.x = -fbuf[0];
kf->rotation.y = -fbuf[1];
kf->rotation.z = -fbuf[2];
kf->rotation.w = fbuf[3];
kf->translation.x = fbuf[4];
kf->translation.y = fbuf[5];
kf->translation.z = fbuf[6];
kf->deltaTime = fbuf[7]; // absolute time here
}
}else if(strncmp(info.ident, "KRTS", 4) == 0){
seq->SetNumFrames(numFrames, true);
KeyFrameTrans *kf = (KeyFrameTrans*)seq->GetKeyFrame(0);
for(l = 0; l < numFrames; l++, kf++){
CFileMgr::Read(fd, buf, 0x2C);
kf->rotation.x = -fbuf[0];
kf->rotation.y = -fbuf[1];
kf->rotation.z = -fbuf[2];
kf->rotation.w = fbuf[3];
kf->translation.x = fbuf[4];
kf->translation.y = fbuf[5];
kf->translation.z = fbuf[6];
// scaling ignored
kf->deltaTime = fbuf[10]; // absolute time here
}
} }
}else if(strncmp(info.ident, "KRT0", 4) == 0){
// convert absolute time to deltas seq->SetNumFrames(numFrames, true, false);
for(l = seq->numFrames-1; l > 0; l--){ KeyFrameTrans *kf = (KeyFrameTrans*)seq->GetKeyFrame(0);
KeyFrame *kf1 = seq->GetKeyFrame(l); for(l = 0; l < numFrames; l++, kf++){
KeyFrame *kf2 = seq->GetKeyFrame(l-1); RwStreamRead(stream, buf, 0x20);
kf1->deltaTime -= kf2->deltaTime; kf->rotation.x = -fbuf[0];
kf->rotation.y = -fbuf[1];
kf->rotation.z = -fbuf[2];
kf->rotation.w = fbuf[3];
kf->translation.x = fbuf[4];
kf->translation.y = fbuf[5];
kf->translation.z = fbuf[6];
kf->deltaTime = fbuf[7]; // absolute time here
}
}else if(strncmp(info.ident, "KRTS", 4) == 0){
seq->SetNumFrames(numFrames, true, false);
KeyFrameTrans *kf = (KeyFrameTrans*)seq->GetKeyFrame(0);
for(l = 0; l < numFrames; l++, kf++){
RwStreamRead(stream, buf, 0x2C);
kf->rotation.x = -fbuf[0];
kf->rotation.y = -fbuf[1];
kf->rotation.z = -fbuf[2];
kf->rotation.w = fbuf[3];
kf->translation.x = fbuf[4];
kf->translation.y = fbuf[5];
kf->translation.z = fbuf[6];
// scaling ignored
kf->deltaTime = fbuf[10]; // absolute time here
} }
} }
hier->RemoveQuaternionFlips(); /*
if(compress) // convert absolute time to deltas
hier->RemoveUncompressedData(); for(l = seq->numFrames-1; l > 0; l--){
else KeyFrame *kf1 = seq->GetKeyFrame(l);
hier->CalcTotalTime(); KeyFrame *kf2 = seq->GetKeyFrame(l-1);
kf1->deltaTime -= kf2->deltaTime;
}
*/
} }
hier->RemoveQuaternionFlips();
hier->CalcTotalTime();
} }
if(animIndex > ms_numAnimations)
ms_numAnimations = animIndex;
} }
void void
@ -913,5 +1011,6 @@ CAnimManager::RemoveLastAnimFile(void)
ms_numAnimBlocks--; ms_numAnimBlocks--;
ms_numAnimations = ms_aAnimBlocks[ms_numAnimBlocks].firstIndex; ms_numAnimations = ms_aAnimBlocks[ms_numAnimBlocks].firstIndex;
for(i = 0; i < ms_aAnimBlocks[ms_numAnimBlocks].numAnims; i++) for(i = 0; i < ms_aAnimBlocks[ms_numAnimBlocks].numAnims; i++)
ms_aAnimations[ms_aAnimBlocks[ms_numAnimBlocks].firstIndex + i].RemoveAnimSequences(); ms_aAnimations[ms_aAnimBlocks[ms_numAnimBlocks].firstIndex + i].Shutdown();
ms_aAnimBlocks[ms_numAnimBlocks].isLoaded = false;
} }

View File

@ -31,17 +31,21 @@ enum AssocGroupId
ASSOCGRP_ROCKETLEFT, ASSOCGRP_ROCKETLEFT,
ASSOCGRP_ROCKETRIGHT, ASSOCGRP_ROCKETRIGHT,
NUM_ANIM_ASSOC_GROUPS NUM_ANIM_ASSOC_GROUPS // should be 61 in the end
}; };
class CAnimBlendAssociation; class CAnimBlendAssociation;
class CAnimBlendAssocGroup; class CAnimBlendAssocGroup;
#define MAX_ANIMBLOCK_NAME 20
// A block of hierarchies // A block of hierarchies
struct CAnimBlock struct CAnimBlock
{ {
char name[24]; char name[MAX_ANIMBLOCK_NAME];
int32 firstIndex; bool isLoaded;
int16 refCount;
int32 firstIndex; // first animtion in ms_aAnimations
int32 numAnims; int32 numAnims;
}; };
@ -64,8 +68,8 @@ struct AnimAssocDefinition
class CAnimManager class CAnimManager
{ {
static const AnimAssocDefinition ms_aAnimAssocDefinitions[NUM_ANIM_ASSOC_GROUPS]; static const AnimAssocDefinition ms_aAnimAssocDefinitions[NUM_ANIM_ASSOC_GROUPS];
static CAnimBlock ms_aAnimBlocks[2]; static CAnimBlock ms_aAnimBlocks[NUMANIMBLOCKS];
static CAnimBlendHierarchy ms_aAnimations[250]; static CAnimBlendHierarchy ms_aAnimations[NUMANIMATIONS];
static int32 ms_numAnimBlocks; static int32 ms_numAnimBlocks;
static int32 ms_numAnimations; static int32 ms_numAnimations;
static CAnimBlendAssocGroup *ms_aAnimAssocGroups; static CAnimBlendAssocGroup *ms_aAnimAssocGroups;
@ -75,7 +79,15 @@ public:
static void Initialise(void); static void Initialise(void);
static void Shutdown(void); static void Shutdown(void);
static void UncompressAnimation(CAnimBlendHierarchy *anim); static void UncompressAnimation(CAnimBlendHierarchy *anim);
static void RemoveFromUncompressedCache(CAnimBlendHierarchy *hier);
static CAnimBlock *GetAnimationBlock(const char *name); static CAnimBlock *GetAnimationBlock(const char *name);
static int32 GetAnimationBlockIndex(const char *name);
static int32 RegisterAnimBlock(const char *name);
static int32 GetNumRefsToAnimBlock(int32 block);
static void AddAnimBlockRef(int32 block);
static void RemoveAnimBlockRefWithoutDelete(int32 block);
static void RemoveAnimBlockRef(int32 block);
static void RemoveAnimBlock(int32 block);
static CAnimBlendHierarchy *GetAnimation(const char *name, CAnimBlock *animBlock); static CAnimBlendHierarchy *GetAnimation(const char *name, CAnimBlock *animBlock);
static CAnimBlendHierarchy *GetAnimation(int32 n) { return &ms_aAnimations[n]; } static CAnimBlendHierarchy *GetAnimation(int32 n) { return &ms_aAnimations[n]; }
static const char *GetAnimGroupName(AssocGroupId groupId); static const char *GetAnimGroupName(AssocGroupId groupId);
@ -87,6 +99,7 @@ public:
static CAnimBlendAssociation *BlendAnimation(RpClump *clump, AssocGroupId groupId, AnimationId animId, float delta); static CAnimBlendAssociation *BlendAnimation(RpClump *clump, AssocGroupId groupId, AnimationId animId, float delta);
static void LoadAnimFiles(void); static void LoadAnimFiles(void);
static void LoadAnimFile(const char *filename); static void LoadAnimFile(const char *filename);
static void LoadAnimFile(int fd, bool compress); static void LoadAnimFile(RwStream *stream, bool compress, char (*somename)[32] = nil);
static void CreateAnimAssocGroups(void);
static void RemoveLastAnimFile(void); static void RemoveLastAnimFile(void);
}; };

View File

@ -185,23 +185,28 @@ CCutsceneMgr::LoadCutsceneData(const char *szCutsceneName)
CGame::DrasticTidyUpMemory(true); CGame::DrasticTidyUpMemory(true);
strcpy(ms_cutsceneName, szCutsceneName); strcpy(ms_cutsceneName, szCutsceneName);
file = CFileMgr::OpenFile("ANIM\\CUTS.IMG", "rb");
RwStream *stream;
stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, "ANIM\\CUTS.IMG");
assert(stream);
// Load animations // Load animations
sprintf(gString, "%s.IFP", szCutsceneName); sprintf(gString, "%s.IFP", szCutsceneName);
if (ms_pCutsceneDir->FindItem(gString, offset, size)) { if (ms_pCutsceneDir->FindItem(gString, offset, size)) {
CStreaming::MakeSpaceFor(size << 11); CStreaming::MakeSpaceFor(size << 11);
CStreaming::ImGonnaUseStreamingMemory(); CStreaming::ImGonnaUseStreamingMemory();
CFileMgr::Seek(file, offset << 11, SEEK_SET); RwStreamSkip(stream, offset << 11);
CAnimManager::LoadAnimFile(file, false); CAnimManager::LoadAnimFile(stream, false);
ms_cutsceneAssociations.CreateAssociations(szCutsceneName); ms_cutsceneAssociations.CreateAssociations(szCutsceneName);
CStreaming::IHaveUsedStreamingMemory(); CStreaming::IHaveUsedStreamingMemory();
ms_animLoaded = true; ms_animLoaded = true;
} else { } else {
ms_animLoaded = false; ms_animLoaded = false;
} }
RwStreamClose(stream, nil);
// Load camera data // Load camera data
file = CFileMgr::OpenFile("ANIM\\CUTS.IMG", "rb");
sprintf(gString, "%s.DAT", szCutsceneName); sprintf(gString, "%s.DAT", szCutsceneName);
if (ms_pCutsceneDir->FindItem(gString, offset, size)) { if (ms_pCutsceneDir->FindItem(gString, offset, size)) {
CFileMgr::Seek(file, offset << 11, SEEK_SET); CFileMgr::Seek(file, offset << 11, SEEK_SET);

View File

@ -386,7 +386,6 @@ RpAnimBlendClumpFillFrameArray(RpClump *clump, AnimBlendFrameData **frames)
AnimBlendFrameData *pFrameDataFound; AnimBlendFrameData *pFrameDataFound;
// FrameFindCallBack on PS2
void void
FrameFindByNameCBnonskin(AnimBlendFrameData *frame, void *arg) FrameFindByNameCBnonskin(AnimBlendFrameData *frame, void *arg)
{ {
@ -395,7 +394,6 @@ FrameFindByNameCBnonskin(AnimBlendFrameData *frame, void *arg)
pFrameDataFound = frame; pFrameDataFound = frame;
} }
#ifdef PED_SKIN
void void
FrameFindByNameCBskin(AnimBlendFrameData *frame, void *arg) FrameFindByNameCBskin(AnimBlendFrameData *frame, void *arg)
{ {
@ -403,21 +401,33 @@ FrameFindByNameCBskin(AnimBlendFrameData *frame, void *arg)
if(name && CGeneral::faststricmp(name, (char*)arg) == 0) if(name && CGeneral::faststricmp(name, (char*)arg) == 0)
pFrameDataFound = frame; pFrameDataFound = frame;
} }
#endif
void
FrameFindByBoneCB(AnimBlendFrameData *frame, void *arg)
{
if(frame->nodeID == (int32)(uintptr)arg)
pFrameDataFound = frame;
}
AnimBlendFrameData* AnimBlendFrameData*
RpAnimBlendClumpFindFrame(RpClump *clump, const char *name) RpAnimBlendClumpFindFrame(RpClump *clump, const char *name)
{ {
pFrameDataFound = nil; pFrameDataFound = nil;
#ifdef PED_SKIN
if(IsClumpSkinned(clump)) if(IsClumpSkinned(clump))
(*RPANIMBLENDCLUMPDATA(clump))->ForAllFrames(FrameFindByNameCBskin, (void*)name); (*RPANIMBLENDCLUMPDATA(clump))->ForAllFrames(FrameFindByNameCBskin, (void*)name);
else else
#endif
(*RPANIMBLENDCLUMPDATA(clump))->ForAllFrames(FrameFindByNameCBnonskin, (void*)name); (*RPANIMBLENDCLUMPDATA(clump))->ForAllFrames(FrameFindByNameCBnonskin, (void*)name);
return pFrameDataFound; return pFrameDataFound;
} }
AnimBlendFrameData*
RpAnimBlendClumpFindBone(RpClump *clump, uint32 boneTag)
{
pFrameDataFound = nil;
(*RPANIMBLENDCLUMPDATA(clump))->ForAllFrames(FrameFindByBoneCB, (void*)boneTag);
return pFrameDataFound;
}
void void
RpAnimBlendClumpUpdateAnimations(RpClump *clump, float timeDelta) RpAnimBlendClumpUpdateAnimations(RpClump *clump, float timeDelta)
{ {

View File

@ -26,6 +26,7 @@ void RpAnimBlendClumpInit(RpClump *clump);
bool RpAnimBlendClumpIsInitialized(RpClump *clump); bool RpAnimBlendClumpIsInitialized(RpClump *clump);
void RpAnimBlendClumpFillFrameArray(RpClump* clump, AnimBlendFrameData** frames); void RpAnimBlendClumpFillFrameArray(RpClump* clump, AnimBlendFrameData** frames);
AnimBlendFrameData *RpAnimBlendClumpFindFrame(RpClump *clump, const char *name); AnimBlendFrameData *RpAnimBlendClumpFindFrame(RpClump *clump, const char *name);
AnimBlendFrameData *RpAnimBlendClumpFindBone(RpClump *clump, uint32 boneTag);
void FillFrameArrayCallBack(AnimBlendFrameData *frame, void *arg); void FillFrameArrayCallBack(AnimBlendFrameData *frame, void *arg);
CAnimBlendAssociation *RpAnimBlendClumpGetAssociation(RpClump *clump, uint32 id); CAnimBlendAssociation *RpAnimBlendClumpGetAssociation(RpClump *clump, uint32 id);
CAnimBlendAssociation *RpAnimBlendClumpGetMainAssociation(RpClump *clump, CAnimBlendAssociation **assocRet, float *blendRet); CAnimBlendAssociation *RpAnimBlendClumpGetMainAssociation(RpClump *clump, CAnimBlendAssociation **assocRet, float *blendRet);

View File

@ -1529,7 +1529,6 @@ CCamera::UpdateTargetEntity(void)
pTargetEntity = FindPlayerVehicle(); pTargetEntity = FindPlayerVehicle();
else{ else{
pTargetEntity = FindPlayerPed(); pTargetEntity = FindPlayerPed();
#ifndef GTA_PS2_STUFF
// this keeps the camera on the player while entering cars // this keeps the camera on the player while entering cars
if(PLAYER->GetPedState() == PED_ENTER_CAR || if(PLAYER->GetPedState() == PED_ENTER_CAR ||
PLAYER->GetPedState() == PED_CARJACK || PLAYER->GetPedState() == PED_CARJACK ||
@ -1539,7 +1538,6 @@ CCamera::UpdateTargetEntity(void)
if(!enteringCar) if(!enteringCar)
if(Cams[ActiveCam].CamTargetEntity != pTargetEntity) if(Cams[ActiveCam].CamTargetEntity != pTargetEntity)
Cams[ActiveCam].CamTargetEntity = pTargetEntity; Cams[ActiveCam].CamTargetEntity = pTargetEntity;
#endif
} }
bool cantOpen = true; bool cantOpen = true;
@ -1558,16 +1556,9 @@ CCamera::UpdateTargetEntity(void)
if((PLAYER->GetPedState() == PED_CARJACK || PLAYER->GetPedState() == PED_OPEN_DOOR) && !cantOpen){ if((PLAYER->GetPedState() == PED_CARJACK || PLAYER->GetPedState() == PED_OPEN_DOOR) && !cantOpen){
if(!enteringCar && CarZoomIndicator != CAM_ZOOM_1STPRS) if(!enteringCar && CarZoomIndicator != CAM_ZOOM_1STPRS)
#ifdef GTA_PS2_STUFF
// dunno if this has any amazing effects
{
#endif
pTargetEntity = PLAYER->m_pMyVehicle; pTargetEntity = PLAYER->m_pMyVehicle;
if(PLAYER->m_pMyVehicle == nil) if(PLAYER->m_pMyVehicle == nil)
pTargetEntity = PLAYER; pTargetEntity = PLAYER;
#ifdef GTA_PS2_STUFF
}
#endif
} }
if(PLAYER->GetPedState() == PED_EXIT_CAR) if(PLAYER->GetPedState() == PED_EXIT_CAR)

View File

@ -39,7 +39,7 @@ CColStore::AddColSlot(const char *name)
ColDef *def = ms_pColPool->New(); ColDef *def = ms_pColPool->New();
assert(def); assert(def);
def->isLoaded = false; def->isLoaded = false;
def->a = 0; def->unused = 0;
def->bounds.left = 1000000.0f; def->bounds.left = 1000000.0f;
def->bounds.top = 1000000.0f; def->bounds.top = 1000000.0f;
def->bounds.right = -1000000.0f; def->bounds.right = -1000000.0f;
@ -133,6 +133,7 @@ CColStore::LoadAllCollision(void)
for(i = 1; i < COLSTORESIZE; i++) for(i = 1; i < COLSTORESIZE; i++)
if(GetSlot(i)) if(GetSlot(i))
CStreaming::RequestCol(i, 0); CStreaming::RequestCol(i, 0);
CStreaming::LoadAllRequestedModels(false); CStreaming::LoadAllRequestedModels(false);
} }

View File

@ -3,7 +3,7 @@
#include "templates.h" #include "templates.h"
struct ColDef { // made up name struct ColDef { // made up name
int32 a; int32 unused;
bool isLoaded; bool isLoaded;
CRect bounds; CRect bounds;
char name[20]; char name[20];

View File

@ -358,7 +358,7 @@ CStreaming::LoadCdDirectory(const char *dirname, int n)
*dot = '\0'; *dot = '\0';
if(!CGeneral::faststricmp(dot+1, "DFF")){ if(strncasecmp(dot+1, "DFF", 3) == 0){
if(CModelInfo::GetModelInfo(direntry.name, &modelId)){ if(CModelInfo::GetModelInfo(direntry.name, &modelId)){
bAddToStreaming = true; bAddToStreaming = true;
}else{ }else{
@ -370,13 +370,13 @@ CStreaming::LoadCdDirectory(const char *dirname, int n)
#endif #endif
lastID = -1; lastID = -1;
} }
}else if(!CGeneral::faststricmp(dot+1, "TXD")){ }else if(strncasecmp(dot+1, "TXD", 3) == 0){
modelId = CTxdStore::FindTxdSlot(direntry.name); modelId = CTxdStore::FindTxdSlot(direntry.name);
if(modelId == -1) if(modelId == -1)
modelId = CTxdStore::AddTxdSlot(direntry.name); modelId = CTxdStore::AddTxdSlot(direntry.name);
modelId += STREAM_OFFSET_TXD; modelId += STREAM_OFFSET_TXD;
bAddToStreaming = true; bAddToStreaming = true;
}else if(!CGeneral::faststricmp(dot+1, "COL")){ }else if(strncasecmp(dot+1, "COL", 3) == 0){
modelId = CColStore::FindColSlot(direntry.name); modelId = CColStore::FindColSlot(direntry.name);
if(modelId == -1) if(modelId == -1)
modelId = CColStore::AddColSlot(direntry.name); modelId = CColStore::AddColSlot(direntry.name);
@ -413,7 +413,7 @@ GetObjectName(int streamId)
sprintf(objname, "%s.dff", CModelInfo::GetModelInfo(streamId)->GetName()); sprintf(objname, "%s.dff", CModelInfo::GetModelInfo(streamId)->GetName());
else if(streamId >= STREAM_OFFSET_TXD && streamId < STREAM_OFFSET_COL) else if(streamId >= STREAM_OFFSET_TXD && streamId < STREAM_OFFSET_COL)
sprintf(objname, "%s.txd", CTxdStore::GetTxdName(streamId-STREAM_OFFSET_TXD)); sprintf(objname, "%s.txd", CTxdStore::GetTxdName(streamId-STREAM_OFFSET_TXD));
else if(streamId >= STREAM_OFFSET_COL && streamId < NUMSTREAMINFO) else if(streamId >= STREAM_OFFSET_COL && streamId < STREAM_OFFSET_ANIM)
sprintf(objname, "%s.col", CColStore::GetColName(streamId-STREAM_OFFSET_COL)); sprintf(objname, "%s.col", CColStore::GetColName(streamId-STREAM_OFFSET_COL));
// TODO(MIAMI): IFP // TODO(MIAMI): IFP
return objname; return objname;
@ -506,7 +506,7 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId)
RwStreamClose(stream, &mem); RwStreamClose(stream, &mem);
return false; return false;
} }
}else if(streamId >= STREAM_OFFSET_COL && streamId < NUMSTREAMINFO){ }else if(streamId >= STREAM_OFFSET_COL && streamId < STREAM_OFFSET_ANIM){
if(!CColStore::LoadCol(streamId-STREAM_OFFSET_COL, mem.start, mem.length)){ if(!CColStore::LoadCol(streamId-STREAM_OFFSET_COL, mem.start, mem.length)){
debug("Failed to load %s.col\n", CColStore::GetColName(streamId - STREAM_OFFSET_COL)); debug("Failed to load %s.col\n", CColStore::GetColName(streamId - STREAM_OFFSET_COL));
RemoveModel(streamId); RemoveModel(streamId);
@ -514,6 +514,8 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId)
RwStreamClose(stream, &mem); RwStreamClose(stream, &mem);
return false; return false;
} }
}else if(streamId >= STREAM_OFFSET_ANIM){
assert(streamId < NUMSTREAMINFO);
// TODO(MIAMI): IFP // TODO(MIAMI): IFP
} }
@ -829,7 +831,7 @@ CStreaming::RemoveModel(int32 id)
CModelInfo::GetModelInfo(id)->DeleteRwObject(); CModelInfo::GetModelInfo(id)->DeleteRwObject();
else if(id >= STREAM_OFFSET_TXD && id < STREAM_OFFSET_COL) else if(id >= STREAM_OFFSET_TXD && id < STREAM_OFFSET_COL)
CTxdStore::RemoveTxd(id - STREAM_OFFSET_TXD); CTxdStore::RemoveTxd(id - STREAM_OFFSET_TXD);
else if(id >= STREAM_OFFSET_COL && id < NUMSTREAMINFO) else if(id >= STREAM_OFFSET_COL && id < STREAM_OFFSET_ANIM)
CColStore::RemoveCol(id - STREAM_OFFSET_COL); CColStore::RemoveCol(id - STREAM_OFFSET_COL);
// TODO(MIAMI): IFP // TODO(MIAMI): IFP
ms_memoryUsed -= ms_aInfoForModel[id].GetCdSize()*CDSTREAM_SECTOR_SIZE; ms_memoryUsed -= ms_aInfoForModel[id].GetCdSize()*CDSTREAM_SECTOR_SIZE;
@ -854,7 +856,7 @@ CStreaming::RemoveModel(int32 id)
RpClumpGtaCancelStream(); RpClumpGtaCancelStream();
else if(id >= STREAM_OFFSET_TXD && id < STREAM_OFFSET_COL) else if(id >= STREAM_OFFSET_TXD && id < STREAM_OFFSET_COL)
CTxdStore::RemoveTxd(id - STREAM_OFFSET_TXD); CTxdStore::RemoveTxd(id - STREAM_OFFSET_TXD);
else if(id >= STREAM_OFFSET_COL && id < NUMSTREAMINFO) else if(id >= STREAM_OFFSET_COL && id < STREAM_OFFSET_ANIM)
CColStore::RemoveCol(id - STREAM_OFFSET_COL); CColStore::RemoveCol(id - STREAM_OFFSET_COL);
// TODO(MIAMI): IFP // TODO(MIAMI): IFP
} }

View File

@ -5,7 +5,8 @@
enum { enum {
STREAM_OFFSET_TXD = MODELINFOSIZE, STREAM_OFFSET_TXD = MODELINFOSIZE,
STREAM_OFFSET_COL = STREAM_OFFSET_TXD+TXDSTORESIZE, STREAM_OFFSET_COL = STREAM_OFFSET_TXD+TXDSTORESIZE,
NUMSTREAMINFO = STREAM_OFFSET_COL+COLSTORESIZE STREAM_OFFSET_ANIM = STREAM_OFFSET_COL+COLSTORESIZE,
NUMSTREAMINFO = STREAM_OFFSET_ANIM+NUMANIMBLOCKS
}; };
enum StreamFlags enum StreamFlags
@ -118,16 +119,19 @@ public:
static bool HasModelLoaded(int32 id) { return ms_aInfoForModel[id].m_loadState == STREAMSTATE_LOADED; } static bool HasModelLoaded(int32 id) { return ms_aInfoForModel[id].m_loadState == STREAMSTATE_LOADED; }
static bool HasTxdLoaded(int32 id) { return HasModelLoaded(id+STREAM_OFFSET_TXD); } static bool HasTxdLoaded(int32 id) { return HasModelLoaded(id+STREAM_OFFSET_TXD); }
static bool HasColLoaded(int32 id) { return HasModelLoaded(id+STREAM_OFFSET_COL); } static bool HasColLoaded(int32 id) { return HasModelLoaded(id+STREAM_OFFSET_COL); }
static bool HasAnimLoaded(int32 id) { return HasModelLoaded(id+STREAM_OFFSET_ANIM); }
static bool CanRemoveModel(int32 id) { return (ms_aInfoForModel[id].m_flags & STREAMFLAGS_CANT_REMOVE) == 0; } static bool CanRemoveModel(int32 id) { return (ms_aInfoForModel[id].m_flags & STREAMFLAGS_CANT_REMOVE) == 0; }
static bool CanRemoveTxd(int32 id) { return CanRemoveModel(id+STREAM_OFFSET_TXD); } static bool CanRemoveTxd(int32 id) { return CanRemoveModel(id+STREAM_OFFSET_TXD); }
static bool CanRemoveCol(int32 id) { return CanRemoveModel(id+STREAM_OFFSET_COL); } static bool CanRemoveCol(int32 id) { return CanRemoveModel(id+STREAM_OFFSET_COL); }
static bool CanRemoveAnim(int32 id) { return CanRemoveModel(id+STREAM_OFFSET_ANIM); }
static void RequestModel(int32 model, int32 flags); static void RequestModel(int32 model, int32 flags);
static void ReRequestModel(int32 model) { RequestModel(model, ms_aInfoForModel[model].m_flags); } static void ReRequestModel(int32 model) { RequestModel(model, ms_aInfoForModel[model].m_flags); }
static void RequestTxd(int32 txd, int32 flags) { RequestModel(txd + STREAM_OFFSET_TXD, flags); } static void RequestTxd(int32 txd, int32 flags) { RequestModel(txd + STREAM_OFFSET_TXD, flags); }
static void ReRequestTxd(int32 txd) { ReRequestModel(txd + STREAM_OFFSET_TXD); } static void ReRequestTxd(int32 txd) { ReRequestModel(txd + STREAM_OFFSET_TXD); }
static void RequestCol(int32 col, int32 flags) { RequestModel(col + STREAM_OFFSET_COL, flags); } static void RequestCol(int32 col, int32 flags) { RequestModel(col + STREAM_OFFSET_COL, flags); }
static void ReRequestCol(int32 col) { ReRequestModel(col + STREAM_OFFSET_COL); } static void ReRequestCol(int32 col) { ReRequestModel(col + STREAM_OFFSET_COL); }
static void RequestSubway(void); static void RequestAnim(int32 col, int32 flags) { RequestModel(col + STREAM_OFFSET_ANIM, flags); }
static void ReRequestAnim(int32 col) { ReRequestModel(col + STREAM_OFFSET_ANIM); }
static void RequestBigBuildings(eLevelName level); static void RequestBigBuildings(eLevelName level);
static void RequestBigBuildings(eLevelName level, const CVector &pos); static void RequestBigBuildings(eLevelName level, const CVector &pos);
static void InstanceBigBuildings(eLevelName level, const CVector &pos); static void InstanceBigBuildings(eLevelName level, const CVector &pos);
@ -140,6 +144,7 @@ public:
static void RemoveModel(int32 id); static void RemoveModel(int32 id);
static void RemoveTxd(int32 id) { RemoveModel(id + STREAM_OFFSET_TXD); } static void RemoveTxd(int32 id) { RemoveModel(id + STREAM_OFFSET_TXD); }
static void RemoveCol(int32 id) { RemoveModel(id + STREAM_OFFSET_COL); } static void RemoveCol(int32 id) { RemoveModel(id + STREAM_OFFSET_COL); }
static void RemoveAnim(int32 id) { RemoveModel(id + STREAM_OFFSET_ANIM); }
static void RemoveUnusedBuildings(eLevelName level); static void RemoveUnusedBuildings(eLevelName level);
static void RemoveBuildings(eLevelName level); static void RemoveBuildings(eLevelName level);
static void RemoveUnusedBigBuildings(eLevelName level); static void RemoveUnusedBigBuildings(eLevelName level);
@ -149,7 +154,6 @@ public:
static bool RemoveLeastUsedModel(uint32 excludeMask); static bool RemoveLeastUsedModel(uint32 excludeMask);
static void RemoveAllUnusedModels(void); static void RemoveAllUnusedModels(void);
static void RemoveUnusedModelsInLoadedList(void); static void RemoveUnusedModelsInLoadedList(void);
static bool RemoveReferencedTxds(int32 mem);
static int32 GetAvailableVehicleSlot(void); static int32 GetAvailableVehicleSlot(void);
static bool IsTxdUsedByRequestedModels(int32 txdId); static bool IsTxdUsedByRequestedModels(int32 txdId);
static bool AddToLoadedVehiclesList(int32 modelId); static bool AddToLoadedVehiclesList(int32 modelId);

View File

@ -187,6 +187,7 @@ public:
#if (defined(_MSC_VER)) #if (defined(_MSC_VER))
extern int strcasecmp(const char *str1, const char *str2); extern int strcasecmp(const char *str1, const char *str2);
extern int strncasecmp(const char *str1, const char *str2, size_t len);
#endif #endif
#define clamp(v, low, high) ((v)<(low) ? (low) : (v)>(high) ? (high) : (v)) #define clamp(v, low, high) ((v)<(low) ? (low) : (v)>(high) ? (high) : (v))

View File

@ -38,6 +38,9 @@ enum Config {
NUMCUTSCENEOBJECTS = 50, // does not exist in VC NUMCUTSCENEOBJECTS = 50, // does not exist in VC
// TODO(MIAMI): colmodel pool // TODO(MIAMI): colmodel pool
NUMANIMBLOCKS = 35,
NUMANIMATIONS = 450,
NUMTEMPOBJECTS = 30, NUMTEMPOBJECTS = 30,
// Path data // Path data

View File

@ -1678,5 +1678,9 @@ int strcasecmp(const char* str1, const char* str2)
{ {
return _strcmpi(str1, str2); return _strcmpi(str1, str2);
} }
int strncasecmp(const char *str1, const char *str2, size_t len)
{
return _strnicmp(str1, str2, len);
}
#endif #endif
#endif #endif

View File

@ -3150,5 +3150,9 @@ int strcasecmp(const char *str1, const char *str2)
{ {
return _strcmpi(str1, str2); return _strcmpi(str1, str2);
} }
int strncasecmp(const char *str1, const char *str2, size_t len)
{
return _strnicmp(str1, str2, len);
}
#endif #endif
#endif #endif