1
0
Fork 0
mirror of https://git.rip/DMCA_FUCKER/re3.git synced 2024-12-24 02:30:01 +00:00

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 "General.h"
#include "RwHelper.h"
#include "ModelIndices.h"
#include "ModelInfo.h"
#include "AnimManager.h"
#include "RpAnimBlend.h"
#include "AnimBlendAssociation.h"
#include "AnimBlendAssocGroup.h"
//--MIAMI: file done
CAnimBlendAssocGroup::CAnimBlendAssocGroup(void)
{
animBlock = nil;
assocList = nil;
numAssociations = 0;
firstAnimId = 0;
groupId = -1;
}
CAnimBlendAssocGroup::~CAnimBlendAssocGroup(void)
@ -43,6 +50,7 @@ CAnimBlendAssocGroup::GetAnimation(const char *name)
for(i = 0; i < numAssociations; i++)
if(!CGeneral::faststricmp(assocList[i].hierarchy->name, name))
return &assocList[i];
debug("\n\nCan't find the fucking animation %s\n\n\n", name);
return nil;
}
@ -102,6 +110,15 @@ GetModelFromName(const char *name)
{
int i;
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++){
mi = CModelInfo::GetModelInfo(i);
@ -118,7 +135,6 @@ CAnimBlendAssocGroup::CreateAssociations(const char *name)
int i;
CAnimBlock *animBlock;
if(assocList)
DestroyAssociations();
animBlock = CAnimManager::GetAnimationBlock(name);
@ -128,13 +144,18 @@ CAnimBlendAssocGroup::CreateAssociations(const char *name)
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->GetName());
if(model){
debug("Associated anim %s with model %s\n", anim->name, model->GetName());
RpClump *clump = (RpClump*)model->CreateInstance();
RpAnimBlendClumpInit(clump);
assocList[i].Init(clump, anim);
if(IsClumpSkinned(clump))
RpClumpForAllAtomics(clump, AtomicRemoveAnimFromSkinCB, nil);
RpClumpDestroy(clump);
assocList[i].animId = i;
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;
}
@ -144,9 +165,7 @@ void
CAnimBlendAssocGroup::CreateAssociations(const char *blockName, RpClump *clump, const char **animNames, int numAssocs)
{
int i;
CAnimBlock *animBlock;
if(assocList)
DestroyAssociations();
animBlock = CAnimManager::GetAnimationBlock(blockName);
@ -155,7 +174,8 @@ CAnimBlendAssocGroup::CreateAssociations(const char *blockName, RpClump *clump,
numAssociations = 0;
for(i = 0; i < numAssocs; i++){
assocList[i].Init(clump, CAnimManager::GetAnimation(animNames[i], animBlock));
assocList[i].animId = i;
assocList[i].animId = firstAnimId + i;
assocList[i].groupId = groupId;
}
numAssociations = numAssocs;
}

View file

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

View file

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

View file

@ -37,7 +37,8 @@ public:
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
CAnimBlendNode *nodes;
CAnimBlendHierarchy *hierarchy;
@ -46,8 +47,8 @@ public:
float currentTime;
float speed;
float timeStep;
int32 animId;
int32 flags;
int16 animId;
int16 flags;
int32 callbackType;
void (*callback)(CAnimBlendAssociation*, void*);
void *callbackArg;
@ -75,7 +76,7 @@ public:
void SetCurrentTime(float time);
void SyncAnimation(CAnimBlendAssociation *other);
void Start(float time);
void UpdateTime(float timeDelta, float relSpeed);
bool UpdateTime(float timeDelta, float relSpeed);
bool UpdateBlend(float timeDelta);
void SetRun(void) { flags |= ASSOC_RUNNING; }
@ -86,4 +87,3 @@ public:
return (CAnimBlendAssociation*)((uint8*)l - offsetof(CAnimBlendAssociation, link));
}
};
static_assert(sizeof(CAnimBlendAssociation) == 0x40, "CAnimBlendAssociation: error");

View file

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

View file

@ -35,9 +35,6 @@ class CAnimBlendClumpData
public:
CAnimBlendLink link;
int32 numFrames;
#ifdef PED_SKIN
int32 modelNumber; // doesn't seem to be used
#endif
CVector *velocity;
// order of frames is determined by RW hierarchy
AnimBlendFrameData *frames;
@ -50,6 +47,3 @@ public:
#endif
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 "AnimBlendHierarchy.h"
#include "AnimManager.h"
//--MIAMI: file done
CAnimBlendHierarchy::CAnimBlendHierarchy(void)
{
@ -15,9 +18,10 @@ CAnimBlendHierarchy::CAnimBlendHierarchy(void)
void
CAnimBlendHierarchy::Shutdown(void)
{
CAnimManager::RemoveFromUncompressedCache(this);
RemoveAnimSequences();
totalLength = 0.0f;
compressed = 0;
linkPtr = nil;
}
void
@ -30,15 +34,44 @@ void
CAnimBlendHierarchy::CalcTotalTime(void)
{
int i, j;
float totalTime = 0.0f;
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;
totalTime = Max(totalTime, seqTime);
#ifdef FIX_BUGS
if(sequences[i].numFrames == 0)
continue;
#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
@ -53,17 +86,19 @@ CAnimBlendHierarchy::RemoveQuaternionFlips(void)
void
CAnimBlendHierarchy::RemoveAnimSequences(void)
{
if(sequences)
delete[] sequences;
sequences = nil;
numSequences = 0;
}
void
CAnimBlendHierarchy::Uncompress(void)
{
if(totalLength == 0.0f)
CalcTotalTime();
compressed = 0;
if(totalLength == 0.0f){
RemoveQuaternionFlips();
CalcTotalTime();
}
}
void

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -33,13 +33,18 @@ public:
CAnimBlendSequence(void);
virtual ~CAnimBlendSequence(void);
void SetName(char *name);
void SetNumFrames(int numFrames, bool translation);
void SetNumFrames(int numFrames, bool translation, bool compressed);
void RemoveQuaternionFlips(void);
KeyFrame *GetKeyFrame(int n) {
return type & KF_TRANS ?
&((KeyFrameTrans*)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); }
// TODO? these are unused
// void Uncompress(void);

View file

@ -10,9 +10,12 @@
#include "AnimBlendAssociation.h"
#include "AnimBlendAssocGroup.h"
#include "AnimManager.h"
#include "Streaming.h"
CAnimBlock CAnimManager::ms_aAnimBlocks[2];
CAnimBlendHierarchy CAnimManager::ms_aAnimations[250];
//--MIAMI: code done (except for pointless TODO)
CAnimBlock CAnimManager::ms_aAnimBlocks[NUMANIMBLOCKS];
CAnimBlendHierarchy CAnimManager::ms_aAnimations[NUMANIMATIONS];
int32 CAnimManager::ms_numAnimBlocks;
int32 CAnimManager::ms_numAnimations;
CAnimBlendAssocGroup *CAnimManager::ms_aAnimAssocGroups;
@ -564,8 +567,6 @@ CAnimManager::Initialise(void)
ms_numAnimations = 0;
ms_numAnimBlocks = 0;
ms_animCache.Init(25);
// dumpanimdata();
}
void
@ -573,17 +574,24 @@ CAnimManager::Shutdown(void)
{
int i;
ms_animCache.Shutdown();
for(i = 0; i < NUMANIMBLOCKS; i++)
CStreaming::RemoveAnim(i);
for(i = 0; i < ms_numAnimations; i++)
ms_aAnimations[i].Shutdown();
ms_animCache.Shutdown();
delete[] ms_aAnimAssocGroups;
}
void
CAnimManager::UncompressAnimation(CAnimBlendHierarchy *hier)
{
if(hier->compressed2){
if(hier->totalLength == 0.0f)
hier->CalcTotalTimeCompressed();
}else{
if(!hier->compressed){
if(hier->linkPtr){
hier->linkPtr->Remove();
@ -600,6 +608,16 @@ CAnimManager::UncompressAnimation(CAnimBlendHierarchy *hier)
hier->Uncompress();
}
}
}
void
CAnimManager::RemoveFromUncompressedCache(CAnimBlendHierarchy *hier)
{
if(hier->linkPtr){
ms_animCache.Remove(hier->linkPtr);
hier->linkPtr = nil;
}
}
CAnimBlock*
CAnimManager::GetAnimationBlock(const char *name)
@ -612,6 +630,73 @@ CAnimManager::GetAnimationBlock(const char *name)
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*
CAnimManager::GetAnimation(const char *name, CAnimBlock *animBlock)
{
@ -619,7 +704,7 @@ CAnimManager::GetAnimation(const char *name, CAnimBlock *animBlock)
CAnimBlendHierarchy *hier = &ms_aAnimations[animBlock->firstIndex];
for(i = 0; i < animBlock->numAnims; i++){
if(!CGeneral::faststricmp(hier->name, name))
if(strcasecmp(hier->name, name) == 0)
return hier;
hier++;
}
@ -739,24 +824,33 @@ CAnimManager::BlendAnimation(RpClump *clump, AssocGroupId groupId, AnimationId a
void
CAnimManager::LoadAnimFiles(void)
{
LoadAnimFile("ANIM\\PED.IFP");
ms_aAnimAssocGroups = new CAnimBlendAssocGroup[NUM_ANIM_ASSOC_GROUPS];
CreateAnimAssocGroups();
}
void
CAnimManager::CreateAnimAssocGroups(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++){
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);
RpClump *clump = (RpClump*)mi->CreateInstance();
RpAnimBlendClumpInit(clump);
CAnimBlendAssocGroup *group = &CAnimManager::ms_aAnimAssocGroups[i];
const AnimAssocDefinition *def = &CAnimManager::ms_aAnimAssocDefinitions[i];
CAnimBlendAssocGroup *group = &ms_aAnimAssocGroups[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);
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
@ -767,15 +861,16 @@ CAnimManager::LoadAnimFiles(void)
void
CAnimManager::LoadAnimFile(const char *filename)
{
int fd;
fd = CFileMgr::OpenFile(filename, "rb");
assert(fd > 0);
LoadAnimFile(fd, true);
CFileMgr::CloseFile(fd);
RwStream *stream;
stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename);
assert(stream);
LoadAnimFile(stream, true);
RwStreamClose(stream, nil);
}
//--MIAMI: done (except maybe implement some unimplemented compression?)
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)
struct IfpHeader {
@ -783,60 +878,63 @@ CAnimManager::LoadAnimFile(int fd, bool compress)
uint32 size;
};
IfpHeader anpk, info, name, dgan, cpan, anim;
int numANPK;
char buf[256];
int i, j, k, l;
int j, k, l;
float *fbuf = (float*)buf;
CFileMgr::Read(fd, (char*)&anpk, sizeof(IfpHeader));
if(strncmp(anpk.ident, "ANLF", 4) == 0){
// block name
RwStreamRead(stream, &anpk, sizeof(IfpHeader));
ROUNDSIZE(anpk.size);
CFileMgr::Read(fd, buf, anpk.size);
numANPK = *(int*)buf;
}else if(strncmp(anpk.ident, "ANPK", 4) == 0){
CFileMgr::Seek(fd, -8, 1);
numANPK = 1;
RwStreamRead(stream, &info, sizeof(IfpHeader));
ROUNDSIZE(info.size);
RwStreamRead(stream, buf, info.size);
CAnimBlock *animBlock = GetAnimationBlock(buf+4);
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++){
// 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;
debug("Loading ANIMS %s\n", animBlock->name);
animBlock->isLoaded = true;
int animIndex = animBlock->firstIndex;
for(j = 0; j < animBlock->numAnims; j++){
CAnimBlendHierarchy *hier = &ms_aAnimations[ms_numAnimations++];
CAnimBlendHierarchy *hier = &ms_aAnimations[animIndex++];
// animation name
CFileMgr::Read(fd, (char*)&name, sizeof(IfpHeader));
RwStreamRead(stream, &name, sizeof(IfpHeader));
ROUNDSIZE(name.size);
CFileMgr::Read(fd, buf, 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
CFileMgr::Read(fd, (char*)&dgan, sizeof(IfpHeader));
RwStreamRead(stream, (char*)&dgan, sizeof(IfpHeader));
ROUNDSIZE(dgan.size);
CFileMgr::Read(fd, (char*)&info, sizeof(IfpHeader));
RwStreamRead(stream, (char*)&info, sizeof(IfpHeader));
ROUNDSIZE(info.size);
CFileMgr::Read(fd, buf, info.size);
RwStreamRead(stream, 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));
RwStreamRead(stream, &cpan, sizeof(IfpHeader));
ROUNDSIZE(dgan.size);
CFileMgr::Read(fd, (char*)&anim, sizeof(IfpHeader));
RwStreamRead(stream, &anim, sizeof(IfpHeader));
ROUNDSIZE(anim.size);
CFileMgr::Read(fd, buf, anim.size);
RwStreamRead(stream, buf, anim.size);
int numFrames = *(int*)(buf+28);
#ifdef PED_SKIN
if(anim.size == 44)
@ -846,12 +944,12 @@ CAnimManager::LoadAnimFile(int fd, bool compress)
if(numFrames == 0)
continue;
CFileMgr::Read(fd, (char*)&info, sizeof(info));
RwStreamRead(stream, &info, sizeof(info));
if(strncmp(info.ident, "KR00", 4) == 0){
seq->SetNumFrames(numFrames, false);
seq->SetNumFrames(numFrames, false, false);
KeyFrame *kf = seq->GetKeyFrame(0);
for(l = 0; l < numFrames; l++, kf++){
CFileMgr::Read(fd, buf, 0x14);
RwStreamRead(stream, buf, 0x14);
kf->rotation.x = -fbuf[0];
kf->rotation.y = -fbuf[1];
kf->rotation.z = -fbuf[2];
@ -859,10 +957,10 @@ CAnimManager::LoadAnimFile(int fd, bool compress)
kf->deltaTime = fbuf[4]; // absolute time here
}
}else if(strncmp(info.ident, "KRT0", 4) == 0){
seq->SetNumFrames(numFrames, true);
seq->SetNumFrames(numFrames, true, false);
KeyFrameTrans *kf = (KeyFrameTrans*)seq->GetKeyFrame(0);
for(l = 0; l < numFrames; l++, kf++){
CFileMgr::Read(fd, buf, 0x20);
RwStreamRead(stream, buf, 0x20);
kf->rotation.x = -fbuf[0];
kf->rotation.y = -fbuf[1];
kf->rotation.z = -fbuf[2];
@ -873,10 +971,10 @@ CAnimManager::LoadAnimFile(int fd, bool compress)
kf->deltaTime = fbuf[7]; // absolute time here
}
}else if(strncmp(info.ident, "KRTS", 4) == 0){
seq->SetNumFrames(numFrames, true);
seq->SetNumFrames(numFrames, true, false);
KeyFrameTrans *kf = (KeyFrameTrans*)seq->GetKeyFrame(0);
for(l = 0; l < numFrames; l++, kf++){
CFileMgr::Read(fd, buf, 0x2C);
RwStreamRead(stream, buf, 0x2C);
kf->rotation.x = -fbuf[0];
kf->rotation.y = -fbuf[1];
kf->rotation.z = -fbuf[2];
@ -889,21 +987,21 @@ CAnimManager::LoadAnimFile(int fd, bool compress)
}
}
/*
// 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();
}
}
if(animIndex > ms_numAnimations)
ms_numAnimations = animIndex;
}
void
@ -913,5 +1011,6 @@ CAnimManager::RemoveLastAnimFile(void)
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();
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_ROCKETRIGHT,
NUM_ANIM_ASSOC_GROUPS
NUM_ANIM_ASSOC_GROUPS // should be 61 in the end
};
class CAnimBlendAssociation;
class CAnimBlendAssocGroup;
#define MAX_ANIMBLOCK_NAME 20
// A block of hierarchies
struct CAnimBlock
{
char name[24];
int32 firstIndex;
char name[MAX_ANIMBLOCK_NAME];
bool isLoaded;
int16 refCount;
int32 firstIndex; // first animtion in ms_aAnimations
int32 numAnims;
};
@ -64,8 +68,8 @@ struct AnimAssocDefinition
class CAnimManager
{
static const AnimAssocDefinition ms_aAnimAssocDefinitions[NUM_ANIM_ASSOC_GROUPS];
static CAnimBlock ms_aAnimBlocks[2];
static CAnimBlendHierarchy ms_aAnimations[250];
static CAnimBlock ms_aAnimBlocks[NUMANIMBLOCKS];
static CAnimBlendHierarchy ms_aAnimations[NUMANIMATIONS];
static int32 ms_numAnimBlocks;
static int32 ms_numAnimations;
static CAnimBlendAssocGroup *ms_aAnimAssocGroups;
@ -75,7 +79,15 @@ public:
static void Initialise(void);
static void Shutdown(void);
static void UncompressAnimation(CAnimBlendHierarchy *anim);
static void RemoveFromUncompressedCache(CAnimBlendHierarchy *hier);
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(int32 n) { return &ms_aAnimations[n]; }
static const char *GetAnimGroupName(AssocGroupId groupId);
@ -87,6 +99,7 @@ public:
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 LoadAnimFile(RwStream *stream, bool compress, char (*somename)[32] = nil);
static void CreateAnimAssocGroups(void);
static void RemoveLastAnimFile(void);
};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -5,7 +5,8 @@
enum {
STREAM_OFFSET_TXD = MODELINFOSIZE,
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
@ -118,16 +119,19 @@ public:
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 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 CanRemoveTxd(int32 id) { return CanRemoveModel(id+STREAM_OFFSET_TXD); }
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 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 ReRequestTxd(int32 txd) { ReRequestModel(txd + STREAM_OFFSET_TXD); }
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 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, const CVector &pos);
static void InstanceBigBuildings(eLevelName level, const CVector &pos);
@ -140,6 +144,7 @@ public:
static void RemoveModel(int32 id);
static void RemoveTxd(int32 id) { RemoveModel(id + STREAM_OFFSET_TXD); }
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 RemoveBuildings(eLevelName level);
static void RemoveUnusedBigBuildings(eLevelName level);
@ -149,7 +154,6 @@ public:
static bool RemoveLeastUsedModel(uint32 excludeMask);
static void RemoveAllUnusedModels(void);
static void RemoveUnusedModelsInLoadedList(void);
static bool RemoveReferencedTxds(int32 mem);
static int32 GetAvailableVehicleSlot(void);
static bool IsTxdUsedByRequestedModels(int32 txdId);
static bool AddToLoadedVehiclesList(int32 modelId);

View file

@ -187,6 +187,7 @@ public:
#if (defined(_MSC_VER))
extern int strcasecmp(const char *str1, const char *str2);
extern int strncasecmp(const char *str1, const char *str2, size_t len);
#endif
#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
// TODO(MIAMI): colmodel pool
NUMANIMBLOCKS = 35,
NUMANIMATIONS = 450,
NUMTEMPOBJECTS = 30,
// Path data

View file

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

View file

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