Jedi Academy Release
This commit is contained in:
commit
684d1bcb3b
|
@ -0,0 +1,774 @@
|
||||||
|
// leave this as first line for PCH reasons...
|
||||||
|
//
|
||||||
|
#pragma warning( disable : 4786)
|
||||||
|
#pragma warning( disable : 4100)
|
||||||
|
#pragma warning( disable : 4663)
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include "..\smartheap\smrtheap.h"
|
||||||
|
#include "../game/q_shared.h"
|
||||||
|
#include "..\qcommon\qcommon.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#if MEM_DEBUG
|
||||||
|
#include "..\smartheap\heapagnt.h"
|
||||||
|
|
||||||
|
static const int maxStack=2048;
|
||||||
|
static int TotalMem;
|
||||||
|
static int TotalBlocks;
|
||||||
|
static int nStack;
|
||||||
|
static char StackNames[maxStack][256];
|
||||||
|
static int StackSize[maxStack];
|
||||||
|
static int StackCount[maxStack];
|
||||||
|
static int StackCache[48];
|
||||||
|
static int StackCacheAt=0;
|
||||||
|
static int CheckpointSize[3000];
|
||||||
|
static int CheckpointCount[3000];
|
||||||
|
|
||||||
|
//#define _FASTRPT_
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _FASTRPT_
|
||||||
|
class CMyStrComparator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool operator()(const char *s1, const char *s2) const { return(strcmp(s1, s2) < 0); }
|
||||||
|
};
|
||||||
|
|
||||||
|
hmap<const char *,int,CMyStrComparator> Lookup;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
cvar_t *mem_leakfile;
|
||||||
|
cvar_t *mem_leakreport;
|
||||||
|
|
||||||
|
MEM_BOOL MEM_CALLBACK MyMemReporter2(MEM_ERROR_INFO *info)
|
||||||
|
{
|
||||||
|
static char buffer[10000];
|
||||||
|
if (!info->objectCreationInfo)
|
||||||
|
return 1;
|
||||||
|
info=info->objectCreationInfo;
|
||||||
|
int idx=info->checkpoint;
|
||||||
|
if (idx<0||idx>=1000)
|
||||||
|
{
|
||||||
|
idx=0;
|
||||||
|
}
|
||||||
|
CheckpointCount[idx]++;
|
||||||
|
CheckpointSize[idx]+=info->argSize;
|
||||||
|
dbgMemFormatCall(info,buffer,9999);
|
||||||
|
if (strstr(buffer,"ntdll"))
|
||||||
|
return 1;
|
||||||
|
if (strstr(buffer,"CLBCATQ"))
|
||||||
|
return 1;
|
||||||
|
int i;
|
||||||
|
TotalBlocks++;
|
||||||
|
if (TotalBlocks%1000==0)
|
||||||
|
{
|
||||||
|
char mess[1000];
|
||||||
|
sprintf(mess,"%d blocks processed\n",TotalBlocks);
|
||||||
|
OutputDebugString(mess);
|
||||||
|
}
|
||||||
|
for (i=strlen(buffer);i>0;i--)
|
||||||
|
{
|
||||||
|
if (buffer[i]=='\n')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!i)
|
||||||
|
return 1;
|
||||||
|
buffer[i]=0;
|
||||||
|
char *buf=buffer;
|
||||||
|
while (*buf)
|
||||||
|
{
|
||||||
|
if (*buf=='\n')
|
||||||
|
{
|
||||||
|
buf++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf++;
|
||||||
|
}
|
||||||
|
char *start=0;
|
||||||
|
char *altName=0;
|
||||||
|
while (*buf)
|
||||||
|
{
|
||||||
|
while (*buf==' ')
|
||||||
|
buf++;
|
||||||
|
start=buf;
|
||||||
|
while (*buf!=0&&*buf!='\n')
|
||||||
|
buf++;
|
||||||
|
if (*start)
|
||||||
|
{
|
||||||
|
if (*buf)
|
||||||
|
{
|
||||||
|
*buf=0;
|
||||||
|
buf++;
|
||||||
|
}
|
||||||
|
if (strlen(start)>255)
|
||||||
|
start[255]=0;
|
||||||
|
if (strstr(start,"std::"))
|
||||||
|
{
|
||||||
|
altName="std::??";
|
||||||
|
// start=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strstr(start,"Malloc"))
|
||||||
|
{
|
||||||
|
altName="Malloc??";
|
||||||
|
start=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strstr(start,"G_Alloc"))
|
||||||
|
{
|
||||||
|
altName="G_Alloc";
|
||||||
|
start=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strstr(start,"Hunk_Alloc"))
|
||||||
|
{
|
||||||
|
altName="Hunk_Alloc";
|
||||||
|
start=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strstr(start,"FS_LoadFile"))
|
||||||
|
{
|
||||||
|
altName="FS_LoadFile";
|
||||||
|
start=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strstr(start,"CopyString"))
|
||||||
|
{
|
||||||
|
altName="CopyString";
|
||||||
|
start=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!start||!*start)
|
||||||
|
{
|
||||||
|
start=altName;
|
||||||
|
if (!start||!*start)
|
||||||
|
{
|
||||||
|
start="UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef _FASTRPT_
|
||||||
|
hmap<const char *,int,CMyStrComparator>::iterator f=Lookup.find(start);
|
||||||
|
if(f==Lookup.end())
|
||||||
|
{
|
||||||
|
strcpy(StackNames[nStack++],start);
|
||||||
|
Lookup[(const char *)&StackNames[nStack-1]]=nStack-1;
|
||||||
|
StackSize[nStack-1]=info->argSize;
|
||||||
|
StackCount[nStack-1]=1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StackSize[(*f).second]+=info->argSize;
|
||||||
|
StackCount[(*f).second]++;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
for (i=0;i<48;i++)
|
||||||
|
{
|
||||||
|
if (StackCache[i]<0||StackCache[i]>=nStack)
|
||||||
|
continue;
|
||||||
|
if (!strcmpi(start,StackNames[StackCache[i]]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i<48)
|
||||||
|
{
|
||||||
|
StackSize[StackCache[i]]+=info->argSize;
|
||||||
|
StackCount[StackCache[i]]++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i=0;i<nStack;i++)
|
||||||
|
{
|
||||||
|
if (!strcmpi(start,StackNames[i]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i<nStack)
|
||||||
|
{
|
||||||
|
StackSize[i]+=info->argSize;
|
||||||
|
StackCount[i]++;
|
||||||
|
StackCache[StackCacheAt]=i;
|
||||||
|
StackCacheAt++;
|
||||||
|
if (StackCacheAt>=48)
|
||||||
|
StackCacheAt=0;
|
||||||
|
}
|
||||||
|
else if (i<maxStack)
|
||||||
|
{
|
||||||
|
strcpy(StackNames[i],start);
|
||||||
|
StackSize[i]=info->argSize;
|
||||||
|
StackCount[i]=1;
|
||||||
|
nStack++;
|
||||||
|
}
|
||||||
|
else if (nStack<maxStack)
|
||||||
|
{
|
||||||
|
nStack++;
|
||||||
|
strcpy(StackNames[maxStack-1],"*****OTHER*****");
|
||||||
|
StackSize[maxStack-1]=info->argSize;
|
||||||
|
StackCount[maxStack-1]=1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StackSize[maxStack-1]+=info->argSize;
|
||||||
|
StackCount[maxStack-1]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
TotalMem+=info->argSize;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_BOOL MEM_CALLBACK MyMemReporter3(MEM_ERROR_INFO *info)
|
||||||
|
{
|
||||||
|
static char buffer[10000];
|
||||||
|
if (!info->objectCreationInfo)
|
||||||
|
return 1;
|
||||||
|
info=info->objectCreationInfo;
|
||||||
|
int idx=info->checkpoint;
|
||||||
|
if (idx<0||idx>=3000)
|
||||||
|
{
|
||||||
|
idx=0;
|
||||||
|
}
|
||||||
|
CheckpointCount[idx]++;
|
||||||
|
CheckpointSize[idx]+=info->argSize;
|
||||||
|
dbgMemFormatCall(info,buffer,9999);
|
||||||
|
int i;
|
||||||
|
TotalBlocks++;
|
||||||
|
// if (TotalBlocks%1000==0)
|
||||||
|
// {
|
||||||
|
// char mess[1000];
|
||||||
|
// sprintf(mess,"%d blocks processed\n",TotalBlocks);
|
||||||
|
// OutputDebugString(mess);
|
||||||
|
// }
|
||||||
|
for (i=strlen(buffer);i>0;i--)
|
||||||
|
{
|
||||||
|
if (buffer[i]=='\n')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!i)
|
||||||
|
return 1;
|
||||||
|
buffer[i]=0;
|
||||||
|
char *buf=buffer;
|
||||||
|
while (*buf)
|
||||||
|
{
|
||||||
|
if (*buf=='\n')
|
||||||
|
{
|
||||||
|
buf++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf++;
|
||||||
|
}
|
||||||
|
char *start=0;
|
||||||
|
char *altName=0;
|
||||||
|
while (*buf)
|
||||||
|
{
|
||||||
|
while (*buf==' ')
|
||||||
|
buf++;
|
||||||
|
start=buf;
|
||||||
|
while (*buf!=0&&*buf!='\n')
|
||||||
|
buf++;
|
||||||
|
if (*start)
|
||||||
|
{
|
||||||
|
if (*buf)
|
||||||
|
{
|
||||||
|
*buf=0;
|
||||||
|
buf++;
|
||||||
|
}
|
||||||
|
if (strlen(start)>255)
|
||||||
|
start[255]=0;
|
||||||
|
if (strstr(start,"SV_AreaEntities"))
|
||||||
|
{
|
||||||
|
altName="SV_AreaEntities??";
|
||||||
|
start=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strstr(start,"SV_Trace"))
|
||||||
|
{
|
||||||
|
altName="SV_Trace??";
|
||||||
|
start=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strstr(start,"SV_PointContents"))
|
||||||
|
{
|
||||||
|
altName="SV_PointContents??";
|
||||||
|
start=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strstr(start,"CG_Trace"))
|
||||||
|
{
|
||||||
|
altName="??";
|
||||||
|
start=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strstr(start,"CG_PointContents"))
|
||||||
|
{
|
||||||
|
altName="??";
|
||||||
|
start=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
if (strstr(start,""))
|
||||||
|
{
|
||||||
|
altName="??";
|
||||||
|
start=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strstr(start,""))
|
||||||
|
{
|
||||||
|
altName="??";
|
||||||
|
start=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!start||!*start)
|
||||||
|
{
|
||||||
|
start=altName;
|
||||||
|
if (!start||!*start)
|
||||||
|
{
|
||||||
|
start="UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef _FASTRPT_
|
||||||
|
hmap<const char *,int,CMyStrComparator>::iterator f=Lookup.find(start);
|
||||||
|
if(f==Lookup.end())
|
||||||
|
{
|
||||||
|
strcpy(StackNames[nStack++],start);
|
||||||
|
Lookup[(const char *)&StackNames[nStack-1]]=nStack-1;
|
||||||
|
StackSize[nStack-1]=info->argSize;
|
||||||
|
StackCount[nStack-1]=1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StackSize[(*f).second]+=info->argSize;
|
||||||
|
StackCount[(*f).second]++;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
for (i=0;i<48;i++)
|
||||||
|
{
|
||||||
|
if (StackCache[i]<0||StackCache[i]>=nStack)
|
||||||
|
continue;
|
||||||
|
if (!strcmpi(start,StackNames[StackCache[i]]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i<48)
|
||||||
|
{
|
||||||
|
StackSize[StackCache[i]]+=info->argSize;
|
||||||
|
StackCount[StackCache[i]]++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i=0;i<nStack;i++)
|
||||||
|
{
|
||||||
|
if (!strcmpi(start,StackNames[i]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i<nStack)
|
||||||
|
{
|
||||||
|
StackSize[i]+=info->argSize;
|
||||||
|
StackCount[i]++;
|
||||||
|
StackCache[StackCacheAt]=i;
|
||||||
|
StackCacheAt++;
|
||||||
|
if (StackCacheAt>=48)
|
||||||
|
StackCacheAt=0;
|
||||||
|
}
|
||||||
|
else if (i<maxStack)
|
||||||
|
{
|
||||||
|
strcpy(StackNames[i],start);
|
||||||
|
StackSize[i]=info->argSize;
|
||||||
|
StackCount[i]=1;
|
||||||
|
nStack++;
|
||||||
|
}
|
||||||
|
else if (nStack<maxStack)
|
||||||
|
{
|
||||||
|
nStack++;
|
||||||
|
strcpy(StackNames[maxStack-1],"*****OTHER*****");
|
||||||
|
StackSize[maxStack-1]=info->argSize;
|
||||||
|
StackCount[maxStack-1]=1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StackSize[maxStack-1]+=info->argSize;
|
||||||
|
StackCount[maxStack-1]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
TotalMem+=info->argSize;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SH_Checking_f(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class Leakage
|
||||||
|
{
|
||||||
|
MEM_POOL MyPool;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Leakage()
|
||||||
|
{
|
||||||
|
MyPool = MemInitDefaultPool();
|
||||||
|
// MemPoolSetSmallBlockSize(MyPool, 16);
|
||||||
|
MemPoolSetSmallBlockAllocator(MyPool,MEM_SMALL_BLOCK_SH3);
|
||||||
|
#if MEM_DEBUG
|
||||||
|
dbgMemSetGuardSize(2);
|
||||||
|
EnableChecking(100000);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void LeakReport(void)
|
||||||
|
{
|
||||||
|
#if MEM_DEBUG
|
||||||
|
|
||||||
|
// This just makes sure we have map nodes available without allocation
|
||||||
|
// during the heap walk (which could be bad).
|
||||||
|
int i;
|
||||||
|
#ifdef _FASTRPT_
|
||||||
|
hlist<int> makeSureWeHaveNodes;
|
||||||
|
for(i=0;i<5000;i++)
|
||||||
|
{
|
||||||
|
makeSureWeHaveNodes.push_back(0);
|
||||||
|
}
|
||||||
|
makeSureWeHaveNodes.clear();
|
||||||
|
Lookup.clear();
|
||||||
|
#endif
|
||||||
|
char mess[1000];
|
||||||
|
int blocks=dbgMemTotalCount();
|
||||||
|
int mem=dbgMemTotalSize()/1024;
|
||||||
|
sprintf(mess,"Final Memory Summary %d blocks %d K\n",blocks,mem);
|
||||||
|
OutputDebugString(mess);
|
||||||
|
|
||||||
|
for (i=0;i<3000;i++)
|
||||||
|
{
|
||||||
|
CheckpointSize[i]=0;
|
||||||
|
CheckpointCount[i]=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TotalMem=0;
|
||||||
|
TotalBlocks=0;
|
||||||
|
nStack=0;
|
||||||
|
MemSetErrorHandler(MyMemReporter2);
|
||||||
|
dbgMemReportLeakage(NULL,1,1000);
|
||||||
|
MemSetErrorHandler(MemDefaultErrorHandler);
|
||||||
|
multimap<int,pair<int,char *> > sortit;
|
||||||
|
multimap<int,pair<int,char *> >::iterator j;
|
||||||
|
if (TotalBlocks)
|
||||||
|
{
|
||||||
|
// Sort by size.
|
||||||
|
Sleep(100);
|
||||||
|
OutputDebugString("**************************************\n");
|
||||||
|
OutputDebugString("**********Memory Leak Report**********\n");
|
||||||
|
OutputDebugString("*************** By Size **************\n");
|
||||||
|
OutputDebugString("**************************************\n");
|
||||||
|
sprintf(mess,"Actual leakage %d blocks %d K\n",TotalBlocks,TotalMem/1024);
|
||||||
|
OutputDebugString(mess);
|
||||||
|
sortit.clear();
|
||||||
|
for (i=0;i<nStack;i++)
|
||||||
|
sortit.insert(pair<int,pair<int,char *> >(-StackSize[i],pair<int,char *>(StackCount[i],StackNames[i])));
|
||||||
|
Sleep(5);
|
||||||
|
for (j=sortit.begin();j!=sortit.end();j++)
|
||||||
|
{
|
||||||
|
sprintf(mess,"%5d KB %6d cnt %s\n",-(*j).first/1024,(*j).second.first,(*j).second.second);
|
||||||
|
// if (!(-(*j).first/1024))
|
||||||
|
// break;
|
||||||
|
Sleep(5);
|
||||||
|
OutputDebugString(mess);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort by count.
|
||||||
|
Sleep(100);
|
||||||
|
OutputDebugString("**************************************\n");
|
||||||
|
OutputDebugString("**********Memory Leak Report**********\n");
|
||||||
|
OutputDebugString("************** By Count **************\n");
|
||||||
|
OutputDebugString("**************************************\n");
|
||||||
|
sprintf(mess,"Actual leakage %d blocks %d K\n",TotalBlocks,TotalMem/1024);
|
||||||
|
OutputDebugString(mess);
|
||||||
|
sortit.clear();
|
||||||
|
for (i=0;i<nStack;i++)
|
||||||
|
sortit.insert(pair<int,pair<int,char *> >(-StackCount[i],pair<int,char *>(StackSize[i],StackNames[i])));
|
||||||
|
Sleep(5);
|
||||||
|
for (j=sortit.begin();j!=sortit.end();j++)
|
||||||
|
{
|
||||||
|
sprintf(mess,"%5d KB %6d cnt %s\n",(*j).second.first/1024,-(*j).first,(*j).second.second);
|
||||||
|
// if (!(-(*j).first/1024))
|
||||||
|
// break;
|
||||||
|
Sleep(5);
|
||||||
|
OutputDebugString(mess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OutputDebugString("No Memory Leaks\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
TotalMem=0;
|
||||||
|
TotalBlocks=0;
|
||||||
|
nStack=0;
|
||||||
|
MemSetErrorHandler(MyMemReporter3);
|
||||||
|
dbgMemReportLeakage(NULL,2001,2001);
|
||||||
|
MemSetErrorHandler(MemDefaultErrorHandler);
|
||||||
|
if (TotalBlocks)
|
||||||
|
{
|
||||||
|
// Sort by count.
|
||||||
|
Sleep(100);
|
||||||
|
OutputDebugString("**************************************\n");
|
||||||
|
OutputDebugString("SV_PointContents ");
|
||||||
|
sprintf(mess,"%d Calls.\n",TotalBlocks);
|
||||||
|
OutputDebugString(mess);
|
||||||
|
OutputDebugString("**************************************\n");
|
||||||
|
sortit.clear();
|
||||||
|
for (i=0;i<nStack;i++)
|
||||||
|
sortit.insert(pair<int,pair<int,char *> >(-StackCount[i],pair<int,char *>(StackSize[i],StackNames[i])));
|
||||||
|
Sleep(5);
|
||||||
|
for (j=sortit.begin();j!=sortit.end();j++)
|
||||||
|
{
|
||||||
|
sprintf(mess,"%7d cnt %s\n",-(*j).first,(*j).second.second);
|
||||||
|
Sleep(5);
|
||||||
|
OutputDebugString(mess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TotalMem=0;
|
||||||
|
TotalBlocks=0;
|
||||||
|
nStack=0;
|
||||||
|
MemSetErrorHandler(MyMemReporter3);
|
||||||
|
dbgMemReportLeakage(NULL,2002,2002);
|
||||||
|
MemSetErrorHandler(MemDefaultErrorHandler);
|
||||||
|
if (TotalBlocks)
|
||||||
|
{
|
||||||
|
// Sort by count.
|
||||||
|
Sleep(100);
|
||||||
|
OutputDebugString("**************************************\n");
|
||||||
|
OutputDebugString("SV_Trace ");
|
||||||
|
sprintf(mess,"%d Calls.\n",TotalBlocks);
|
||||||
|
OutputDebugString(mess);
|
||||||
|
OutputDebugString("**************************************\n");
|
||||||
|
sortit.clear();
|
||||||
|
for (i=0;i<nStack;i++)
|
||||||
|
sortit.insert(pair<int,pair<int,char *> >(-StackCount[i],pair<int,char *>(StackSize[i],StackNames[i])));
|
||||||
|
Sleep(5);
|
||||||
|
for (j=sortit.begin();j!=sortit.end();j++)
|
||||||
|
{
|
||||||
|
sprintf(mess,"%7d cnt %s\n",-(*j).first,(*j).second.second);
|
||||||
|
Sleep(5);
|
||||||
|
OutputDebugString(mess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TotalMem=0;
|
||||||
|
TotalBlocks=0;
|
||||||
|
nStack=0;
|
||||||
|
MemSetErrorHandler(MyMemReporter3);
|
||||||
|
dbgMemReportLeakage(NULL,2003,2003);
|
||||||
|
MemSetErrorHandler(MemDefaultErrorHandler);
|
||||||
|
if (TotalBlocks)
|
||||||
|
{
|
||||||
|
// Sort by count.
|
||||||
|
Sleep(100);
|
||||||
|
OutputDebugString("**************************************\n");
|
||||||
|
OutputDebugString("SV_AreaEntities ");
|
||||||
|
sprintf(mess,"%d Calls.\n",TotalBlocks);
|
||||||
|
OutputDebugString(mess);
|
||||||
|
OutputDebugString("**************************************\n");
|
||||||
|
sortit.clear();
|
||||||
|
for (i=0;i<nStack;i++)
|
||||||
|
sortit.insert(pair<int,pair<int,char *> >(-StackCount[i],pair<int,char *>(StackSize[i],StackNames[i])));
|
||||||
|
Sleep(5);
|
||||||
|
for (j=sortit.begin();j!=sortit.end();j++)
|
||||||
|
{
|
||||||
|
sprintf(mess,"%7d cnt %s\n",-(*j).first,(*j).second.second);
|
||||||
|
Sleep(5);
|
||||||
|
OutputDebugString(mess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TotalMem=0;
|
||||||
|
TotalBlocks=0;
|
||||||
|
nStack=0;
|
||||||
|
MemSetErrorHandler(MyMemReporter3);
|
||||||
|
dbgMemReportLeakage(NULL,2004,2004);
|
||||||
|
MemSetErrorHandler(MemDefaultErrorHandler);
|
||||||
|
if (TotalBlocks)
|
||||||
|
{
|
||||||
|
// Sort by count.
|
||||||
|
Sleep(100);
|
||||||
|
OutputDebugString("**************************************\n");
|
||||||
|
OutputDebugString("CG_Trace ");
|
||||||
|
sprintf(mess,"%d Calls.\n",TotalBlocks);
|
||||||
|
OutputDebugString(mess);
|
||||||
|
OutputDebugString("**************************************\n");
|
||||||
|
sortit.clear();
|
||||||
|
for (i=0;i<nStack;i++)
|
||||||
|
sortit.insert(pair<int,pair<int,char *> >(-StackCount[i],pair<int,char *>(StackSize[i],StackNames[i])));
|
||||||
|
Sleep(5);
|
||||||
|
for (j=sortit.begin();j!=sortit.end();j++)
|
||||||
|
{
|
||||||
|
sprintf(mess,"%7d cnt %s\n",-(*j).first,(*j).second.second);
|
||||||
|
Sleep(5);
|
||||||
|
OutputDebugString(mess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TotalMem=0;
|
||||||
|
TotalBlocks=0;
|
||||||
|
nStack=0;
|
||||||
|
MemSetErrorHandler(MyMemReporter3);
|
||||||
|
dbgMemReportLeakage(NULL,2005,2005);
|
||||||
|
MemSetErrorHandler(MemDefaultErrorHandler);
|
||||||
|
if (TotalBlocks)
|
||||||
|
{
|
||||||
|
// Sort by count.
|
||||||
|
Sleep(100);
|
||||||
|
OutputDebugString("**************************************\n");
|
||||||
|
OutputDebugString("CG_PointContents ");
|
||||||
|
sprintf(mess,"%d Calls.\n",TotalBlocks);
|
||||||
|
OutputDebugString(mess);
|
||||||
|
OutputDebugString("**************************************\n");
|
||||||
|
sortit.clear();
|
||||||
|
for (i=0;i<nStack;i++)
|
||||||
|
sortit.insert(pair<int,pair<int,char *> >(-StackCount[i],pair<int,char *>(StackSize[i],StackNames[i])));
|
||||||
|
Sleep(5);
|
||||||
|
for (j=sortit.begin();j!=sortit.end();j++)
|
||||||
|
{
|
||||||
|
sprintf(mess,"%7d cnt %s\n",-(*j).first,(*j).second.second);
|
||||||
|
Sleep(5);
|
||||||
|
OutputDebugString(mess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if 0 //sw doesn't have the tag stuff
|
||||||
|
// Sort by size.
|
||||||
|
Sleep(5);
|
||||||
|
OutputDebugString("***************************************\n");
|
||||||
|
OutputDebugString("By Tag, sort: size ********************\n");
|
||||||
|
OutputDebugString("size(K) count name \n");
|
||||||
|
OutputDebugString("-----------------------\n");
|
||||||
|
Sleep(5);
|
||||||
|
multimap<int,int> sorted;
|
||||||
|
for (i=0;i<1000;i++)
|
||||||
|
{
|
||||||
|
if (CheckpointCount[i])
|
||||||
|
{
|
||||||
|
sorted.insert(pair<int,int>(-CheckpointSize[i],i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
multimap<int,int>::iterator k;
|
||||||
|
for (k=sorted.begin();k!=sorted.end();k++)
|
||||||
|
{
|
||||||
|
sprintf(mess,"%8d %8d %s\n",CheckpointSize[(*k).second]/1024,CheckpointCount[(*k).second],(*k).second>=2?tagDefs[(*k).second-2]:"unknown");
|
||||||
|
Sleep(5);
|
||||||
|
OutputDebugString(mess);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort by count.
|
||||||
|
Sleep(5);
|
||||||
|
OutputDebugString("By Tag, sort: count *******************\n");
|
||||||
|
OutputDebugString("size(K) count name \n");
|
||||||
|
OutputDebugString("-----------------------\n");
|
||||||
|
Sleep(5);
|
||||||
|
sorted.clear();
|
||||||
|
for (i=0;i<1000;i++)
|
||||||
|
{
|
||||||
|
if (CheckpointCount[i])
|
||||||
|
{
|
||||||
|
sorted.insert(pair<int,int>(-CheckpointCount[i],i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (k=sorted.begin();k!=sorted.end();k++)
|
||||||
|
{
|
||||||
|
sprintf(mess,"%8d %8d %s\n",CheckpointSize[(*k).second]/1024,CheckpointCount[(*k).second],(*k).second>=2?tagDefs[(*k).second-2]:"unknown");
|
||||||
|
Sleep(5);
|
||||||
|
OutputDebugString(mess);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
~Leakage()
|
||||||
|
{
|
||||||
|
#if MEM_DEBUG
|
||||||
|
if (mem_leakfile && mem_leakfile->integer)
|
||||||
|
{
|
||||||
|
dbgMemSetDefaultErrorOutput(DBGMEM_OUTPUT_FILE,"leakage.out");
|
||||||
|
dbgMemReportLeakage(NULL,1,1);
|
||||||
|
dbgMemSetDefaultErrorOutput(DBGMEM_OUTPUT_PROMPT,NULL);
|
||||||
|
}
|
||||||
|
if (mem_leakreport && mem_leakreport->integer)
|
||||||
|
{
|
||||||
|
LeakReport();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#if MEM_DEBUG
|
||||||
|
|
||||||
|
void EnableChecking(int x)
|
||||||
|
{
|
||||||
|
if (x)
|
||||||
|
{
|
||||||
|
dbgMemSetSafetyLevel(MEM_SAFETY_DEBUG);
|
||||||
|
dbgMemPoolSetCheckFrequency(MyPool, x);
|
||||||
|
dbgMemSetCheckFrequency(x);
|
||||||
|
dbgMemDeferFreeing(TRUE);
|
||||||
|
dbgMemSetDeferQueueLen(50000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dbgMemSetSafetyLevel(MEM_SAFETY_SOME);
|
||||||
|
dbgMemDeferFreeing(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
static Leakage TheLeakage;
|
||||||
|
|
||||||
|
#if MEM_DEBUG
|
||||||
|
|
||||||
|
void MEM_Checking_f(void)
|
||||||
|
{
|
||||||
|
if (Cmd_Argc() != 2)
|
||||||
|
{
|
||||||
|
Com_Printf ("mem_checking <frequency>\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (atol(Cmd_Argv(1)) > 0 && atol(Cmd_Argv(1)) < 100)
|
||||||
|
{
|
||||||
|
Com_Printf ("mem_checking frequency is too low ( < 100 )\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TheLeakage.EnableChecking(atol(Cmd_Argv(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MEM_Report_f(void)
|
||||||
|
{
|
||||||
|
if (0)
|
||||||
|
{
|
||||||
|
dbgMemSetDefaultErrorOutput(DBGMEM_OUTPUT_FILE,"leakage.out");
|
||||||
|
dbgMemReportLeakage(NULL,1,1);
|
||||||
|
dbgMemSetDefaultErrorOutput(DBGMEM_OUTPUT_PROMPT,NULL);
|
||||||
|
}
|
||||||
|
TheLeakage.LeakReport();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
void myexit(void)
|
||||||
|
{
|
||||||
|
TheLeakage.LeakReport();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
void SH_Register(void)
|
||||||
|
{
|
||||||
|
Cmd_AddCommand ("mem_checking", MEM_Checking_f);
|
||||||
|
Cmd_AddCommand ("mem_report", MEM_Report_f);
|
||||||
|
|
||||||
|
mem_leakfile = Cvar_Get( "mem_leakfile", "0", 0 );
|
||||||
|
mem_leakreport = Cvar_Get( "mem_leakreport", "1", 0 );
|
||||||
|
// atexit(myexit);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,88 @@
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 7.00
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "game", "game\game.vcproj", "{52D48192-6C71-4D4A-BE26-D05C0E02939C}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "exe", "starwars.vcproj", "{1BE1D500-A2DB-4585-B3D8-50B8D60C5685}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "x_game", "x_game\x_game.vcproj", "{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "x_exe", "x_exe\x_exe.vcproj", "{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "goblib", "goblib\goblib.vcproj", "{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SourceCodeControl) = preSolution
|
||||||
|
SccNumberOfProjects = 2
|
||||||
|
SccProjectUniqueName0 = game\\game.vcproj
|
||||||
|
SccProjectName0 = \u0022$/jedi/code\u0022,\u0020ROBAAAAA
|
||||||
|
SccLocalPath0 = .
|
||||||
|
SccProvider0 = MSSCCI:Microsoft\u0020Visual\u0020SourceSafe
|
||||||
|
SccProjectFilePathRelativizedFromConnection0 = game\\
|
||||||
|
SccProjectUniqueName1 = starwars.vcproj
|
||||||
|
SccProjectName1 = \u0022$/jedi/code\u0022,\u0020ROBAAAAA
|
||||||
|
SccLocalPath1 = .
|
||||||
|
SccProvider1 = MSSCCI:Microsoft\u0020Visual\u0020SourceSafe
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionConfiguration) = preSolution
|
||||||
|
ConfigName.0 = Debug
|
||||||
|
ConfigName.1 = FinalBuild
|
||||||
|
ConfigName.2 = Release
|
||||||
|
ConfigName.3 = SHDebug
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectDependencies) = postSolution
|
||||||
|
{1BE1D500-A2DB-4585-B3D8-50B8D60C5685}.0 = {52D48192-6C71-4D4A-BE26-D05C0E02939C}
|
||||||
|
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.0 = {E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}
|
||||||
|
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.1 = {68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfiguration) = postSolution
|
||||||
|
{52D48192-6C71-4D4A-BE26-D05C0E02939C}.Debug.ActiveCfg = Debug|Win32
|
||||||
|
{52D48192-6C71-4D4A-BE26-D05C0E02939C}.Debug.Build.0 = Debug|Win32
|
||||||
|
{52D48192-6C71-4D4A-BE26-D05C0E02939C}.FinalBuild.ActiveCfg = FinalBuild|Win32
|
||||||
|
{52D48192-6C71-4D4A-BE26-D05C0E02939C}.FinalBuild.Build.0 = FinalBuild|Win32
|
||||||
|
{52D48192-6C71-4D4A-BE26-D05C0E02939C}.Release.ActiveCfg = Release|Win32
|
||||||
|
{52D48192-6C71-4D4A-BE26-D05C0E02939C}.Release.Build.0 = Release|Win32
|
||||||
|
{52D48192-6C71-4D4A-BE26-D05C0E02939C}.SHDebug.ActiveCfg = SHDebug|Win32
|
||||||
|
{1BE1D500-A2DB-4585-B3D8-50B8D60C5685}.Debug.ActiveCfg = Debug|Win32
|
||||||
|
{1BE1D500-A2DB-4585-B3D8-50B8D60C5685}.Debug.Build.0 = Debug|Win32
|
||||||
|
{1BE1D500-A2DB-4585-B3D8-50B8D60C5685}.FinalBuild.ActiveCfg = FinalBuild|Win32
|
||||||
|
{1BE1D500-A2DB-4585-B3D8-50B8D60C5685}.FinalBuild.Build.0 = FinalBuild|Win32
|
||||||
|
{1BE1D500-A2DB-4585-B3D8-50B8D60C5685}.Release.ActiveCfg = Release|Win32
|
||||||
|
{1BE1D500-A2DB-4585-B3D8-50B8D60C5685}.Release.Build.0 = Release|Win32
|
||||||
|
{1BE1D500-A2DB-4585-B3D8-50B8D60C5685}.SHDebug.ActiveCfg = SHDebug|Win32
|
||||||
|
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.Debug.ActiveCfg = Debug|Xbox
|
||||||
|
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.Debug.Build.0 = Debug|Xbox
|
||||||
|
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.FinalBuild.ActiveCfg = FinalBuild|Xbox
|
||||||
|
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.FinalBuild.Build.0 = FinalBuild|Xbox
|
||||||
|
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.Release.ActiveCfg = Release|Xbox
|
||||||
|
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.Release.Build.0 = Release|Xbox
|
||||||
|
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.SHDebug.ActiveCfg = Debug|Xbox
|
||||||
|
{E7A12117-F3B0-4C68-9B44-66CEFCA3AEAA}.SHDebug.Build.0 = Debug|Xbox
|
||||||
|
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.Debug.ActiveCfg = Debug|Xbox
|
||||||
|
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.Debug.Build.0 = Debug|Xbox
|
||||||
|
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.FinalBuild.ActiveCfg = FinalBuild|Xbox
|
||||||
|
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.FinalBuild.Build.0 = FinalBuild|Xbox
|
||||||
|
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.Release.ActiveCfg = Release|Xbox
|
||||||
|
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.Release.Build.0 = Release|Xbox
|
||||||
|
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.SHDebug.ActiveCfg = Debug|Xbox
|
||||||
|
{FD1DA207-0D4A-47A8-A6AD-B81AE1BA28DA}.SHDebug.Build.0 = Debug|Xbox
|
||||||
|
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.Debug.ActiveCfg = Debug|Xbox
|
||||||
|
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.Debug.Build.0 = Debug|Xbox
|
||||||
|
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.FinalBuild.ActiveCfg = FinalBuild|Xbox
|
||||||
|
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.FinalBuild.Build.0 = FinalBuild|Xbox
|
||||||
|
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.Release.ActiveCfg = Release|Xbox
|
||||||
|
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.Release.Build.0 = Release|Xbox
|
||||||
|
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.SHDebug.ActiveCfg = Debug|Xbox
|
||||||
|
{68A067E3-BB9E-435B-9AA3-DD45DB2AA4DB}.SHDebug.Build.0 = Debug|Xbox
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionItems) = postSolution
|
||||||
|
Item:1 = tonet.bat
|
||||||
|
Item:2 = VU.bat
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityAddIns) = postSolution
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(DevPartner) = postSolution
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(DevPartner) = postSolution
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
|
@ -0,0 +1,10 @@
|
||||||
|
""
|
||||||
|
{
|
||||||
|
"FILE_VERSION" = "9237"
|
||||||
|
"ENLISTMENT_CHOICE" = "NEVER"
|
||||||
|
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||||
|
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||||
|
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||||
|
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||||
|
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
|
||||||
|
}
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,480 @@
|
||||||
|
/************************************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (C) 2001-2002 Raven Software
|
||||||
|
*
|
||||||
|
* RM_Area.cpp
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
|
||||||
|
#include "../server/exe_headers.h"
|
||||||
|
|
||||||
|
#include "rm_headers.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#pragma optimize("p", on)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMArea::CRMArea
|
||||||
|
* constructor
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
CRMArea::CRMArea (
|
||||||
|
float spacingRadius,
|
||||||
|
float paddingSize,
|
||||||
|
float confineRadius,
|
||||||
|
vec3_t confineOrigin,
|
||||||
|
vec3_t lookAtOrigin,
|
||||||
|
bool flatten,
|
||||||
|
int symmetric
|
||||||
|
)
|
||||||
|
{
|
||||||
|
mMoveCount = 0;
|
||||||
|
mAngle = 0;
|
||||||
|
mCollision = true;
|
||||||
|
mConfineRadius = confineRadius;
|
||||||
|
mPaddingSize = paddingSize;
|
||||||
|
mSpacingRadius = spacingRadius;
|
||||||
|
mFlatten = flatten;
|
||||||
|
mLookAt = true;
|
||||||
|
mLockOrigin = false;
|
||||||
|
mSymmetric = symmetric;
|
||||||
|
mRadius = spacingRadius;
|
||||||
|
|
||||||
|
VectorCopy ( confineOrigin, mConfineOrigin );
|
||||||
|
VectorCopy ( lookAtOrigin, mLookAtOrigin );
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMArea::LookAt
|
||||||
|
* Angle the area towards the given point
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* lookat - the origin to look at
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* the angle in radians that was calculated
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
float CRMArea::LookAt ( vec3_t lookat )
|
||||||
|
{
|
||||||
|
if (mLookAt)
|
||||||
|
{ // this area orients itself towards a point
|
||||||
|
vec3_t a;
|
||||||
|
|
||||||
|
VectorCopy ( lookat, mLookAtOrigin );
|
||||||
|
VectorSubtract ( lookat, mOrigin, a );
|
||||||
|
|
||||||
|
mAngle = atan2 ( a[1], a[0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
return mAngle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMArea::Mirror
|
||||||
|
* Mirrors the area to the other side of the map. This includes mirroring the confine origin
|
||||||
|
* and lookat origin
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMArea::Mirror ( void )
|
||||||
|
{
|
||||||
|
mOrigin[0] = -mOrigin[0];
|
||||||
|
mOrigin[1] = -mOrigin[1];
|
||||||
|
|
||||||
|
mConfineOrigin[0] = -mConfineOrigin[0];
|
||||||
|
mConfineOrigin[1] = -mConfineOrigin[1];
|
||||||
|
|
||||||
|
mLookAtOrigin[0] = -mLookAtOrigin[0];
|
||||||
|
mLookAtOrigin[1] = -mLookAtOrigin[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMAreaManager::CRMAreaManager
|
||||||
|
* constructor
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
CRMAreaManager::CRMAreaManager ( const vec3_t mins, const vec3_t maxs)
|
||||||
|
{
|
||||||
|
VectorCopy ( mins, mMins );
|
||||||
|
VectorCopy ( maxs, mMaxs );
|
||||||
|
|
||||||
|
mWidth = mMaxs[0] - mMins[0];
|
||||||
|
mHeight = mMaxs[1] - mMins[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMAreaManager::~CRMAreaManager
|
||||||
|
* Removes all managed areas
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
CRMAreaManager::~CRMAreaManager ( )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for ( i = mAreas.size() - 1; i >=0; i -- )
|
||||||
|
{
|
||||||
|
delete mAreas[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
mAreas.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMAreaManager::MoveArea
|
||||||
|
* Moves an area within the area manager thus shifting any other areas as needed
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* area - area to be moved
|
||||||
|
* origin - new origin to attempt to move to
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMAreaManager::MoveArea ( CRMArea* movedArea, vec3_t origin)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
// Increment the addcount (this is for infinite protection)
|
||||||
|
movedArea->AddMoveCount ();
|
||||||
|
|
||||||
|
// Infinite recursion prevention
|
||||||
|
if ( movedArea->GetMoveCount() > 250 )
|
||||||
|
{
|
||||||
|
// assert ( 0 );
|
||||||
|
movedArea->EnableCollision ( false );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First set the area's origin, This may cause it to be in collision with
|
||||||
|
// another area but that will get fixed later
|
||||||
|
movedArea->SetOrigin ( origin );
|
||||||
|
|
||||||
|
// when symmetric we want to ensure that no instances end up on the "other" side of the imaginary diaganol that cuts the map in two
|
||||||
|
// mSymmetric tells us which side of the map is legal
|
||||||
|
if ( movedArea->GetSymmetric ( ) )
|
||||||
|
{
|
||||||
|
const vec3pair_t& bounds = TheRandomMissionManager->GetLandScape()->GetBounds();
|
||||||
|
|
||||||
|
vec3_t point;
|
||||||
|
vec3_t dir;
|
||||||
|
vec3_t tang;
|
||||||
|
bool push;
|
||||||
|
float len;
|
||||||
|
|
||||||
|
VectorSubtract( movedArea->GetOrigin(), bounds[0], point );
|
||||||
|
VectorSubtract( bounds[1], bounds[0], dir );
|
||||||
|
VectorNormalize(dir);
|
||||||
|
|
||||||
|
dir[2] = 0;
|
||||||
|
point[2] = 0;
|
||||||
|
VectorMA( bounds[0], DotProduct(point, dir), dir, tang );
|
||||||
|
VectorSubtract ( movedArea->GetOrigin(), tang, dir );
|
||||||
|
|
||||||
|
dir[2] = 0;
|
||||||
|
push = false;
|
||||||
|
len = VectorNormalize(dir);
|
||||||
|
|
||||||
|
if ( len < movedArea->GetRadius ( ) )
|
||||||
|
{
|
||||||
|
if ( movedArea->GetLockOrigin ( ) )
|
||||||
|
{
|
||||||
|
movedArea->EnableCollision ( false );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VectorMA ( point, (movedArea->GetSpacingRadius() - len) + TheRandomMissionManager->GetLandScape()->irand(10,movedArea->GetSpacingRadius()), dir, point );
|
||||||
|
origin[0] = point[0] + bounds[0][0];
|
||||||
|
origin[1] = point[1] + bounds[0][1];
|
||||||
|
movedArea->SetOrigin ( origin );
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ( movedArea->GetSymmetric ( ) )
|
||||||
|
{
|
||||||
|
case SYMMETRY_TOPLEFT:
|
||||||
|
if ( origin[1] > origin[0] )
|
||||||
|
{
|
||||||
|
movedArea->Mirror ( );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SYMMETRY_BOTTOMRIGHT:
|
||||||
|
if ( origin[1] < origin[0] )
|
||||||
|
{
|
||||||
|
movedArea->Mirror ( );
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// unknown symmetry type
|
||||||
|
assert ( 0 );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confine to area unless we are being pushed back by the same guy who pushed us last time (infinite loop)
|
||||||
|
if ( movedArea->GetConfineRadius() )
|
||||||
|
{
|
||||||
|
if ( movedArea->GetMoveCount() < 25 )
|
||||||
|
{
|
||||||
|
vec3_t cdiff;
|
||||||
|
float cdist;
|
||||||
|
|
||||||
|
VectorSubtract ( movedArea->GetOrigin(), movedArea->GetConfineOrigin(), cdiff );
|
||||||
|
cdiff[2] = 0;
|
||||||
|
cdist = VectorLength ( cdiff );
|
||||||
|
|
||||||
|
if ( cdist + movedArea->GetSpacingRadius() > movedArea->GetConfineRadius() )
|
||||||
|
{
|
||||||
|
cdist = movedArea->GetConfineRadius() - movedArea->GetSpacingRadius();
|
||||||
|
VectorNormalize ( cdiff );
|
||||||
|
|
||||||
|
VectorMA ( movedArea->GetConfineOrigin(), cdist, cdiff, movedArea->GetOrigin());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if it fell off the world in the x direction
|
||||||
|
if ( movedArea->GetOrigin()[0] + movedArea->GetSpacingRadius() > mMaxs[0] )
|
||||||
|
movedArea->GetOrigin()[0] = mMaxs[0] - movedArea->GetSpacingRadius() - (TheRandomMissionManager->GetLandScape()->irand(10,200));
|
||||||
|
else if ( movedArea->GetOrigin()[0] - movedArea->GetSpacingRadius() < mMins[0] )
|
||||||
|
movedArea->GetOrigin()[0] = mMins[0] + movedArea->GetSpacingRadius() + (TheRandomMissionManager->GetLandScape()->irand(10,200));
|
||||||
|
|
||||||
|
// See if it fell off the world in the y direction
|
||||||
|
if ( movedArea->GetOrigin()[1] + movedArea->GetSpacingRadius() > mMaxs[1] )
|
||||||
|
movedArea->GetOrigin()[1] = mMaxs[1] - movedArea->GetSpacingRadius() - (TheRandomMissionManager->GetLandScape()->irand(10,200));
|
||||||
|
else if ( movedArea->GetOrigin()[1] - movedArea->GetSpacingRadius() < mMins[1] )
|
||||||
|
movedArea->GetOrigin()[1] = mMins[1] + movedArea->GetSpacingRadius() + (TheRandomMissionManager->GetLandScape()->irand(10,200));
|
||||||
|
|
||||||
|
// Look at what we need to look at
|
||||||
|
movedArea->LookAt ( movedArea->GetLookAtOrigin() );
|
||||||
|
|
||||||
|
// Dont collide against things that have no collision
|
||||||
|
// if ( !movedArea->IsCollisionEnabled ( ) )
|
||||||
|
// {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// See if its colliding
|
||||||
|
for(index = 0, size = mAreas.size(); index < size; index ++ )
|
||||||
|
{
|
||||||
|
CRMArea *area = mAreas[index];
|
||||||
|
vec3_t diff;
|
||||||
|
vec3_t newOrigin;
|
||||||
|
float dist;
|
||||||
|
float targetdist;
|
||||||
|
|
||||||
|
// Skip the one that was moved in the first place
|
||||||
|
if ( area == movedArea )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( area->GetLockOrigin ( ) && movedArea->GetLockOrigin( ) )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dont collide against things that have no collision
|
||||||
|
if ( !area->IsCollisionEnabled ( ) )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab the distance between the two
|
||||||
|
// only want the horizontal distance -- dmv
|
||||||
|
//dist = Distance ( movedArea->GetOrigin ( ), area->GetOrigin ( ));
|
||||||
|
vec3_t maOrigin;
|
||||||
|
vec3_t aOrigin;
|
||||||
|
VectorCopy(movedArea->GetOrigin(), maOrigin);
|
||||||
|
VectorCopy(area->GetOrigin(), aOrigin);
|
||||||
|
maOrigin[2] = aOrigin[2] = 0;
|
||||||
|
dist = Distance ( maOrigin, aOrigin );
|
||||||
|
targetdist = movedArea->GetSpacingRadius() + area->GetSpacingRadius() + maximum(movedArea->GetPaddingSize(),area->GetPaddingSize());
|
||||||
|
|
||||||
|
if ( dist == 0 )
|
||||||
|
{
|
||||||
|
area->GetOrigin()[0] += (50 * (float)(TheRandomMissionManager->GetLandScape()->irand(0,99))/100.0f);
|
||||||
|
area->GetOrigin()[1] += (50 * (float)(TheRandomMissionManager->GetLandScape()->irand(0,99))/100.0f);
|
||||||
|
|
||||||
|
VectorCopy(area->GetOrigin(), aOrigin);
|
||||||
|
aOrigin[2] = 0;
|
||||||
|
|
||||||
|
dist = Distance ( maOrigin, aOrigin );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Are they are enough apart?
|
||||||
|
if ( dist >= targetdist )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dont move a step if locked
|
||||||
|
if ( area->GetLockOrigin ( ) )
|
||||||
|
{
|
||||||
|
MoveArea ( area, area->GetOrigin ( ) );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we got a collision, move the guy we hit
|
||||||
|
VectorSubtract ( area->GetOrigin(), movedArea->GetOrigin(), diff );
|
||||||
|
diff[2] = 0;
|
||||||
|
VectorNormalize ( diff );
|
||||||
|
|
||||||
|
// Push by the difference in the distance and no-collide radius
|
||||||
|
VectorMA ( area->GetOrigin(), targetdist - dist + 1 , diff, newOrigin );
|
||||||
|
|
||||||
|
// Move the area now
|
||||||
|
MoveArea ( area, newOrigin );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMAreaManager::CreateArea
|
||||||
|
* Creates an area and adds it to the list of managed areas
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* a pointer to the newly added area class
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
CRMArea* CRMAreaManager::CreateArea (
|
||||||
|
vec3_t origin,
|
||||||
|
float spacingRadius,
|
||||||
|
int spacingLine,
|
||||||
|
float paddingSize,
|
||||||
|
float confineRadius,
|
||||||
|
vec3_t confineOrigin,
|
||||||
|
vec3_t lookAtOrigin,
|
||||||
|
bool flatten,
|
||||||
|
bool collide,
|
||||||
|
bool lockorigin,
|
||||||
|
int symmetric
|
||||||
|
)
|
||||||
|
{
|
||||||
|
CRMArea* area = new CRMArea ( spacingRadius, paddingSize, confineRadius, confineOrigin, lookAtOrigin, flatten, symmetric );
|
||||||
|
|
||||||
|
if ( lockorigin || spacingLine )
|
||||||
|
{
|
||||||
|
area->LockOrigin ( );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (origin[0] != lookAtOrigin[0] || origin[1] != lookAtOrigin[1])
|
||||||
|
area->EnableLookAt(true);
|
||||||
|
|
||||||
|
// First add the area to the list
|
||||||
|
mAreas.push_back ( area );
|
||||||
|
|
||||||
|
area->EnableCollision(collide);
|
||||||
|
|
||||||
|
// Set the real radius which is used for center line detection
|
||||||
|
if ( spacingLine )
|
||||||
|
{
|
||||||
|
area->SetRadius ( spacingRadius + (spacingLine - 1) * spacingRadius );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now move the area around
|
||||||
|
MoveArea ( area, origin );
|
||||||
|
|
||||||
|
if ( (origin[0] != lookAtOrigin[0] || origin[1] != lookAtOrigin[1]) )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
vec3_t linedir;
|
||||||
|
vec3_t dir;
|
||||||
|
vec3_t up = {0,0,1};
|
||||||
|
vec3_t zerodvec;
|
||||||
|
|
||||||
|
VectorClear(zerodvec);
|
||||||
|
|
||||||
|
VectorSubtract ( lookAtOrigin, origin, dir );
|
||||||
|
VectorNormalize ( dir );
|
||||||
|
dir[2] = 0;
|
||||||
|
CrossProduct ( dir, up, linedir );
|
||||||
|
|
||||||
|
for ( i = 0; i < spacingLine - 1; i ++ )
|
||||||
|
{
|
||||||
|
CRMArea* linearea;
|
||||||
|
vec3_t lineorigin;
|
||||||
|
|
||||||
|
linearea = new CRMArea ( spacingRadius, paddingSize, 0, zerodvec, zerodvec, false, symmetric );
|
||||||
|
linearea->LockOrigin ( );
|
||||||
|
linearea->EnableCollision(collide);
|
||||||
|
|
||||||
|
VectorMA ( origin, spacingRadius + (spacingRadius * 2 * i), linedir, lineorigin );
|
||||||
|
mAreas.push_back ( linearea );
|
||||||
|
MoveArea ( linearea, lineorigin );
|
||||||
|
|
||||||
|
linearea = new CRMArea ( spacingRadius, paddingSize, 0, zerodvec, zerodvec, false, symmetric );
|
||||||
|
linearea->LockOrigin ( );
|
||||||
|
linearea->EnableCollision(collide);
|
||||||
|
|
||||||
|
VectorMA ( origin, -spacingRadius - (spacingRadius * 2 * i), linedir, lineorigin );
|
||||||
|
mAreas.push_back ( linearea );
|
||||||
|
MoveArea ( linearea, lineorigin );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return it for convienience
|
||||||
|
return area;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMAreaManager::EnumArea
|
||||||
|
* Allows for enumeration through the area list. If an invalid index is given then NULL will
|
||||||
|
* be returned;
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* index - current enumeration index
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* requested area class pointer or NULL if the index was invalid
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
CRMArea* CRMAreaManager::EnumArea ( const int index )
|
||||||
|
{
|
||||||
|
// This isnt an assertion case because there is no size method for
|
||||||
|
// the area manager so the areas are enumerated until NULL is returned.
|
||||||
|
if ( index < 0 || index >= mAreas.size ( ) )
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mAreas[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#pragma optimize("p", off)
|
||||||
|
#endif
|
|
@ -0,0 +1,99 @@
|
||||||
|
/************************************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (C) 2001-2002 Raven Software
|
||||||
|
*
|
||||||
|
* RM_Area.h
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#if !defined(RM_AREA_H_INC)
|
||||||
|
#define RM_AREA_H_INC
|
||||||
|
|
||||||
|
#ifdef DEBUG_LINKING
|
||||||
|
#pragma message("...including RM_Area.h")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CRMArea
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
float mPaddingSize;
|
||||||
|
float mSpacingRadius;
|
||||||
|
float mConfineRadius;
|
||||||
|
float mRadius;
|
||||||
|
float mAngle;
|
||||||
|
int mMoveCount;
|
||||||
|
vec3_t mOrigin;
|
||||||
|
vec3_t mConfineOrigin;
|
||||||
|
vec3_t mLookAtOrigin;
|
||||||
|
bool mCollision;
|
||||||
|
bool mFlatten;
|
||||||
|
bool mLookAt;
|
||||||
|
bool mLockOrigin;
|
||||||
|
int mSymmetric;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CRMArea ( float spacing, float padding, float confine, vec3_t confineOrigin, vec3_t lookAtOrigin, bool flatten = true, int symmetric = 0 );
|
||||||
|
|
||||||
|
void Mirror ( void );
|
||||||
|
|
||||||
|
void SetOrigin(vec3_t origin) { VectorCopy ( origin, mOrigin ); }
|
||||||
|
void SetAngle(float angle) { mAngle = angle; }
|
||||||
|
void SetSymmetric(int sym) { mSymmetric = sym; }
|
||||||
|
|
||||||
|
void EnableCollision(bool e) { mCollision = e; }
|
||||||
|
void EnableLookAt(bool la) {mLookAt = la; }
|
||||||
|
|
||||||
|
float LookAt(vec3_t lookat);
|
||||||
|
void LockOrigin( void ) { mLockOrigin = true; }
|
||||||
|
|
||||||
|
void AddMoveCount() { mMoveCount++; }
|
||||||
|
void ClearMoveCount() { mMoveCount=0; }
|
||||||
|
|
||||||
|
float GetPaddingSize() { return mPaddingSize; }
|
||||||
|
float GetSpacingRadius() { return mSpacingRadius; }
|
||||||
|
float GetRadius() { return mRadius; }
|
||||||
|
float GetConfineRadius() { return mConfineRadius; }
|
||||||
|
float GetAngle() { return mAngle; }
|
||||||
|
int GetMoveCount() { return mMoveCount; }
|
||||||
|
vec_t* GetOrigin() { return mOrigin; }
|
||||||
|
vec_t* GetConfineOrigin() { return mConfineOrigin; }
|
||||||
|
vec_t* GetLookAtOrigin() { return mLookAtOrigin; }
|
||||||
|
bool GetLookAt() { return mLookAt;}
|
||||||
|
bool GetLockOrigin() { return mLockOrigin; }
|
||||||
|
int GetSymmetric() { return mSymmetric; }
|
||||||
|
|
||||||
|
void SetRadius(float r) { mRadius = r; }
|
||||||
|
|
||||||
|
bool IsCollisionEnabled(){ return mCollision; }
|
||||||
|
bool IsFlattened (){ return mFlatten; }
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef vector<CRMArea*> rmAreaVector_t;
|
||||||
|
|
||||||
|
class CRMAreaManager
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
rmAreaVector_t mAreas;
|
||||||
|
vec3_t mMins;
|
||||||
|
vec3_t mMaxs;
|
||||||
|
float mWidth;
|
||||||
|
float mHeight;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CRMAreaManager ( const vec3_t mins, const vec3_t maxs );
|
||||||
|
~CRMAreaManager ( );
|
||||||
|
|
||||||
|
CRMArea* CreateArea ( vec3_t origin, float spacing, int spacingline, float padding, float confine, vec3_t confineOrigin, vec3_t lookAtOrigin, bool flatten=true, bool collide=true, bool lockorigin=false, int symmetric=0);
|
||||||
|
void MoveArea ( CRMArea* area, vec3_t origin);
|
||||||
|
CRMArea* EnumArea ( const int index );
|
||||||
|
|
||||||
|
// void CreateMap ( void );
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
#pragma once
|
||||||
|
#if !defined(RM_HEADERS_H_INC)
|
||||||
|
#define RM_HEADERS_H_INC
|
||||||
|
|
||||||
|
#ifdef DEBUG_LINKING
|
||||||
|
#pragma message("...including RM_Headers.h")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma warning (push, 3)
|
||||||
|
#include <vector>
|
||||||
|
#include <list>
|
||||||
|
#pragma warning (pop)
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#if !defined(GENERICPARSER2_H_INC)
|
||||||
|
#include "../game/genericparser2.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(CM_LOCAL_H_INC)
|
||||||
|
#include "../qcommon/cm_local.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MAX_INSTANCE_TRIES 5
|
||||||
|
|
||||||
|
// on a symmetric map which corner is the first node
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SYMMETRY_NONE,
|
||||||
|
SYMMETRY_TOPLEFT,
|
||||||
|
SYMMETRY_BOTTOMRIGHT
|
||||||
|
|
||||||
|
} symmetry_t;
|
||||||
|
|
||||||
|
#if !defined(CM_TERRAINMAP_H_INC)
|
||||||
|
#include "../qcommon/cm_terrainmap.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(RM_AREA_H_INC)
|
||||||
|
#include "RM_Area.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(RM_PATH_H_INC)
|
||||||
|
#include "RM_Path.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(RM_OBJECTIVE_H_INC)
|
||||||
|
#include "RM_Objective.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(RM_INSTANCEFILE_H_INC)
|
||||||
|
#include "RM_InstanceFile.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(RM_INSTANCE_H_INC)
|
||||||
|
#include "RM_Instance.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(RM_MISSION_H_INC)
|
||||||
|
#include "RM_Mission.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(RM_MANAGER_H_INC)
|
||||||
|
#include "RM_Manager.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(RM_TERRAIN_H_INC)
|
||||||
|
#include "RM_Terrain.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,191 @@
|
||||||
|
#include "../server/exe_headers.h"
|
||||||
|
|
||||||
|
#include "rm_headers.h"
|
||||||
|
#include "../qcommon/cm_terrainmap.h"
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMInstance::CRMInstance
|
||||||
|
* constructs a instnace object using the given parser group
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* instance: parser group containing information about the instance
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
CRMInstance::CRMInstance ( CGPGroup *instGroup, CRMInstanceFile& instFile )
|
||||||
|
{
|
||||||
|
mObjective = NULL;
|
||||||
|
mSpacingRadius = 0;
|
||||||
|
mFlattenRadius = 0;
|
||||||
|
mFilter[0] = mTeamFilter[0] = 0;
|
||||||
|
mArea = NULL;
|
||||||
|
mAutomapSymbol = 0;
|
||||||
|
mEntityID = 0;
|
||||||
|
mSide = 0;
|
||||||
|
mMirror = 0;
|
||||||
|
mFlattenHeight = 66;
|
||||||
|
mSpacingLine = 0;
|
||||||
|
mSurfaceSprites = true;
|
||||||
|
mLockOrigin = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMInstance::PreSpawn
|
||||||
|
* Prepares the instance for spawning by flattening the ground under it
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* landscape: landscape the instance will be spawned on
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* true: spawn preparation successful
|
||||||
|
* false: spawn preparation failed
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
bool CRMInstance::PreSpawn ( CRandomTerrain* terrain, qboolean IsServer )
|
||||||
|
{
|
||||||
|
vec3_t origin;
|
||||||
|
CArea area;
|
||||||
|
|
||||||
|
VectorCopy(GetOrigin(), origin);
|
||||||
|
|
||||||
|
if (mMirror)
|
||||||
|
{
|
||||||
|
origin[0] = TheRandomMissionManager->GetLandScape()->GetBounds()[0][0] + TheRandomMissionManager->GetLandScape()->GetBounds()[1][0] - origin[0];
|
||||||
|
origin[1] = TheRandomMissionManager->GetLandScape()->GetBounds()[0][1] + TheRandomMissionManager->GetLandScape()->GetBounds()[1][1] - origin[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
const vec3_t& terxelSize = terrain->GetLandScape()->GetTerxelSize ( );
|
||||||
|
const vec3pair_t& bounds = terrain->GetLandScape()->GetBounds();
|
||||||
|
|
||||||
|
// Align the instance to the center of a terxel
|
||||||
|
origin[0] = bounds[0][0] + (int)((origin[0] - bounds[0][0] + terxelSize[0] / 2) / terxelSize[0]) * terxelSize[0];
|
||||||
|
origin[1] = bounds[0][1] + (int)((origin[1] - bounds[0][1] + terxelSize[1] / 2) / terxelSize[1]) * terxelSize[1];
|
||||||
|
|
||||||
|
|
||||||
|
// This is BAD - By copying the mirrored origin back into the instance, you've now mirrored the original instance
|
||||||
|
// so when anything from this point on looks at the instance they'll be looking at a mirrored version but will be expecting the original
|
||||||
|
// so later in the spawn functions the instance will be re-mirrored, because it thinks the mInstances have not been changed
|
||||||
|
// VectorCopy(origin, GetOrigin());
|
||||||
|
|
||||||
|
// Flatten the area below the instance
|
||||||
|
if ( GetFlattenRadius() )
|
||||||
|
{
|
||||||
|
area.Init( origin, GetFlattenRadius(), 0.0f, AT_NONE, 0, 0 );
|
||||||
|
terrain->GetLandScape()->FlattenArea( &area, mFlattenHeight | (mSurfaceSprites?0:0x80), false, true, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMInstance::PostSpawn
|
||||||
|
* Finishes the spawn by linking any objectives into the world that are associated with it
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* landscape: landscape the instance was spawned on
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* true: post spawn successfull
|
||||||
|
* false: post spawn failed
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
bool CRMInstance::PostSpawn ( CRandomTerrain* terrain, qboolean IsServer )
|
||||||
|
{
|
||||||
|
if ( mObjective )
|
||||||
|
{
|
||||||
|
return mObjective->Link ( );
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#ifndef DEDICATED
|
||||||
|
void CRMInstance::DrawAutomapSymbol()
|
||||||
|
{
|
||||||
|
// draw proper symbol on map for instance
|
||||||
|
switch (GetAutomapSymbol())
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case AUTOMAP_NONE:
|
||||||
|
if (HasObjective())
|
||||||
|
CM_TM_AddObjective(GetOrigin()[0], GetOrigin()[1], GetSide());
|
||||||
|
break;
|
||||||
|
case AUTOMAP_BLD:
|
||||||
|
CM_TM_AddBuilding(GetOrigin()[0], GetOrigin()[1], GetSide());
|
||||||
|
if (HasObjective())
|
||||||
|
CM_TM_AddObjective(GetOrigin()[0], GetOrigin()[1], GetSide());
|
||||||
|
break;
|
||||||
|
case AUTOMAP_OBJ:
|
||||||
|
CM_TM_AddObjective(GetOrigin()[0], GetOrigin()[1], GetSide());
|
||||||
|
break;
|
||||||
|
case AUTOMAP_START:
|
||||||
|
CM_TM_AddStart(GetOrigin()[0], GetOrigin()[1], GetSide());
|
||||||
|
break;
|
||||||
|
case AUTOMAP_END:
|
||||||
|
CM_TM_AddEnd(GetOrigin()[0], GetOrigin()[1], GetSide());
|
||||||
|
break;
|
||||||
|
case AUTOMAP_ENEMY:
|
||||||
|
if (HasObjective())
|
||||||
|
CM_TM_AddObjective(GetOrigin()[0], GetOrigin()[1]);
|
||||||
|
if (1 == Cvar_VariableIntegerValue("rmg_automapshowall"))
|
||||||
|
CM_TM_AddNPC(GetOrigin()[0], GetOrigin()[1], false);
|
||||||
|
break;
|
||||||
|
case AUTOMAP_FRIEND:
|
||||||
|
if (HasObjective())
|
||||||
|
CM_TM_AddObjective(GetOrigin()[0], GetOrigin()[1]);
|
||||||
|
if (1 == Cvar_VariableIntegerValue("rmg_automapshowall"))
|
||||||
|
CM_TM_AddNPC(GetOrigin()[0], GetOrigin()[1], true);
|
||||||
|
break;
|
||||||
|
case AUTOMAP_WALL:
|
||||||
|
CM_TM_AddWallRect(GetOrigin()[0], GetOrigin()[1], GetSide());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // !DEDICATED
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMInstance::Preview
|
||||||
|
* Renderings debug information about the instance
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMInstance::Preview ( const vec3_t from )
|
||||||
|
{
|
||||||
|
/* CEntity *tent;
|
||||||
|
|
||||||
|
// Add a cylindar for the whole settlement
|
||||||
|
tent = G_TempEntity( GetOrigin(), EV_DEBUG_CYLINDER );
|
||||||
|
VectorCopy( GetOrigin(), tent->s.origin2 );
|
||||||
|
tent->s.pos.trBase[2] += 40;
|
||||||
|
tent->s.origin2[2] += 50;
|
||||||
|
tent->s.time = 1050 + ((int)(GetSpacingRadius())<<16);
|
||||||
|
tent->s.time2 = GetPreviewColor ( );
|
||||||
|
G_AddTempEntity(tent);
|
||||||
|
|
||||||
|
// Origin line
|
||||||
|
tent = G_TempEntity( GetOrigin ( ), EV_DEBUG_LINE );
|
||||||
|
VectorCopy( GetOrigin(), tent->s.origin2 );
|
||||||
|
tent->s.origin2[2] += 400;
|
||||||
|
tent->s.time = 1050;
|
||||||
|
tent->s.weapon = 10;
|
||||||
|
tent->s.time2 = (255<<24) + (255<<16) + (255<<8) + 255;
|
||||||
|
G_AddTempEntity(tent);
|
||||||
|
|
||||||
|
if ( GetFlattenRadius ( ) )
|
||||||
|
{
|
||||||
|
// Add a cylindar for the whole settlement
|
||||||
|
tent = G_TempEntity( GetOrigin(), EV_DEBUG_CYLINDER );
|
||||||
|
VectorCopy( GetOrigin(), tent->s.origin2 );
|
||||||
|
tent->s.pos.trBase[2] += 40;
|
||||||
|
tent->s.origin2[2] += 50;
|
||||||
|
tent->s.time = 1050 + ((int)(GetFlattenRadius ( ))<<16);
|
||||||
|
tent->s.time2 = (255<<24) + (80<<16) +(80<<8) + 80;
|
||||||
|
G_AddTempEntity(tent);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
#pragma once
|
||||||
|
#if !defined(RM_INSTANCE_H_INC)
|
||||||
|
#define RM_INSTANCE_H_INC
|
||||||
|
|
||||||
|
#ifdef DEBUG_LINKING
|
||||||
|
#pragma message("...including RM_Instance.h")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(CM_LANDSCAPE_H_INC)
|
||||||
|
#include "../qcommon/cm_landscape.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum CRMAutomapSymbol
|
||||||
|
{
|
||||||
|
AUTOMAP_NONE = 0,
|
||||||
|
AUTOMAP_BLD = 1,
|
||||||
|
AUTOMAP_OBJ = 2,
|
||||||
|
AUTOMAP_START= 3,
|
||||||
|
AUTOMAP_END = 4,
|
||||||
|
AUTOMAP_ENEMY= 5,
|
||||||
|
AUTOMAP_FRIEND=6,
|
||||||
|
AUTOMAP_WALL=7
|
||||||
|
};
|
||||||
|
|
||||||
|
class CRMInstance
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
char mFilter[MAX_QPATH]; // filter of entities inside of this
|
||||||
|
char mTeamFilter[MAX_QPATH]; // team specific filter
|
||||||
|
|
||||||
|
vec3pair_t mBounds; // Bounding box for instance itself
|
||||||
|
|
||||||
|
CRMArea* mArea; // Position of the instance
|
||||||
|
|
||||||
|
CRMObjective* mObjective; // Objective associated with this instance
|
||||||
|
|
||||||
|
// optional instance specific strings for objective
|
||||||
|
string mMessage; // message outputed when objective is completed
|
||||||
|
string mDescription; // description of objective
|
||||||
|
string mInfo; // more info for objective
|
||||||
|
|
||||||
|
float mSpacingRadius; // Radius to space instances with
|
||||||
|
float mFlattenRadius; // Radius to flatten under instances
|
||||||
|
|
||||||
|
int mSpacingLine; // Line of spacing radius's, forces locket
|
||||||
|
bool mLockOrigin; // Origin cant move
|
||||||
|
|
||||||
|
bool mSurfaceSprites; // allow surface sprites under instance?
|
||||||
|
|
||||||
|
int mAutomapSymbol; // show which symbol on automap 0=none
|
||||||
|
|
||||||
|
int mEntityID; // id of entity spawned
|
||||||
|
int mSide; // blue or red side
|
||||||
|
int mMirror; // mirror origin, angle
|
||||||
|
|
||||||
|
int mFlattenHeight; // height to flatten land
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CRMInstance ( CGPGroup* instance, CRMInstanceFile& instFile);
|
||||||
|
|
||||||
|
virtual ~CRMInstance ( ) { }
|
||||||
|
|
||||||
|
virtual bool IsValid ( ) { return true; }
|
||||||
|
|
||||||
|
virtual bool PreSpawn ( CRandomTerrain* terrain, qboolean IsServer );
|
||||||
|
virtual bool Spawn ( CRandomTerrain* terrain, qboolean IsServer ) { return false; }
|
||||||
|
virtual bool PostSpawn ( CRandomTerrain* terrain, qboolean IsServer );
|
||||||
|
|
||||||
|
virtual void Preview ( const vec3_t from );
|
||||||
|
|
||||||
|
virtual void SetArea ( CRMAreaManager* amanager, CRMArea* area ) { mArea = area; }
|
||||||
|
virtual void SetFilter ( const char *filter ) { strcpy(mFilter, filter); }
|
||||||
|
virtual void SetTeamFilter ( const char *teamFilter ) { strcpy(mTeamFilter, teamFilter); }
|
||||||
|
void SetObjective ( CRMObjective* obj ) { mObjective = obj; }
|
||||||
|
CRMObjective* GetObjective (void) {return mObjective;}
|
||||||
|
bool HasObjective () {return mObjective != NULL;}
|
||||||
|
int GetAutomapSymbol () {return mAutomapSymbol;}
|
||||||
|
void DrawAutomapSymbol ();
|
||||||
|
const char* GetMessage(void) { return mMessage.c_str(); }
|
||||||
|
const char* GetDescription(void){ return mDescription.c_str(); }
|
||||||
|
const char* GetInfo(void) { return mInfo.c_str(); }
|
||||||
|
void SetMessage(const char* msg) { mMessage = msg; }
|
||||||
|
void SetDescription(const char* desc) { mDescription = desc; }
|
||||||
|
void SetInfo(const char* info) { mInfo = info; }
|
||||||
|
void SetSide(int side) {mSide = side;}
|
||||||
|
int GetSide ( ) {return mSide;}
|
||||||
|
|
||||||
|
// NOTE: should consider making SetMirror also set all other variables that need flipping
|
||||||
|
// like the origin and Side, etc... Otherwise an Instance may have had it's origin flipped
|
||||||
|
// but then later will have mMirror set to false, but the origin is still flipped. So any functions
|
||||||
|
// that look at the instance later will see mMirror set to false, but not realize the origin has ALREADY been flipped
|
||||||
|
virtual void SetMirror(int mirror) { mMirror = mirror;}
|
||||||
|
int GetMirror ( ) { return mMirror;}
|
||||||
|
|
||||||
|
virtual bool GetSurfaceSprites ( ) { return mSurfaceSprites; }
|
||||||
|
|
||||||
|
virtual bool GetLockOrigin ( ) { return mLockOrigin; }
|
||||||
|
virtual int GetSpacingLine ( ) { return mSpacingLine; }
|
||||||
|
|
||||||
|
virtual int GetPreviewColor ( ) { return 0; }
|
||||||
|
virtual float GetSpacingRadius ( ) { return mSpacingRadius; }
|
||||||
|
virtual float GetFlattenRadius ( ) { return mFlattenRadius; }
|
||||||
|
const char *GetFilter ( ) { return mFilter; }
|
||||||
|
const char *GetTeamFilter ( ) { return mTeamFilter; }
|
||||||
|
|
||||||
|
CRMArea& GetArea ( ) { return *mArea; }
|
||||||
|
vec_t* GetOrigin ( ) {return mArea->GetOrigin(); }
|
||||||
|
float GetAngle ( ) {return mArea->GetAngle();}
|
||||||
|
void SetAngle(float ang ) { mArea->SetAngle(ang);}
|
||||||
|
const vec3pair_t& GetBounds(void) const { return(mBounds); }
|
||||||
|
|
||||||
|
void SetFlattenHeight ( int height ) { mFlattenHeight = height; }
|
||||||
|
int GetFlattenHeight ( void ) { return mFlattenHeight; }
|
||||||
|
|
||||||
|
void SetSpacingRadius (float spacing) { mSpacingRadius = spacing; }
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef list<CRMInstance*>::iterator rmInstanceIter_t;
|
||||||
|
typedef list<CRMInstance*> rmInstanceList_t;
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,200 @@
|
||||||
|
/************************************************************************************************
|
||||||
|
*
|
||||||
|
* RM_InstanceFile.cpp
|
||||||
|
*
|
||||||
|
* implements the CRMInstanceFile class. This class provides functionality to load
|
||||||
|
* and create instances from an instance file. First call Open to open the instance file and
|
||||||
|
* then use CreateInstance to create new instances. When finished call Close to cleanup.
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
|
||||||
|
#include "../server/exe_headers.h"
|
||||||
|
|
||||||
|
#include "rm_headers.h"
|
||||||
|
|
||||||
|
//#include "rm_instance_npc.h"
|
||||||
|
#include "rm_instance_bsp.h"
|
||||||
|
#include "rm_instance_random.h"
|
||||||
|
#include "rm_instance_group.h"
|
||||||
|
#include "rm_instance_void.h"
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMInstanceFile::CRMInstanceFile
|
||||||
|
* constructor
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
CRMInstanceFile::CRMInstanceFile ( )
|
||||||
|
{
|
||||||
|
mInstances = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMInstanceFile::~CRMInstanceFile
|
||||||
|
* Destroys the instance file by freeing the parser
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
CRMInstanceFile::~CRMInstanceFile ( )
|
||||||
|
{
|
||||||
|
Close ( );
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMInstanceFile::Open
|
||||||
|
* Opens the given instance file and prepares it for use in instance creation
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* instance: Name of instance to open. Note that the root path will be automatically
|
||||||
|
* added and shouldnt be included in the given name
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* true: instance file successfully loaded
|
||||||
|
* false: instance file could not be loaded for some reason
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
bool CRMInstanceFile::Open ( const char* instance )
|
||||||
|
{
|
||||||
|
char instanceDef[MAX_QPATH];
|
||||||
|
CGPGroup *basegroup;
|
||||||
|
|
||||||
|
// Build the filename
|
||||||
|
Com_sprintf(instanceDef, MAX_QPATH, "ext_data/rmg/%s.instance", instance );
|
||||||
|
|
||||||
|
#ifndef FINAL_BUILD
|
||||||
|
// Debug message
|
||||||
|
Com_Printf("CM_Terrain: Loading and parsing instanceDef %s.....\n", instance);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Parse the text file using the generic parser
|
||||||
|
if(!Com_ParseTextFile(instanceDef, mParser ))
|
||||||
|
{
|
||||||
|
Com_sprintf(instanceDef, MAX_QPATH, "ext_data/arioche/%s.instance", instance );
|
||||||
|
if(!Com_ParseTextFile(instanceDef, mParser ))
|
||||||
|
{
|
||||||
|
Com_Printf(va("CM_Terrain: Could not open instance file '%s'\n", instanceDef));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The whole file....
|
||||||
|
basegroup = mParser.GetBaseParseGroup();
|
||||||
|
|
||||||
|
// The root { } struct
|
||||||
|
mInstances = basegroup->GetSubGroups();
|
||||||
|
|
||||||
|
// The "instances" { } structure
|
||||||
|
mInstances = mInstances->GetSubGroups ( );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMInstanceFile::Close
|
||||||
|
* Closes an open instance file
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMInstanceFile::Close ( void )
|
||||||
|
{
|
||||||
|
// If not open then dont close it
|
||||||
|
if ( NULL == mInstances )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mParser.Clean();
|
||||||
|
|
||||||
|
mInstances = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMInstanceFile::CreateInstance
|
||||||
|
* Creates an instance (to be freed by caller) using the given instance name.
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* name: Name of the instance to read from the instance file
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* NULL: instance could not be read from the instance file
|
||||||
|
* NON-NULL: instance created and returned for further use
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
CRMInstance* CRMInstanceFile::CreateInstance ( const char* name )
|
||||||
|
{
|
||||||
|
static int instanceID = 0;
|
||||||
|
|
||||||
|
CGPGroup* group;
|
||||||
|
CRMInstance* instance;
|
||||||
|
|
||||||
|
// Make sure we were loaded
|
||||||
|
assert ( mInstances );
|
||||||
|
|
||||||
|
// Search through the instances for the one with the given name
|
||||||
|
for ( group = mInstances; group; group = group->GetNext ( ) )
|
||||||
|
{
|
||||||
|
// Skip it if the name doesnt match
|
||||||
|
if ( stricmp ( name, group->FindPairValue ( "name", "" ) ) )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the various forms of instance types
|
||||||
|
if ( !stricmp ( group->GetName ( ), "bsp" ) )
|
||||||
|
{
|
||||||
|
instance = new CRMBSPInstance ( group, *this );
|
||||||
|
}
|
||||||
|
else if ( !stricmp ( group->GetName ( ), "npc" ) )
|
||||||
|
{
|
||||||
|
// instance = new CRMNPCInstance ( group, *this );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if ( !stricmp ( group->GetName ( ), "group" ) )
|
||||||
|
{
|
||||||
|
instance = new CRMGroupInstance ( group, *this );
|
||||||
|
}
|
||||||
|
else if ( !stricmp ( group->GetName ( ), "random" ) )
|
||||||
|
{
|
||||||
|
instance = new CRMRandomInstance ( group, *this );
|
||||||
|
}
|
||||||
|
else if ( !stricmp ( group->GetName ( ), "void" ) )
|
||||||
|
{
|
||||||
|
instance = new CRMVoidInstance ( group, *this );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the instance isnt valid after being created then delete it
|
||||||
|
if ( !instance->IsValid ( ) )
|
||||||
|
{
|
||||||
|
delete instance;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The instance was successfully created so return it
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef FINAL_BUILD
|
||||||
|
// The instance wasnt found in the file so report it
|
||||||
|
Com_Printf(va("WARNING: Instance '%s' was not found in the active instance file\n", name ));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
#pragma once
|
||||||
|
#if !defined(RM_INSTANCEFILE_H_INC)
|
||||||
|
#define RM_INSTANCEFILE_H_INC
|
||||||
|
|
||||||
|
#ifdef DEBUG_LINKING
|
||||||
|
#pragma message("...including RM_InstanceFile.h")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CRMInstance;
|
||||||
|
|
||||||
|
class CRMInstanceFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
CRMInstanceFile ( );
|
||||||
|
~CRMInstanceFile ( );
|
||||||
|
|
||||||
|
bool Open ( const char* instance );
|
||||||
|
void Close ( void );
|
||||||
|
CRMInstance* CreateInstance ( const char* name );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
CGenericParser2 mParser;
|
||||||
|
CGPGroup* mInstances;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,294 @@
|
||||||
|
/************************************************************************************************
|
||||||
|
*
|
||||||
|
* RM_Instance_BSP.cpp
|
||||||
|
*
|
||||||
|
* Implements the CRMBSPInstance class. This class is reponsible for parsing a
|
||||||
|
* bsp instance as well as spawning it into a landscape.
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
|
||||||
|
#include "../server/exe_headers.h"
|
||||||
|
|
||||||
|
#include "../qcommon/cm_local.h"
|
||||||
|
#include "../server/server.h"
|
||||||
|
#include "rm_headers.h"
|
||||||
|
|
||||||
|
#include "rm_instance_bsp.h"
|
||||||
|
|
||||||
|
#include "../client/vmachine.h"
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMBSPInstance::CRMBSPInstance
|
||||||
|
* constructs a building instance object using the given parser group
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* instance: parser group containing information about the building instance
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
CRMBSPInstance::CRMBSPInstance(CGPGroup *instGroup, CRMInstanceFile& instFile) : CRMInstance ( instGroup, instFile )
|
||||||
|
{
|
||||||
|
strcpy(mBsp, instGroup->FindPairValue("file", ""));
|
||||||
|
|
||||||
|
mAngleVariance = DEG2RAD(atof(instGroup->FindPairValue("anglevariance", "0")));
|
||||||
|
mBaseAngle = DEG2RAD(atof(instGroup->FindPairValue("baseangle", "0")));
|
||||||
|
mAngleDiff = DEG2RAD(atof(instGroup->FindPairValue("anglediff", "0")));
|
||||||
|
mSpacingRadius = atof( instGroup->FindPairValue ( "spacing", "100" ) );
|
||||||
|
mSpacingLine = atoi( instGroup->FindPairValue ( "spacingline", "0" ) );
|
||||||
|
mSurfaceSprites = (!Q_stricmp ( instGroup->FindPairValue ( "surfacesprites", "no" ), "yes")) ? true : false;
|
||||||
|
mLockOrigin = (!Q_stricmp ( instGroup->FindPairValue ( "lockorigin", "no" ), "yes")) ? true : false;
|
||||||
|
mFlattenRadius = atof( instGroup->FindPairValue ( "flatten", "0" ) );
|
||||||
|
mHoleRadius = atof( instGroup->FindPairValue ( "hole", "0" ) );
|
||||||
|
|
||||||
|
const char * automapSymName = instGroup->FindPairValue ( "automap_symbol", "building" );
|
||||||
|
if (0 == strcmpi(automapSymName, "none")) mAutomapSymbol = AUTOMAP_NONE ;
|
||||||
|
else if (0 == strcmpi(automapSymName, "building")) mAutomapSymbol = AUTOMAP_BLD ;
|
||||||
|
else if (0 == strcmpi(automapSymName, "objective")) mAutomapSymbol = AUTOMAP_OBJ ;
|
||||||
|
else if (0 == strcmpi(automapSymName, "start")) mAutomapSymbol = AUTOMAP_START;
|
||||||
|
else if (0 == strcmpi(automapSymName, "end")) mAutomapSymbol = AUTOMAP_END ;
|
||||||
|
else if (0 == strcmpi(automapSymName, "enemy")) mAutomapSymbol = AUTOMAP_ENEMY;
|
||||||
|
else if (0 == strcmpi(automapSymName, "friend")) mAutomapSymbol = AUTOMAP_FRIEND;
|
||||||
|
else if (0 == strcmpi(automapSymName, "wall")) mAutomapSymbol = AUTOMAP_WALL;
|
||||||
|
else mAutomapSymbol = atoi( automapSymName );
|
||||||
|
|
||||||
|
// optional instance objective strings
|
||||||
|
SetMessage(instGroup->FindPairValue("objective_message",""));
|
||||||
|
SetDescription(instGroup->FindPairValue("objective_description",""));
|
||||||
|
SetInfo(instGroup->FindPairValue("objective_info",""));
|
||||||
|
|
||||||
|
mBounds[0][0] = 0;
|
||||||
|
mBounds[0][1] = 0;
|
||||||
|
mBounds[1][0] = 0;
|
||||||
|
mBounds[1][1] = 0;
|
||||||
|
|
||||||
|
mBaseAngle += (TheRandomMissionManager->GetLandScape()->irand(0,mAngleVariance) - mAngleVariance/2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMBSPInstance::Spawn
|
||||||
|
* spawns a bsp into the world using the previously aquired origin
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
bool CRMBSPInstance::Spawn ( CRandomTerrain* terrain, qboolean IsServer)
|
||||||
|
{
|
||||||
|
#ifndef PRE_RELEASE_DEMO
|
||||||
|
// TEntity* ent;
|
||||||
|
float yaw;
|
||||||
|
char temp[10000];
|
||||||
|
char *savePtr;
|
||||||
|
vec3_t origin;
|
||||||
|
vec3_t notmirrored;
|
||||||
|
float water_level = terrain->GetLandScape()->GetWaterHeight();
|
||||||
|
|
||||||
|
const vec3_t& terxelSize = terrain->GetLandScape()->GetTerxelSize ( );
|
||||||
|
const vec3pair_t& bounds = terrain->GetLandScape()->GetBounds();
|
||||||
|
|
||||||
|
// If this entity somehow lost its collision flag then boot it
|
||||||
|
if ( !GetArea().IsCollisionEnabled ( ) )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy out the unmirrored version
|
||||||
|
VectorCopy(GetOrigin(), notmirrored);
|
||||||
|
|
||||||
|
// we want to mirror it before determining the Z value just in case the landscape isn't perfectly mirrored
|
||||||
|
if (mMirror)
|
||||||
|
{
|
||||||
|
GetOrigin()[0] = TheRandomMissionManager->GetLandScape()->GetBounds()[0][0] + TheRandomMissionManager->GetLandScape()->GetBounds()[1][0] - GetOrigin()[0];
|
||||||
|
GetOrigin()[1] = TheRandomMissionManager->GetLandScape()->GetBounds()[0][1] + TheRandomMissionManager->GetLandScape()->GetBounds()[1][1] - GetOrigin()[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Align the instance to the center of a terxel
|
||||||
|
GetOrigin ( )[0] = bounds[0][0] + (int)((GetOrigin ( )[0] - bounds[0][0] + terxelSize[0] / 2) / terxelSize[0]) * terxelSize[0];
|
||||||
|
GetOrigin ( )[1] = bounds[0][1] + (int)((GetOrigin ( )[1] - bounds[0][1] + terxelSize[1] / 2) / terxelSize[1]) * terxelSize[1];
|
||||||
|
|
||||||
|
// Make sure the bsp is resting on the ground, not below or above it
|
||||||
|
// NOTE: This check is basically saying "is this instance not a bridge", because when instances are created they are all
|
||||||
|
// placed above the world's Z boundary, EXCEPT FOR BRIDGES. So this call to GetWorldHeight will move all other instances down to
|
||||||
|
// ground level except bridges
|
||||||
|
if ( GetOrigin()[2] > terrain->GetBounds()[1][2] )
|
||||||
|
{
|
||||||
|
if( GetFlattenRadius() )
|
||||||
|
{
|
||||||
|
terrain->GetLandScape()->GetWorldHeight ( GetOrigin(), GetBounds ( ), false );
|
||||||
|
GetOrigin()[2] += 5;
|
||||||
|
}
|
||||||
|
else if (IsServer)
|
||||||
|
{ // if this instance does not flatten the ground around it, do a trace to more accurately determine its Z value
|
||||||
|
trace_t tr;
|
||||||
|
vec3_t end;
|
||||||
|
vec3_t start;
|
||||||
|
|
||||||
|
VectorCopy(GetOrigin(), end);
|
||||||
|
VectorCopy(GetOrigin(), start);
|
||||||
|
// start the trace below the top height of the landscape
|
||||||
|
start[2] = TheRandomMissionManager->GetLandScape()->GetBounds()[1][2] - 1;
|
||||||
|
// end the trace at the bottom of the world
|
||||||
|
end[2] = MIN_WORLD_COORD;
|
||||||
|
|
||||||
|
memset ( &tr, 0, sizeof ( tr ) );
|
||||||
|
SV_Trace( &tr, start, vec3_origin, vec3_origin, end, ENTITYNUM_NONE, CONTENTS_TERRAIN|CONTENTS_SOLID, G2_NOCOLLIDE, 0); //qfalse, 0, 10 );
|
||||||
|
|
||||||
|
if( !(tr.contents & CONTENTS_TERRAIN) || (tr.fraction == 1.0) )
|
||||||
|
{
|
||||||
|
if ( 0 )
|
||||||
|
assert(0); // this should never happen
|
||||||
|
|
||||||
|
// restore the unmirrored origin
|
||||||
|
VectorCopy( notmirrored, GetOrigin() );
|
||||||
|
// don't spawn
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// assign the Z-value to wherever it hit the terrain
|
||||||
|
GetOrigin()[2] = tr.endpos[2];
|
||||||
|
// lower it a little, otherwise the bottom of the instance might be exposed if on some weird sloped terrain
|
||||||
|
GetOrigin()[2] -= 16; // FIXME: would it be better to use a number related to the instance itself like 1/5 it's height or something...
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
terrain->GetLandScape()->GetWorldHeight ( GetOrigin(), GetBounds ( ), true );
|
||||||
|
}
|
||||||
|
|
||||||
|
// save away the origin
|
||||||
|
VectorCopy(GetOrigin(), origin);
|
||||||
|
// make sure not to spawn if in water
|
||||||
|
if (!HasObjective() && GetOrigin()[2] < water_level)
|
||||||
|
return false;
|
||||||
|
// restore the origin
|
||||||
|
VectorCopy(origin, GetOrigin());
|
||||||
|
|
||||||
|
if (mMirror)
|
||||||
|
{ // change blue things to red for symmetric maps
|
||||||
|
if (strlen(mFilter) > 0)
|
||||||
|
{
|
||||||
|
char * blue = strstr(mFilter,"blue");
|
||||||
|
if (blue)
|
||||||
|
{
|
||||||
|
blue[0] = (char) 0;
|
||||||
|
strcat(mFilter, "red");
|
||||||
|
SetSide(SIDE_RED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (strlen(mTeamFilter) > 0)
|
||||||
|
{
|
||||||
|
char * blue = strstr(mTeamFilter,"blue");
|
||||||
|
if (blue)
|
||||||
|
{
|
||||||
|
strcpy(mTeamFilter, "red");
|
||||||
|
SetSide(SIDE_RED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
yaw = RAD2DEG(mArea->GetAngle() + mBaseAngle) + 180;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
yaw = RAD2DEG(mArea->GetAngle() + mBaseAngle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if( TheRandomMissionManager->GetMission()->GetSymmetric() )
|
||||||
|
{
|
||||||
|
vec3_t diagonal;
|
||||||
|
vec3_t lineToPoint;
|
||||||
|
vec3_t mins;
|
||||||
|
vec3_t maxs;
|
||||||
|
vec3_t point;
|
||||||
|
vec3_t vProj;
|
||||||
|
vec3_t vec;
|
||||||
|
float distance;
|
||||||
|
|
||||||
|
VectorCopy( TheRandomMissionManager->GetLandScape()->GetBounds()[1], maxs );
|
||||||
|
VectorCopy( TheRandomMissionManager->GetLandScape()->GetBounds()[0], mins );
|
||||||
|
VectorCopy( GetOrigin(), point );
|
||||||
|
mins[2] = maxs[2] = point[2] = 0;
|
||||||
|
VectorSubtract( point, mins, lineToPoint );
|
||||||
|
VectorSubtract( maxs, mins, diagonal);
|
||||||
|
|
||||||
|
|
||||||
|
VectorNormalize(diagonal);
|
||||||
|
VectorMA( mins, DotProduct(lineToPoint, diagonal), diagonal, vProj);
|
||||||
|
VectorSubtract(point, vProj, vec );
|
||||||
|
distance = VectorLength(vec);
|
||||||
|
|
||||||
|
// if an instance is too close to the imaginary diagonal that cuts the world in half, don't spawn it
|
||||||
|
// otherwise you can get overlapping instances
|
||||||
|
if( distance < GetSpacingRadius() )
|
||||||
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
|
mAutomapSymbol = AUTOMAP_END;
|
||||||
|
#endif
|
||||||
|
if( !HasObjective() )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Spawn in the bsp model
|
||||||
|
sprintf(temp,
|
||||||
|
"{\n"
|
||||||
|
"\"classname\" \"misc_bsp\"\n"
|
||||||
|
"\"bspmodel\" \"%s\"\n"
|
||||||
|
"\"origin\" \"%f %f %f\"\n"
|
||||||
|
"\"angles\" \"0 %f 0\"\n"
|
||||||
|
"\"filter\" \"%s\"\n"
|
||||||
|
"\"teamfilter\" \"%s\"\n"
|
||||||
|
"\"spacing\" \"%d\"\n"
|
||||||
|
"\"flatten\" \"%d\"\n"
|
||||||
|
"}\n",
|
||||||
|
mBsp,
|
||||||
|
GetOrigin()[0], GetOrigin()[1], GetOrigin()[2],
|
||||||
|
AngleNormalize360(yaw),
|
||||||
|
mFilter,
|
||||||
|
mTeamFilter,
|
||||||
|
(int)GetSpacingRadius(),
|
||||||
|
(int)GetFlattenRadius()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (IsServer)
|
||||||
|
{ // only allow for true spawning on the server
|
||||||
|
savePtr = sv.entityParsePoint;
|
||||||
|
sv.entityParsePoint = temp;
|
||||||
|
// VM_Call( cgvm, GAME_SPAWN_RMG_ENTITY );
|
||||||
|
// char *s;
|
||||||
|
int bufferSize = 1024;
|
||||||
|
char buffer[1024];
|
||||||
|
|
||||||
|
// s = COM_Parse( (const char **)&sv.entityParsePoint );
|
||||||
|
Q_strncpyz( buffer, sv.entityParsePoint, bufferSize );
|
||||||
|
if ( sv.entityParsePoint && sv.entityParsePoint[0] )
|
||||||
|
{
|
||||||
|
ge->GameSpawnRMGEntity(sv.entityParsePoint);
|
||||||
|
}
|
||||||
|
sv.entityParsePoint = savePtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef DEDICATED
|
||||||
|
DrawAutomapSymbol();
|
||||||
|
#endif
|
||||||
|
Com_DPrintf( "RMG: Building '%s' spawned at (%f %f %f)\n", mBsp, GetOrigin()[0], GetOrigin()[1], GetOrigin()[2] );
|
||||||
|
// now restore the instances un-mirrored origin
|
||||||
|
// NOTE: all this origin flipping, setting the side etc... should be done when mMirror is set
|
||||||
|
// because right after this function is called, mMirror is set to 0 but all the instance data is STILL MIRRORED -- not good
|
||||||
|
VectorCopy(notmirrored, GetOrigin());
|
||||||
|
|
||||||
|
#endif // PRE_RELEASE_DEMO
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
#pragma once
|
||||||
|
#if !defined(RM_INSTANCE_BSP_H_INC)
|
||||||
|
#define RM_INSTANCE_BSP_H_INC
|
||||||
|
|
||||||
|
#ifdef DEBUG_LINKING
|
||||||
|
#pragma message("...including RM_Instance_BSP.h")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CRMBSPInstance : public CRMInstance
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
char mBsp[MAX_QPATH];
|
||||||
|
float mAngleVariance;
|
||||||
|
float mBaseAngle;
|
||||||
|
float mAngleDiff;
|
||||||
|
|
||||||
|
float mHoleRadius;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CRMBSPInstance ( CGPGroup *instance, CRMInstanceFile& instFile );
|
||||||
|
|
||||||
|
virtual int GetPreviewColor ( ) { return (255<<24)+255; }
|
||||||
|
|
||||||
|
virtual float GetHoleRadius ( ) { return mHoleRadius; }
|
||||||
|
|
||||||
|
virtual bool Spawn ( CRandomTerrain* terrain, qboolean IsServer );
|
||||||
|
|
||||||
|
const char* GetModelName (void) const { return(mBsp); }
|
||||||
|
float GetAngleDiff (void) const { return(mAngleDiff); }
|
||||||
|
bool GetAngularType (void) const { return(mAngleDiff != 0.0f); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,343 @@
|
||||||
|
/************************************************************************************************
|
||||||
|
*
|
||||||
|
* RM_Instance_Group.cpp
|
||||||
|
*
|
||||||
|
* Implements the CRMGroupInstance class. This class is reponsible for parsing a
|
||||||
|
* group instance as well as spawning it into a landscape.
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
|
||||||
|
#include "../server/exe_headers.h"
|
||||||
|
|
||||||
|
#include "rm_headers.h"
|
||||||
|
|
||||||
|
#include "rm_instance_group.h"
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMGroupInstance::CRMGroupInstance
|
||||||
|
* constructur
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* settlementID: ID of the settlement being created
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
CRMGroupInstance::CRMGroupInstance ( CGPGroup *instGroup, CRMInstanceFile& instFile )
|
||||||
|
: CRMInstance ( instGroup, instFile )
|
||||||
|
{
|
||||||
|
// Grab the padding and confine radius
|
||||||
|
mPaddingSize = atof ( instGroup->FindPairValue ( "padding", va("%i", TheRandomMissionManager->GetMission()->GetDefaultPadding() ) ) );
|
||||||
|
mConfineRadius = atof ( instGroup->FindPairValue ( "confine", "0" ) );
|
||||||
|
|
||||||
|
const char * automapSymName = instGroup->FindPairValue ( "automap_symbol", "none" );
|
||||||
|
if (0 == strcmpi(automapSymName, "none")) mAutomapSymbol = AUTOMAP_NONE ;
|
||||||
|
else if (0 == strcmpi(automapSymName, "building")) mAutomapSymbol = AUTOMAP_BLD ;
|
||||||
|
else if (0 == strcmpi(automapSymName, "objective")) mAutomapSymbol = AUTOMAP_OBJ ;
|
||||||
|
else if (0 == strcmpi(automapSymName, "start")) mAutomapSymbol = AUTOMAP_START;
|
||||||
|
else if (0 == strcmpi(automapSymName, "end")) mAutomapSymbol = AUTOMAP_END ;
|
||||||
|
else if (0 == strcmpi(automapSymName, "enemy")) mAutomapSymbol = AUTOMAP_ENEMY;
|
||||||
|
else if (0 == strcmpi(automapSymName, "friend")) mAutomapSymbol = AUTOMAP_FRIEND;
|
||||||
|
else mAutomapSymbol = atoi( automapSymName );
|
||||||
|
|
||||||
|
// optional instance objective strings
|
||||||
|
SetMessage(instGroup->FindPairValue("objective_message",""));
|
||||||
|
SetDescription(instGroup->FindPairValue("objective_description",""));
|
||||||
|
SetInfo(instGroup->FindPairValue("objective_info",""));
|
||||||
|
|
||||||
|
// Iterate through the sub groups to determine the instances which make up the group
|
||||||
|
instGroup = instGroup->GetSubGroups ( );
|
||||||
|
|
||||||
|
while ( instGroup )
|
||||||
|
{
|
||||||
|
CRMInstance* instance;
|
||||||
|
const char* name;
|
||||||
|
int mincount;
|
||||||
|
int maxcount;
|
||||||
|
int count;
|
||||||
|
float minrange;
|
||||||
|
float maxrange;
|
||||||
|
|
||||||
|
// Make sure only instances are specified as sub groups
|
||||||
|
assert ( 0 == stricmp ( instGroup->GetName ( ), "instance" ) );
|
||||||
|
|
||||||
|
// Grab the name
|
||||||
|
name = instGroup->FindPairValue ( "name", "" );
|
||||||
|
|
||||||
|
// Grab the range information
|
||||||
|
minrange = atof(instGroup->FindPairValue ( "minrange", "0" ) );
|
||||||
|
maxrange = atof(instGroup->FindPairValue ( "maxrange", "0" ) );
|
||||||
|
|
||||||
|
// Grab the count information and randomly generate a count value
|
||||||
|
mincount = atoi(instGroup->FindPairValue ( "mincount", "1" ) );
|
||||||
|
maxcount = atoi(instGroup->FindPairValue ( "maxcount", "1" ) );
|
||||||
|
count = mincount;
|
||||||
|
|
||||||
|
if ( maxcount > mincount )
|
||||||
|
{
|
||||||
|
count += (TheRandomMissionManager->GetLandScape()->irand(0, maxcount-mincount));
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each count create and add the instance
|
||||||
|
for ( ; count ; count -- )
|
||||||
|
{
|
||||||
|
// Create the instance
|
||||||
|
instance = instFile.CreateInstance ( name );
|
||||||
|
|
||||||
|
// Skip this instance if it couldnt be created for some reason. The CreateInstance
|
||||||
|
// method will report an error so no need to do so here.
|
||||||
|
if ( NULL == instance )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the min and max range for the instance
|
||||||
|
instance->SetFilter(mFilter);
|
||||||
|
instance->SetTeamFilter(mTeamFilter);
|
||||||
|
|
||||||
|
// Add the instance to the list
|
||||||
|
mInstances.push_back ( instance );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next sub group
|
||||||
|
instGroup = instGroup->GetNext ( );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMGroupInstance::~CRMGroupInstance
|
||||||
|
* Removes all buildings and inhabitants
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
CRMGroupInstance::~CRMGroupInstance(void)
|
||||||
|
{
|
||||||
|
// Cleanup
|
||||||
|
RemoveInstances ( );
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMGroupInstance::SetFilter
|
||||||
|
* Sets a filter used to exclude instances
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* filter: filter name
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMGroupInstance::SetFilter( const char *filter )
|
||||||
|
{
|
||||||
|
rmInstanceIter_t it;
|
||||||
|
|
||||||
|
CRMInstance::SetFilter(filter);
|
||||||
|
for(it = mInstances.begin(); it != mInstances.end(); it++)
|
||||||
|
{
|
||||||
|
(*it)->SetFilter(filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMGroupInstance::SetTeamFilter
|
||||||
|
* Sets the filter used to exclude team based instances
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* teamFilter: filter name
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMGroupInstance::SetTeamFilter( const char *teamFilter )
|
||||||
|
{
|
||||||
|
rmInstanceIter_t it;
|
||||||
|
|
||||||
|
CRMInstance::SetTeamFilter(teamFilter);
|
||||||
|
for(it = mInstances.begin(); it != mInstances.end(); it++)
|
||||||
|
{
|
||||||
|
(*it)->SetTeamFilter(teamFilter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMGroupInstance::SetMirror
|
||||||
|
* Sets the flag to mirror an instance on map
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* mirror
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMGroupInstance::SetMirror(int mirror)
|
||||||
|
{
|
||||||
|
rmInstanceIter_t it;
|
||||||
|
|
||||||
|
CRMInstance::SetMirror(mirror);
|
||||||
|
for(it = mInstances.begin(); it != mInstances.end(); it++)
|
||||||
|
{
|
||||||
|
(*it)->SetMirror(mirror);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMGroupInstance::RemoveInstances
|
||||||
|
* Removes all instances associated with the group
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMGroupInstance::RemoveInstances ( )
|
||||||
|
{
|
||||||
|
rmInstanceIter_t it;
|
||||||
|
|
||||||
|
for(it = mInstances.begin(); it != mInstances.end(); it++)
|
||||||
|
{
|
||||||
|
delete *it;
|
||||||
|
}
|
||||||
|
|
||||||
|
mInstances.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMGroupInstance::PreSpawn
|
||||||
|
* Prepares the group for spawning by
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* landscape: landscape to calculate the position within
|
||||||
|
* instance: instance to calculate the position for
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
bool CRMGroupInstance::PreSpawn ( CRandomTerrain* terrain, qboolean IsServer )
|
||||||
|
{
|
||||||
|
rmInstanceIter_t it;
|
||||||
|
|
||||||
|
for(it = mInstances.begin(); it != mInstances.end(); it++ )
|
||||||
|
{
|
||||||
|
CRMInstance* instance = *it;
|
||||||
|
|
||||||
|
instance->SetFlattenHeight ( mFlattenHeight );
|
||||||
|
|
||||||
|
// Add the instance to the landscape now
|
||||||
|
instance->PreSpawn ( terrain, IsServer );
|
||||||
|
}
|
||||||
|
|
||||||
|
return CRMInstance::PreSpawn ( terrain, IsServer );
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMGroupInstance::Spawn
|
||||||
|
* Adds the group instance to the given landscape using the specified origin. All sub instances
|
||||||
|
* will be added to the landscape within their min and max range from the origin.
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* landscape: landscape to add the instance group to
|
||||||
|
* origin: origin of the instance group
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
bool CRMGroupInstance::Spawn ( CRandomTerrain* terrain, qboolean IsServer )
|
||||||
|
{
|
||||||
|
rmInstanceIter_t it;
|
||||||
|
|
||||||
|
// Spawn all the instances associated with this group
|
||||||
|
for(it = mInstances.begin(); it != mInstances.end(); it++)
|
||||||
|
{
|
||||||
|
CRMInstance* instance = *it;
|
||||||
|
instance->SetSide(GetSide()); // which side owns it?
|
||||||
|
|
||||||
|
// Add the instance to the landscape now
|
||||||
|
instance->Spawn ( terrain, IsServer );
|
||||||
|
}
|
||||||
|
#ifndef DEDICATED
|
||||||
|
DrawAutomapSymbol();
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMGroupInstance::Preview
|
||||||
|
* Renders debug information for the instance
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* from: point to render the preview from
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMGroupInstance::Preview ( const vec3_t from )
|
||||||
|
{
|
||||||
|
rmInstanceIter_t it;
|
||||||
|
|
||||||
|
CRMInstance::Preview ( from );
|
||||||
|
|
||||||
|
// Render all the instances
|
||||||
|
for(it = mInstances.begin(); it != mInstances.end(); it++)
|
||||||
|
{
|
||||||
|
CRMInstance* instance = *it;
|
||||||
|
|
||||||
|
instance->Preview ( from );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMGroupInstance::SetArea
|
||||||
|
* Overidden to make sure the groups area doesnt eat up any room. The collision on the
|
||||||
|
* groups area will be turned off
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* area: area to set
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMGroupInstance::SetArea ( CRMAreaManager* amanager, CRMArea* area )
|
||||||
|
{
|
||||||
|
rmInstanceIter_t it;
|
||||||
|
|
||||||
|
bool collide = area->IsCollisionEnabled ( );
|
||||||
|
|
||||||
|
// Disable collision
|
||||||
|
area->EnableCollision ( false );
|
||||||
|
|
||||||
|
// Do what really needs to get done
|
||||||
|
CRMInstance::SetArea ( amanager, area );
|
||||||
|
|
||||||
|
// Prepare for spawn by calculating all the positions of the sub instances
|
||||||
|
// and flattening the ground below them.
|
||||||
|
for(it = mInstances.begin(); it != mInstances.end(); it++ )
|
||||||
|
{
|
||||||
|
CRMInstance *instance = *it;
|
||||||
|
CRMArea *newarea;
|
||||||
|
vec3_t origin;
|
||||||
|
|
||||||
|
// Drop it in the center of the group for now
|
||||||
|
origin[0] = GetOrigin()[0];
|
||||||
|
origin[1] = GetOrigin()[1];
|
||||||
|
origin[2] = 2500;
|
||||||
|
|
||||||
|
// Set the area of position
|
||||||
|
newarea = amanager->CreateArea ( origin, instance->GetSpacingRadius(), instance->GetSpacingLine(), mPaddingSize, mConfineRadius, GetOrigin(), GetOrigin(), instance->GetFlattenRadius()?true:false, collide, instance->GetLockOrigin(), area->GetSymmetric ( ) );
|
||||||
|
instance->SetArea ( amanager, newarea );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
#pragma once
|
||||||
|
#if !defined(RM_INSTANCE_GROUP_H_INC)
|
||||||
|
#define RM_INSTANCE_GROUP_H_INC
|
||||||
|
|
||||||
|
#ifdef DEBUG_LINKING
|
||||||
|
#pragma message("...including RM_Instance_Group.h")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CRMGroupInstance : public CRMInstance
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
rmInstanceList_t mInstances;
|
||||||
|
float mConfineRadius;
|
||||||
|
float mPaddingSize;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CRMGroupInstance( CGPGroup* instGroup, CRMInstanceFile& instFile);
|
||||||
|
~CRMGroupInstance();
|
||||||
|
|
||||||
|
virtual bool PreSpawn ( CRandomTerrain* terrain, qboolean IsServer );
|
||||||
|
virtual bool Spawn ( CRandomTerrain* terrain, qboolean IsServer );
|
||||||
|
|
||||||
|
virtual void Preview ( const vec3_t from );
|
||||||
|
|
||||||
|
virtual void SetFilter ( const char *filter );
|
||||||
|
virtual void SetTeamFilter ( const char *teamFilter );
|
||||||
|
virtual void SetArea ( CRMAreaManager* amanager, CRMArea* area );
|
||||||
|
|
||||||
|
virtual int GetPreviewColor ( ) { return (255<<24)+(255<<8); }
|
||||||
|
virtual float GetSpacingRadius ( ) { return 0; }
|
||||||
|
virtual float GetFlattenRadius ( ) { return 0; }
|
||||||
|
virtual void SetMirror(int mirror);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void RemoveInstances ( );
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,187 @@
|
||||||
|
/************************************************************************************************
|
||||||
|
*
|
||||||
|
* RM_Instance_Random.cpp
|
||||||
|
*
|
||||||
|
* Implements the CRMRandomInstance class. This class is reponsible for parsing a
|
||||||
|
* random instance as well as spawning it into a landscape.
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
|
||||||
|
#include "../server/exe_headers.h"
|
||||||
|
|
||||||
|
#include "rm_headers.h"
|
||||||
|
|
||||||
|
#include "rm_instance_random.h"
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMRandomInstance::CRMRandomInstance
|
||||||
|
* constructs a random instance by choosing one of the sub instances and creating it
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* instGroup: parser group containing infromation about this instance
|
||||||
|
* instFile: reference to an open instance file for creating sub instances
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
CRMRandomInstance::CRMRandomInstance ( CGPGroup *instGroup, CRMInstanceFile& instFile )
|
||||||
|
: CRMInstance ( instGroup, instFile )
|
||||||
|
{
|
||||||
|
CGPGroup* group;
|
||||||
|
CGPGroup* groups[MAX_RANDOM_INSTANCES];
|
||||||
|
int numGroups;
|
||||||
|
|
||||||
|
// Build a list of the groups one can be chosen
|
||||||
|
for ( numGroups = 0, group = instGroup->GetSubGroups ( );
|
||||||
|
group;
|
||||||
|
group = group->GetNext ( ) )
|
||||||
|
{
|
||||||
|
// If this isnt an instance group then skip it
|
||||||
|
if ( stricmp ( group->GetName ( ), "instance" ) )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int multiplier = atoi(group->FindPairValue ( "multiplier", "1" ));
|
||||||
|
for ( ; multiplier > 0 && numGroups < MAX_RANDOM_INSTANCES; multiplier -- )
|
||||||
|
{
|
||||||
|
groups[numGroups++] = group;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No groups, no instance
|
||||||
|
if ( !numGroups )
|
||||||
|
{
|
||||||
|
// Initialize this now
|
||||||
|
mInstance = NULL;
|
||||||
|
|
||||||
|
Com_Printf ( "WARNING: No sub instances specified for random instance '%s'\n", group->FindPairValue ( "name", "unknown" ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now choose a group to parse
|
||||||
|
instGroup = groups[TheRandomMissionManager->GetLandScape()->irand(0,numGroups-1)];
|
||||||
|
|
||||||
|
// Create the child instance now. If the instance create fails then the
|
||||||
|
// IsValid routine will return false and this instance wont be added
|
||||||
|
mInstance = instFile.CreateInstance ( instGroup->FindPairValue ( "name", "" ) );
|
||||||
|
mInstance->SetFilter(mFilter);
|
||||||
|
mInstance->SetTeamFilter(mTeamFilter);
|
||||||
|
|
||||||
|
mAutomapSymbol = mInstance->GetAutomapSymbol();
|
||||||
|
|
||||||
|
SetMessage(mInstance->GetMessage());
|
||||||
|
SetDescription(mInstance->GetDescription());
|
||||||
|
SetInfo(mInstance->GetInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMRandomInstance::~CRMRandomInstance
|
||||||
|
* Deletes the sub instance
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
CRMRandomInstance::~CRMRandomInstance(void)
|
||||||
|
{
|
||||||
|
if ( mInstance )
|
||||||
|
{
|
||||||
|
delete mInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CRMRandomInstance::SetMirror(int mirror)
|
||||||
|
{
|
||||||
|
CRMInstance::SetMirror(mirror);
|
||||||
|
if (mInstance)
|
||||||
|
{
|
||||||
|
mInstance->SetMirror(mirror);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CRMRandomInstance::SetFilter( const char *filter )
|
||||||
|
{
|
||||||
|
CRMInstance::SetFilter(filter);
|
||||||
|
if (mInstance)
|
||||||
|
{
|
||||||
|
mInstance->SetFilter(filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CRMRandomInstance::SetTeamFilter( const char *teamFilter )
|
||||||
|
{
|
||||||
|
CRMInstance::SetTeamFilter(teamFilter);
|
||||||
|
if (mInstance)
|
||||||
|
{
|
||||||
|
mInstance->SetTeamFilter(teamFilter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMRandomInstance::PreSpawn
|
||||||
|
* Prepares for the spawn of the random instance
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* landscape: landscape object this instance will be spawned on
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* true: preparation successful
|
||||||
|
* false: preparation failed
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
bool CRMRandomInstance::PreSpawn ( CRandomTerrain* terrain, qboolean IsServer )
|
||||||
|
{
|
||||||
|
assert ( mInstance );
|
||||||
|
|
||||||
|
mInstance->SetFlattenHeight ( GetFlattenHeight( ) );
|
||||||
|
|
||||||
|
return mInstance->PreSpawn ( terrain, IsServer );
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMRandomInstance::Spawn
|
||||||
|
* Spawns the instance onto the landscape
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* landscape: landscape object this instance will be spawned on
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* true: spawn successful
|
||||||
|
* false: spawn failed
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
bool CRMRandomInstance::Spawn ( CRandomTerrain* terrain, qboolean IsServer )
|
||||||
|
{
|
||||||
|
mInstance->SetObjective(GetObjective());
|
||||||
|
mInstance->SetSide(GetSide());
|
||||||
|
|
||||||
|
if ( !mInstance->Spawn ( terrain, IsServer ) )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMRandomInstance::SetArea
|
||||||
|
* Forwards the given area off to the internal instance
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* area: area to be set
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMRandomInstance::SetArea ( CRMAreaManager* amanager, CRMArea* area )
|
||||||
|
{
|
||||||
|
CRMInstance::SetArea ( amanager, area );
|
||||||
|
|
||||||
|
mInstance->SetArea ( amanager, mArea );
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
#pragma once
|
||||||
|
#if !defined(RM_INSTANCE_RANDOM_H_INC)
|
||||||
|
#define RM_INSTANCE_RANDOM_H_INC
|
||||||
|
|
||||||
|
#ifdef DEBUG_LINKING
|
||||||
|
#pragma message("...including RM_Instance_Random.h")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MAX_RANDOM_INSTANCES 64
|
||||||
|
|
||||||
|
class CRMRandomInstance : public CRMInstance
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
CRMInstance* mInstance;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CRMRandomInstance ( CGPGroup* instGroup, CRMInstanceFile& instFile );
|
||||||
|
~CRMRandomInstance ( );
|
||||||
|
|
||||||
|
virtual bool IsValid ( ) { return mInstance==NULL?false:true; }
|
||||||
|
|
||||||
|
virtual int GetPreviewColor ( ) { return mInstance->GetPreviewColor ( ); }
|
||||||
|
|
||||||
|
virtual float GetSpacingRadius ( ) { return mInstance->GetSpacingRadius ( ); }
|
||||||
|
virtual int GetSpacingLine ( ) { return mInstance->GetSpacingLine ( ); }
|
||||||
|
virtual float GetFlattenRadius ( ) { return mInstance->GetFlattenRadius ( ); }
|
||||||
|
virtual bool GetLockOrigin ( ) { return mInstance->GetLockOrigin ( ); }
|
||||||
|
|
||||||
|
virtual void SetFilter ( const char *filter );
|
||||||
|
virtual void SetTeamFilter ( const char *teamFilter );
|
||||||
|
virtual void SetArea ( CRMAreaManager* amanager, CRMArea* area );
|
||||||
|
virtual void SetMirror (int mirror);
|
||||||
|
|
||||||
|
virtual bool PreSpawn ( CRandomTerrain* terrain, qboolean IsServer );
|
||||||
|
virtual bool Spawn ( CRandomTerrain* terrain, qboolean IsServer );
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,53 @@
|
||||||
|
/************************************************************************************************
|
||||||
|
*
|
||||||
|
* RM_Instance_Void.cpp
|
||||||
|
*
|
||||||
|
* Implements the CRMVoidInstance class. This class just adds a void into the
|
||||||
|
* area manager to help space things out.
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
|
||||||
|
#include "../server/exe_headers.h"
|
||||||
|
|
||||||
|
#include "rm_headers.h"
|
||||||
|
|
||||||
|
#include "rm_instance_void.h"
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMVoidInstance::CRMVoidInstance
|
||||||
|
* constructs a void instance
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* instGroup: parser group containing infromation about this instance
|
||||||
|
* instFile: reference to an open instance file for creating sub instances
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
CRMVoidInstance::CRMVoidInstance ( CGPGroup *instGroup, CRMInstanceFile& instFile )
|
||||||
|
: CRMInstance ( instGroup, instFile )
|
||||||
|
{
|
||||||
|
mSpacingRadius = atof( instGroup->FindPairValue ( "spacing", "0" ) );
|
||||||
|
mFlattenRadius = atof( instGroup->FindPairValue ( "flatten", "0" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMVoidInstance::SetArea
|
||||||
|
* Overidden to make sure the void area doesnt continually.
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* area: area to set
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMVoidInstance::SetArea ( CRMAreaManager* amanager, CRMArea* area )
|
||||||
|
{
|
||||||
|
// Disable collision
|
||||||
|
area->EnableCollision ( false );
|
||||||
|
|
||||||
|
// Do what really needs to get done
|
||||||
|
CRMInstance::SetArea ( amanager, area );
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
#if !defined(RM_INSTANCE_VOID_H_INC)
|
||||||
|
#define RM_INSTANCE_VOID_H_INC
|
||||||
|
|
||||||
|
#ifdef DEBUG_LINKING
|
||||||
|
#pragma message("...including RM_Instance_Void.h")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CRMVoidInstance : public CRMInstance
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
CRMVoidInstance ( CGPGroup* instGroup, CRMInstanceFile& instFile );
|
||||||
|
|
||||||
|
virtual void SetArea ( CRMAreaManager* amanager, CRMArea* area );
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,402 @@
|
||||||
|
/************************************************************************************************
|
||||||
|
*
|
||||||
|
* RM_Manager.cpp
|
||||||
|
*
|
||||||
|
* Implements the CRMManager class. The CRMManager class manages the arioche system.
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
|
||||||
|
#include "../server/exe_headers.h"
|
||||||
|
|
||||||
|
#include "rm_headers.h"
|
||||||
|
#include "../server/server.h"
|
||||||
|
|
||||||
|
CRMObjective *CRMManager::mCurObjective=0;
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* TheRandomMissionManager
|
||||||
|
* Pointer to only active CRMManager class
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
CRMManager *TheRandomMissionManager;
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMManager::CRMManager
|
||||||
|
* constructor
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
CRMManager::CRMManager(void)
|
||||||
|
{
|
||||||
|
mLandScape = NULL;
|
||||||
|
mTerrain = NULL;
|
||||||
|
mMission = NULL;
|
||||||
|
mCurPriority = 1;
|
||||||
|
mUseTimeLimit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMManager::~CRMManager
|
||||||
|
* destructor
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
CRMManager::~CRMManager(void)
|
||||||
|
{
|
||||||
|
#ifndef FINAL_BUILD
|
||||||
|
Com_Printf ("... Shutting down TheRandomMissionManager\n");
|
||||||
|
#endif
|
||||||
|
#ifndef DEDICATED
|
||||||
|
CM_TM_Free();
|
||||||
|
#endif
|
||||||
|
if (mMission)
|
||||||
|
{
|
||||||
|
delete mMission;
|
||||||
|
mMission = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMManager::SetLandscape
|
||||||
|
* Sets the landscape and terrain object used to load a mission
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* landscape - landscape object
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMManager::SetLandScape(CCMLandScape *landscape)
|
||||||
|
{
|
||||||
|
mLandScape = landscape;
|
||||||
|
mTerrain = landscape->GetRandomTerrain();
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMManager::LoadMission
|
||||||
|
* Loads the mission using the mission name stored in the ar_mission cvar
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
bool CRMManager::LoadMission ( qboolean IsServer )
|
||||||
|
{
|
||||||
|
#ifndef PRE_RELEASE_DEMO
|
||||||
|
char instances[MAX_QPATH];
|
||||||
|
char mission[MAX_QPATH];
|
||||||
|
char course[MAX_QPATH];
|
||||||
|
char map[MAX_QPATH];
|
||||||
|
char temp[MAX_QPATH];
|
||||||
|
|
||||||
|
#ifndef FINAL_BUILD
|
||||||
|
Com_Printf ("--------- Random Mission Manager ---------\n\n");
|
||||||
|
Com_Printf ("RMG version : 0.01\n\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!mTerrain)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab the arioche variables
|
||||||
|
Cvar_VariableStringBuffer("rmg_usetimelimit", temp, MAX_QPATH);
|
||||||
|
if (strcmpi(temp, "yes") == 0)
|
||||||
|
{
|
||||||
|
mUseTimeLimit = true;
|
||||||
|
}
|
||||||
|
Cvar_VariableStringBuffer("rmg_instances", instances, MAX_QPATH);
|
||||||
|
Cvar_VariableStringBuffer("RMG_mission", temp, MAX_QPATH);
|
||||||
|
Cvar_VariableStringBuffer("rmg_map", map, MAX_QPATH);
|
||||||
|
sprintf(mission, "%s_%s", temp, map);
|
||||||
|
Cvar_VariableStringBuffer("rmg_course", course, MAX_QPATH);
|
||||||
|
|
||||||
|
// dump existing mission, if any
|
||||||
|
if (mMission)
|
||||||
|
{
|
||||||
|
delete mMission;
|
||||||
|
mMission = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new mission file
|
||||||
|
mMission = new CRMMission ( mTerrain );
|
||||||
|
|
||||||
|
// Load the mission using the arioche variables
|
||||||
|
if ( !mMission->Load ( mission, instances, course ) )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mUseTimeLimit)
|
||||||
|
{
|
||||||
|
Cvar_Set("rmg_timelimit", va("%d", mMission->GetTimeLimit()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Cvar_Set("rmg_timelimit", "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsServer)
|
||||||
|
{ // set the names of the teams
|
||||||
|
CGenericParser2 parser;
|
||||||
|
//CGPGroup* root;
|
||||||
|
|
||||||
|
Cvar_VariableStringBuffer("RMG_terrain", temp, MAX_QPATH);
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Create the parser for the mission file
|
||||||
|
if(Com_ParseTextFile(va("ext_data/rmg/%s.teams", temp), parser))
|
||||||
|
{
|
||||||
|
root = parser.GetBaseParseGroup()->GetSubGroups();
|
||||||
|
if (0 == stricmp(root->GetName(), "teams"))
|
||||||
|
{
|
||||||
|
SV_SetConfigstring( CS_GAMETYPE_REDTEAM, root->FindPairValue ( "red", "marine" ));
|
||||||
|
SV_SetConfigstring( CS_GAMETYPE_BLUETEAM, root->FindPairValue ( "blue", "thug" ));
|
||||||
|
}
|
||||||
|
parser.Clean();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
//rww - This is single player, no such thing.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must have a valid landscape before we can spawn the mission
|
||||||
|
assert ( mLandScape );
|
||||||
|
|
||||||
|
#ifndef FINAL_BUILD
|
||||||
|
Com_Printf ("------------------------------------------\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif // PRE_RELEASE_DEMO
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMManager::IsMissionComplete
|
||||||
|
* Determines whether or not all the arioche objectives have been met
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* true: all objectives have been completed
|
||||||
|
* false: one or more of the objectives has not been met
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
bool CRMManager::IsMissionComplete(void)
|
||||||
|
{
|
||||||
|
if ( NULL == mMission->GetCurrentObjective ( ) )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMManager::HasTimeExpired
|
||||||
|
* Determines whether or not the time limit (if one) has expired
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* true: time limit has expired
|
||||||
|
* false: time limit has not expired
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
bool CRMManager::HasTimeExpired(void)
|
||||||
|
{
|
||||||
|
/* if (mMission->GetTimeLimit() == 0 || !mUseTimeLimit)
|
||||||
|
{ // no time limit set
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mMission->GetTimeLimit() * 1000 * 60 > level.time - level.startTime)
|
||||||
|
{ // we are still under our time limit
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// over our time limit!
|
||||||
|
return true;*/
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMManager::UpdateStatisticCvars
|
||||||
|
* Updates the statistic cvars with data from the game
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMManager::UpdateStatisticCvars ( void )
|
||||||
|
{
|
||||||
|
/* // No player set then nothing more to do
|
||||||
|
if ( mPlayer )
|
||||||
|
{
|
||||||
|
float accuracy;
|
||||||
|
|
||||||
|
// Calculate the accuracy
|
||||||
|
accuracy = (float)mPlayer->client->ps.persistant[PERS_SHOTS_HIT];
|
||||||
|
accuracy /= (float)mPlayer->client->ps.persistant[PERS_SHOTS];
|
||||||
|
accuracy *= 100.0f;
|
||||||
|
|
||||||
|
// set the accuracy cvar
|
||||||
|
gi.Cvar_Set ( "ar_pl_accuracy", va("%d%%",(int)accuracy) );
|
||||||
|
|
||||||
|
// Set the # of kills cvar
|
||||||
|
gi.Cvar_Set ( "ar_kills", va("%d", mPlayer->client->ps.persistant[PERS_SCORE] ) );
|
||||||
|
|
||||||
|
int hours;
|
||||||
|
int mins;
|
||||||
|
int seconds;
|
||||||
|
int tens;
|
||||||
|
int millisec = (level.time - level.startTime);
|
||||||
|
|
||||||
|
seconds = millisec / 1000;
|
||||||
|
hours = seconds / (60 * 60);
|
||||||
|
seconds -= (hours * 60 * 60);
|
||||||
|
mins = seconds / 60;
|
||||||
|
seconds -= mins * 60;
|
||||||
|
tens = seconds / 10;
|
||||||
|
seconds -= tens * 10;
|
||||||
|
|
||||||
|
gi.Cvar_Set ( "ar_duration", va("%dhr %dmin %dsec", hours, mins, seconds ) );
|
||||||
|
|
||||||
|
WpnID wpnID = TheWpnSysMgr().GetFavoriteWeapon ( );
|
||||||
|
gi.Cvar_Set ( "ar_fav_wp", CWeaponSystem::GetWpnName ( wpnID ) );
|
||||||
|
|
||||||
|
// show difficulty
|
||||||
|
char difficulty[MAX_QPATH];
|
||||||
|
gi.Cvar_VariableStringBuffer("g_skill", difficulty, MAX_QPATH);
|
||||||
|
strupr(difficulty);
|
||||||
|
gi.Cvar_Set ( "ar_diff", va("&GENERIC_%s&",difficulty) );
|
||||||
|
|
||||||
|
// compute rank
|
||||||
|
float compositeRank = 1;
|
||||||
|
int rankMax = 3; // max rank less 1
|
||||||
|
float timeRank = mUseTimeLimit ? (1.0f - (mins / (float)mMission->GetTimeLimit())) : 0;
|
||||||
|
float killRank = mPlayer->client->ps.persistant[PERS_SCORE] / (float)GetCharacterManager().GetAllSize();
|
||||||
|
killRank = (killRank > 0) ? killRank : 1.0f;
|
||||||
|
float accuRank = (accuracy > 0) ? accuracy*0.01f : 1.0f;
|
||||||
|
float weapRank = 1.0f - CWeaponSystem::GetRank(wpnID);
|
||||||
|
|
||||||
|
compositeRank = ((timeRank + killRank + accuRank + weapRank) / 3.0f) * rankMax + 1;
|
||||||
|
|
||||||
|
if (compositeRank > 4)
|
||||||
|
compositeRank = 4;
|
||||||
|
|
||||||
|
gi.Cvar_Set ( "ar_rank", va("&RMG_RANK%d&",((int)compositeRank)) );
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMManager::CompleteMission
|
||||||
|
* Does end-of-mission stuff (pause game, end screen, return to menu)
|
||||||
|
* <Description> *
|
||||||
|
* Input *
|
||||||
|
* <Variable>: <Description> *
|
||||||
|
* Output / Return *
|
||||||
|
* <Variable>: <Description> *
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMManager::CompleteMission(void)
|
||||||
|
{
|
||||||
|
UpdateStatisticCvars ( );
|
||||||
|
|
||||||
|
mMission->CompleteMission();
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMManager::FailedMission
|
||||||
|
* Does end-of-mission stuff (pause game, end screen, return to menu)
|
||||||
|
* <Description> *
|
||||||
|
* Input *
|
||||||
|
* TimeExpired: indicates if the reason failed was because of time
|
||||||
|
* Output / Return *
|
||||||
|
* <Variable>: <Description> *
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMManager::FailedMission(bool TimeExpired)
|
||||||
|
{
|
||||||
|
UpdateStatisticCvars ( );
|
||||||
|
|
||||||
|
mMission->FailedMission(TimeExpired);
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMManager::CompleteObjective
|
||||||
|
* Marks the given objective as completed
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* obj: objective to set as completed
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMManager::CompleteObjective ( CRMObjective *obj )
|
||||||
|
{
|
||||||
|
assert ( obj );
|
||||||
|
|
||||||
|
mMission->CompleteObjective ( obj );
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMManager::Preview
|
||||||
|
* previews the random mission genration information
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* from: origin being previed from
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMManager::Preview ( const vec3_t from )
|
||||||
|
{
|
||||||
|
// Dont bother if we havent reached our timer yet
|
||||||
|
/* if ( level.time < mPreviewTimer )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let the mission do all the previewing
|
||||||
|
mMission->Preview ( from );
|
||||||
|
|
||||||
|
// Another second
|
||||||
|
mPreviewTimer = level.time + 1000;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMManager::Preview
|
||||||
|
* previews the random mission genration information
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* from: origin being previed from
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
bool CRMManager::SpawnMission ( qboolean IsServer )
|
||||||
|
{
|
||||||
|
// Spawn the mission
|
||||||
|
mMission->Spawn ( mTerrain, IsServer );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
#pragma once
|
||||||
|
#if !defined(RM_MANAGER_H_INC)
|
||||||
|
#define RM_MANAGER_H_INC
|
||||||
|
|
||||||
|
#if !defined(CM_LANDSCAPE_H_INC)
|
||||||
|
#include "../qcommon/cm_landscape.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CRMManager
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
CRMMission* mMission;
|
||||||
|
CCMLandScape* mLandScape;
|
||||||
|
CRandomTerrain* mTerrain;
|
||||||
|
int mPreviewTimer;
|
||||||
|
int mCurPriority;
|
||||||
|
bool mUseTimeLimit;
|
||||||
|
|
||||||
|
void UpdateStatisticCvars ( void );
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
CRMManager (void);
|
||||||
|
~CRMManager (void);
|
||||||
|
|
||||||
|
bool LoadMission ( qboolean IsServer );
|
||||||
|
bool SpawnMission ( qboolean IsServer );
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
void SetLandScape (CCMLandScape *landscape);
|
||||||
|
void SetCurPriority (int priority) { mCurPriority = priority; }
|
||||||
|
|
||||||
|
CRandomTerrain* GetTerrain (void) { return mTerrain; }
|
||||||
|
CCMLandScape* GetLandScape (void) { return mLandScape; }
|
||||||
|
CRMMission* GetMission (void) { return mMission; }
|
||||||
|
int GetCurPriority (void) { return mCurPriority; }
|
||||||
|
|
||||||
|
void Preview ( const vec3_t from );
|
||||||
|
|
||||||
|
bool IsMissionComplete (void);
|
||||||
|
bool HasTimeExpired (void);
|
||||||
|
void CompleteObjective ( CRMObjective *obj );
|
||||||
|
void CompleteMission (void);
|
||||||
|
void FailedMission (bool TimeExpired);
|
||||||
|
|
||||||
|
// eek
|
||||||
|
static CRMObjective *mCurObjective;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern CRMManager* TheRandomMissionManager;
|
||||||
|
|
||||||
|
|
||||||
|
#endif // RANDOMMISSION_H_INC
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,129 @@
|
||||||
|
#pragma once
|
||||||
|
#if !defined(RM_MISSION_H_INC)
|
||||||
|
#define RM_MISSION_H_INC
|
||||||
|
|
||||||
|
#ifdef DEBUG_LINKING
|
||||||
|
#pragma message("...including RM_Mission.h")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// maximum random choices
|
||||||
|
#define MAX_RANDOM_CHOICES 100
|
||||||
|
|
||||||
|
typedef vector<int> rmIntVector_t;
|
||||||
|
|
||||||
|
|
||||||
|
class CRMMission
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
rmObjectiveList_t mObjectives;
|
||||||
|
rmInstanceList_t mInstances;
|
||||||
|
|
||||||
|
CRMInstanceFile mInstanceFile;
|
||||||
|
CRMObjective* mCurrentObjective;
|
||||||
|
|
||||||
|
bool mValidNodes;
|
||||||
|
bool mValidPaths;
|
||||||
|
bool mValidRivers;
|
||||||
|
bool mValidWeapons;
|
||||||
|
bool mValidAmmo;
|
||||||
|
bool mValidObjectives;
|
||||||
|
bool mValidInstances;
|
||||||
|
|
||||||
|
int mTimeLimit;
|
||||||
|
int mMaxInstancePosition;
|
||||||
|
|
||||||
|
// npc multipliers
|
||||||
|
float mAccuracyMultiplier;
|
||||||
|
float mHealthMultiplier;
|
||||||
|
|
||||||
|
// % chance that RMG pickup is actually spawned
|
||||||
|
float mPickupHealth;
|
||||||
|
float mPickupArmor;
|
||||||
|
float mPickupAmmo;
|
||||||
|
float mPickupWeapon;
|
||||||
|
float mPickupEquipment;
|
||||||
|
|
||||||
|
string mDescription;
|
||||||
|
string mExitScreen;
|
||||||
|
string mTimeExpiredScreen;
|
||||||
|
|
||||||
|
// symmetric landscape style
|
||||||
|
symmetry_t mSymmetric;
|
||||||
|
|
||||||
|
// if set to 1 in the mission file, adds an extra connecting path in symmetric maps
|
||||||
|
// to ensure both sides actually do connect
|
||||||
|
int mBackUpPath;
|
||||||
|
|
||||||
|
int mDefaultPadding;
|
||||||
|
|
||||||
|
CRMAreaManager* mAreaManager;
|
||||||
|
|
||||||
|
CRMPathManager* mPathManager;
|
||||||
|
|
||||||
|
CRandomTerrain* mLandScape;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CRMMission ( CRandomTerrain* );
|
||||||
|
~CRMMission ( );
|
||||||
|
|
||||||
|
bool Load ( const char* name, const char* instances, const char* difficulty );
|
||||||
|
bool Spawn ( CRandomTerrain* terrain, qboolean IsServer );
|
||||||
|
|
||||||
|
void Preview ( const vec3_t from );
|
||||||
|
|
||||||
|
CRMObjective* FindObjective ( const char* name );
|
||||||
|
CRMObjective* GetCurrentObjective ( ) { return mCurrentObjective; }
|
||||||
|
|
||||||
|
void CompleteMission (void);
|
||||||
|
void FailedMission (bool TimeExpired);
|
||||||
|
void CompleteObjective ( CRMObjective* ojective );
|
||||||
|
|
||||||
|
int GetTimeLimit (void) { return mTimeLimit; }
|
||||||
|
int GetMaxInstancePosition (void) { return mMaxInstancePosition; }
|
||||||
|
const char* GetDescription (void) { return mDescription.c_str(); }
|
||||||
|
const char* GetExitScreen (void) { return mExitScreen.c_str(); }
|
||||||
|
int GetSymmetric (void) { return mSymmetric; }
|
||||||
|
int GetBackUpPath (void) { return mBackUpPath; }
|
||||||
|
int GetDefaultPadding (void) { return mDefaultPadding; }
|
||||||
|
|
||||||
|
// void CreateMap ( void );
|
||||||
|
|
||||||
|
bool DenyPickupHealth () {return mLandScape->flrand(0.0f,1.0f) > mPickupHealth;}
|
||||||
|
bool DenyPickupArmor () {return mLandScape->flrand(0.0f,1.0f) > mPickupArmor;}
|
||||||
|
bool DenyPickupAmmo () {return mLandScape->flrand(0.0f,1.0f) > mPickupAmmo;}
|
||||||
|
bool DenyPickupWeapon () {return mLandScape->flrand(0.0f,1.0f) > mPickupWeapon;}
|
||||||
|
bool DenyPickupEquipment () {return mLandScape->flrand(0.0f,1.0f) > mPickupEquipment;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// void PurgeUnlinkedTriggers ( );
|
||||||
|
// void PurgeTrigger ( CEntity* trigger );
|
||||||
|
|
||||||
|
void MirrorPos (vec3_t pos);
|
||||||
|
CGPGroup* ParseRandom ( CGPGroup* random );
|
||||||
|
bool ParseOrigin ( CGPGroup* originGroup, vec3_t origin, vec3_t lookat, int* flattenHeight );
|
||||||
|
bool ParseNodes ( CGPGroup* group );
|
||||||
|
bool ParsePaths ( CGPGroup *paths);
|
||||||
|
bool ParseRivers ( CGPGroup *rivers);
|
||||||
|
void PlaceBridges ();
|
||||||
|
void PlaceWallInstance(CRMInstance* instance, float xpos, float ypos, float zpos, int x, int y, float angle);
|
||||||
|
|
||||||
|
|
||||||
|
bool ParseDifficulty ( CGPGroup* difficulty, CGPGroup *parent );
|
||||||
|
bool ParseWeapons ( CGPGroup* weapons );
|
||||||
|
bool ParseAmmo ( CGPGroup* ammo );
|
||||||
|
bool ParseOutfit ( CGPGroup* outfit );
|
||||||
|
bool ParseObjectives ( CGPGroup* objectives );
|
||||||
|
bool ParseInstance ( CGPGroup* instance );
|
||||||
|
bool ParseInstances ( CGPGroup* instances );
|
||||||
|
bool ParseInstancesOnPath ( CGPGroup* group );
|
||||||
|
bool ParseWallRect ( CGPGroup* group, int side);
|
||||||
|
|
||||||
|
// void SpawnNPCTriggers ( CCMLandScape* landscape );
|
||||||
|
// void AttachNPCTriggers ( CCMLandScape* landscape );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,134 @@
|
||||||
|
/************************************************************************************************
|
||||||
|
*
|
||||||
|
* RM_Objective.cpp
|
||||||
|
*
|
||||||
|
* Implements the CRMObjective class. This class is reponsible for parsing an objective
|
||||||
|
* from the mission file as well as linking the objective into the world.
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
|
||||||
|
#include "../server/exe_headers.h"
|
||||||
|
|
||||||
|
#include "rm_headers.h"
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMObjective::CRMObjective
|
||||||
|
* Constructs a random mission objective and fills in the default properties
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
CRMObjective::CRMObjective ( CGPGroup* group )
|
||||||
|
{
|
||||||
|
SetPriority(atoi(group->FindPairValue("priority", "0")));
|
||||||
|
SetMessage( group->FindPairValue("message",va("Objective %i Completed", GetPriority()) ) );
|
||||||
|
SetDescription(group->FindPairValue("description",va("Objective %i", GetPriority()) ) );
|
||||||
|
SetInfo(group->FindPairValue("info",va("Info %i", GetPriority()) ) );
|
||||||
|
SetTrigger(group->FindPairValue("trigger",""));
|
||||||
|
SetName(group->GetName());
|
||||||
|
|
||||||
|
/* const char * soundPath = group->FindPairValue("completed_sound", "" );
|
||||||
|
if (soundPath)
|
||||||
|
mCompleteSoundID = G_SoundIndex(soundPath);
|
||||||
|
*/
|
||||||
|
|
||||||
|
mCompleted = false;
|
||||||
|
mOrderIndex = -1;
|
||||||
|
|
||||||
|
// If no priority was specified for this objective then its active by default.
|
||||||
|
if ( GetPriority ( ) )
|
||||||
|
{
|
||||||
|
mActive = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mActive = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMObjective::FindRandomTrigger
|
||||||
|
* Searches the entitySystem form a random arioche trigger that matches the objective name
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* trigger: a random trigger or NULL if one couldnt be found
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
/*CTriggerAriocheObjective* CRMObjective::FindRandomTrigger ( )
|
||||||
|
{
|
||||||
|
CEntity* search;
|
||||||
|
CEntity* triggers[20];
|
||||||
|
int numTriggers;
|
||||||
|
|
||||||
|
// Start off the first trigger
|
||||||
|
numTriggers = 0;
|
||||||
|
search = entitySystem->GetEntityFromClassname ( NULL, "trigger_arioche_objective" );
|
||||||
|
|
||||||
|
// Make a list of triggers
|
||||||
|
while ( numTriggers < 20 && search )
|
||||||
|
{
|
||||||
|
CTriggerAriocheObjective* trigger = (CTriggerAriocheObjective*) search;
|
||||||
|
|
||||||
|
// Move on to the next trigger
|
||||||
|
search = entitySystem->GetEntityFromClassname ( search, "trigger_arioche_objective" );
|
||||||
|
|
||||||
|
// See if this trigger is already in use
|
||||||
|
if ( trigger->GetObjective ( ) )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the objective names dont match then ignore this trigger
|
||||||
|
if ( stricmp ( trigger->GetObjectiveName ( ), GetTrigger() ) )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the trigger to the list
|
||||||
|
triggers[numTriggers++] = trigger;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no matching triggers then just return NULL
|
||||||
|
if ( 0 == numTriggers )
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a random choice from the trigger list
|
||||||
|
return (CTriggerAriocheObjective*)triggers[TheRandomMissionManager->GetLandScape()->irand(0,numTriggers-1)];
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMObjective::Link
|
||||||
|
* Links the objective into the world using the current state of the world to determine
|
||||||
|
* where it should link
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* true: objective successfully linked
|
||||||
|
* false: objective failed to link
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
bool CRMObjective::Link ( )
|
||||||
|
{
|
||||||
|
/* CTriggerAriocheObjective* trigger;
|
||||||
|
|
||||||
|
// Look for a random trigger to associate this objective to.
|
||||||
|
trigger = FindRandomTrigger ( );
|
||||||
|
if ( NULL != trigger )
|
||||||
|
{
|
||||||
|
trigger->SetObjective ( this );
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
#pragma once
|
||||||
|
#if !defined(RM_OBJECTIVE_H_INC)
|
||||||
|
#define RM_OBJECTIVE_H_INC
|
||||||
|
|
||||||
|
#ifdef DEBUG_LINKING
|
||||||
|
#pragma message("...including RM_Objective.h")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CRMObjective
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
bool mCompleted; // Is objective completed?
|
||||||
|
bool mActive; // set to false if the objective requires another objective to be met first
|
||||||
|
int mPriority; // sequence in which objectives need to be completed
|
||||||
|
int mOrderIndex; // objective index in ui
|
||||||
|
int mCompleteSoundID; // sound for when objective is finished
|
||||||
|
string mMessage; // message outputed when objective is completed
|
||||||
|
string mDescription; // description of objective
|
||||||
|
string mInfo; // more info for objective
|
||||||
|
string mName; // name of objective
|
||||||
|
string mTrigger; // trigger associated with objective
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CRMObjective(CGPGroup *group);
|
||||||
|
~CRMObjective(void) {}
|
||||||
|
|
||||||
|
bool Link (void);
|
||||||
|
|
||||||
|
bool IsCompleted (void) const { return mCompleted; }
|
||||||
|
bool IsActive (void) const { return mActive; }
|
||||||
|
|
||||||
|
void Activate (void) { mActive = true; }
|
||||||
|
void Complete (bool comp) { mCompleted = comp;}
|
||||||
|
|
||||||
|
// Get methods
|
||||||
|
int GetPriority(void){return mPriority;}
|
||||||
|
int GetOrderIndex(void) { return mOrderIndex; }
|
||||||
|
const char* GetMessage(void) { return mMessage.c_str(); }
|
||||||
|
const char* GetDescription(void) { return mDescription.c_str(); }
|
||||||
|
const char* GetInfo(void) { return mInfo.c_str(); }
|
||||||
|
const char* GetName(void) { return mName.c_str(); }
|
||||||
|
const char* GetTrigger(void) { return mTrigger.c_str(); }
|
||||||
|
int CompleteSoundID() { return mCompleteSoundID; };
|
||||||
|
|
||||||
|
// Set methods
|
||||||
|
void SetPriority(int priority){mPriority = priority;}
|
||||||
|
void SetOrderIndex(int order) { mOrderIndex = order; }
|
||||||
|
void SetMessage(const char* msg) { mMessage = msg; }
|
||||||
|
void SetDescription(const char* desc) { mDescription = desc; }
|
||||||
|
void SetInfo(const char* info) { mInfo = info; }
|
||||||
|
void SetName(const char* name) { mName = name; }
|
||||||
|
void SetTrigger(const char* name) { mTrigger = name; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// CTriggerAriocheObjective* FindRandomTrigger ( );
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef list<CRMObjective *>::iterator rmObjectiveIter_t;
|
||||||
|
typedef list<CRMObjective *> rmObjectiveList_t;
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,721 @@
|
||||||
|
/************************************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (C) 2001-2002 Raven Software
|
||||||
|
*
|
||||||
|
* RM_Path.cpp
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
#include "../server/exe_headers.h"
|
||||||
|
|
||||||
|
#include "rm_headers.h"
|
||||||
|
|
||||||
|
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMNode::CRMNode
|
||||||
|
* constructor
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
CRMNode::CRMNode ( )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
mFlattenHeight = -1;
|
||||||
|
|
||||||
|
mPos[0] = 0;
|
||||||
|
mPos[1] = 0;
|
||||||
|
mPos[2] = 0;
|
||||||
|
|
||||||
|
// no paths
|
||||||
|
for (i = 0; i < DIR_MAX; i++)
|
||||||
|
mPathID[i] = -1;
|
||||||
|
|
||||||
|
mAreaPointPlaced = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMPathManager::CRMPathManager
|
||||||
|
* constructor
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
CRMPathManager::CRMPathManager ( CRandomTerrain* terrain )
|
||||||
|
: mXNodes(0), mYNodes(0), mPathCount(0), mRiverCount(0), mMaxDepth(0), mDepth(0),
|
||||||
|
mPathPoints(10), mPathMinWidth(0.02f), mPathMaxWidth(0.04f), mPathDepth(0.3f), mPathDeviation(0.03f), mPathBreadth(5),
|
||||||
|
mRiverDepth(5), mRiverPoints(10), mRiverMinWidth(0.01f), mRiverMaxWidth(0.02f), mRiverBedDepth(1), mRiverDeviation(0.01f), mRiverBreadth(7),
|
||||||
|
mTerrain(terrain), mCrossed(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CRMPathManager::~CRMPathManager ( )
|
||||||
|
{
|
||||||
|
int i,j;
|
||||||
|
|
||||||
|
for ( i = mLocations.size() - 1; i >=0; i-- )
|
||||||
|
{
|
||||||
|
if (mLocations[i])
|
||||||
|
delete mLocations[i];
|
||||||
|
}
|
||||||
|
mLocations.clear();
|
||||||
|
|
||||||
|
for ( j = mNodes.size() - 1; j >=0; j-- )
|
||||||
|
{
|
||||||
|
if (mNodes[j])
|
||||||
|
delete mNodes[j];
|
||||||
|
}
|
||||||
|
mNodes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CRMPathManager::CreateLocation ( const char* name, const int min_depth, int max_depth, const int min_paths, int max_paths )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// sanity checks -- dmv
|
||||||
|
if( max_paths < min_paths )
|
||||||
|
{
|
||||||
|
Com_Printf("[CreateLocation()] ERROR : max_paths < min_paths :: set max_paths = min_paths\n" );
|
||||||
|
max_paths = min_paths;
|
||||||
|
}
|
||||||
|
if( max_depth < min_depth )
|
||||||
|
{
|
||||||
|
Com_Printf("[CreateLocation()] ERROR : max_depth < min_depth :: set max_depth = min_depth\n" );
|
||||||
|
max_depth = min_depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = mLocations.size()-1; i>=0; --i)
|
||||||
|
if ( !stricmp ( name, mLocations[i]->GetName ( ) ) )
|
||||||
|
{
|
||||||
|
mLocations[i]->SetMinDepth(min_depth);
|
||||||
|
mLocations[i]->SetMaxDepth(max_depth);
|
||||||
|
mLocations[i]->SetMinPaths(min_paths);
|
||||||
|
mLocations[i]->SetMaxPaths(max_paths);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CRMLoc* pLoc= new CRMLoc(name, min_depth, max_depth, min_paths, max_paths);
|
||||||
|
mLocations.push_back(pLoc);
|
||||||
|
mMaxDepth = max(mMaxDepth, max_depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CRMPathManager::ClearCells(int x_nodes, int y_nodes)
|
||||||
|
{
|
||||||
|
int x,y;
|
||||||
|
|
||||||
|
// clear cell array - used for generating paths
|
||||||
|
CRMCell empty;
|
||||||
|
for (x=0; x < x_nodes * y_nodes; x++)
|
||||||
|
{
|
||||||
|
if (x >= mCells.size())
|
||||||
|
mCells.push_back(empty);
|
||||||
|
else
|
||||||
|
mCells[x] = empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set borders of world
|
||||||
|
for (y = 0; y < y_nodes; y++)
|
||||||
|
{
|
||||||
|
mCells[y * x_nodes].SetBorder(DIR_W );
|
||||||
|
mCells[y * x_nodes].SetBorder(DIR_SW );
|
||||||
|
mCells[y * x_nodes].SetBorder(DIR_NW );
|
||||||
|
mCells[y * x_nodes + x_nodes-1].SetBorder( DIR_E );
|
||||||
|
mCells[y * x_nodes + x_nodes-1].SetBorder( DIR_NE );
|
||||||
|
mCells[y * x_nodes + x_nodes-1].SetBorder( DIR_SE );
|
||||||
|
}
|
||||||
|
|
||||||
|
for (x = 0; x < x_nodes; x++)
|
||||||
|
{
|
||||||
|
mCells[x].SetBorder( DIR_N );
|
||||||
|
mCells[x].SetBorder( DIR_NE );
|
||||||
|
mCells[x].SetBorder( DIR_NW );
|
||||||
|
mCells[(y_nodes-1) * x_nodes + x].SetBorder( DIR_S );
|
||||||
|
mCells[(y_nodes-1) * x_nodes + x].SetBorder( DIR_SE );
|
||||||
|
mCells[(y_nodes-1) * x_nodes + x].SetBorder( DIR_SW );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMPathManager::CreateArray
|
||||||
|
* Create array of nodes that are spaced over the landscape.
|
||||||
|
* Create array of cells, which is used to determine how nodes are connected.
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* x_nodes, y_nodes - how many nodes in each dimension to layout
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* true if the node array was created, false if we have a problem
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
bool CRMPathManager::CreateArray(const int x_nodes, const int y_nodes)
|
||||||
|
{
|
||||||
|
mXNodes = x_nodes;
|
||||||
|
mYNodes = y_nodes;
|
||||||
|
|
||||||
|
// fill node array with positions that are spaced over the landscape
|
||||||
|
int x,y;
|
||||||
|
|
||||||
|
// dump existing nodes
|
||||||
|
for ( x = mNodes.size() - 1; x >=0; x-- )
|
||||||
|
{
|
||||||
|
if (mNodes[x])
|
||||||
|
delete mNodes[x];
|
||||||
|
}
|
||||||
|
mNodes.clear();
|
||||||
|
mNodes.resize(mXNodes * mYNodes, NULL);
|
||||||
|
|
||||||
|
// add a small amount of random jitter to spots chosen
|
||||||
|
float x_rnd = 0.2f / (mXNodes+1);
|
||||||
|
float y_rnd = 0.2f / (mYNodes+1);
|
||||||
|
|
||||||
|
for (x = 0; x < mXNodes; x++)
|
||||||
|
{
|
||||||
|
float cell_x = (x + 1.0f) / (mXNodes+1);
|
||||||
|
// float cell_x = (x + 2.0f) / (mXNodes+3);
|
||||||
|
|
||||||
|
for (y = 0; y < mYNodes; y++)
|
||||||
|
{
|
||||||
|
vec3_t pos;
|
||||||
|
CRMNode * pnode = new CRMNode();
|
||||||
|
mNodes[x + y*mXNodes] = pnode;
|
||||||
|
|
||||||
|
float cell_y = (y + 1.0f) / (mYNodes+1);
|
||||||
|
// float cell_y = (y + 2.0f) / (mYNodes+3);
|
||||||
|
|
||||||
|
pos[0] = TheRandomMissionManager->GetLandScape()->flrand(cell_x - x_rnd, cell_x + x_rnd);
|
||||||
|
pos[1] = TheRandomMissionManager->GetLandScape()->flrand(cell_y - y_rnd, cell_y + y_rnd);
|
||||||
|
pos[2] = 0;
|
||||||
|
|
||||||
|
SetNodePos(x, y, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearCells(mXNodes, mYNodes);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// neighbor offsets - easy way to turn a direction into the array position for a neighboring cell or node
|
||||||
|
int CRMPathManager::neighbor_x[DIR_MAX] = { 0, 1, 1, 1, 0,-1,-1,-1};
|
||||||
|
int CRMPathManager::neighbor_y[DIR_MAX] = {-1,-1, 0, 1, 1, 1, 0,-1};
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMPathManager::PlaceLocation
|
||||||
|
* This method is used to determine if a named location should be placed at this node.
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* c_x, c_y - cell to examine
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMPathManager::PlaceLocation(const int c_x, const int c_y)
|
||||||
|
{
|
||||||
|
if ( !Node(c_x,c_y)->IsLocation() )
|
||||||
|
{ // not currently a location
|
||||||
|
|
||||||
|
// how many paths lead to this cell?
|
||||||
|
int count_paths = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i<DIR_MAX; i++)
|
||||||
|
if (Node(c_x,c_y)->PathExist(i))
|
||||||
|
count_paths++;
|
||||||
|
|
||||||
|
int deepest_depth = -1;
|
||||||
|
int deepest_loc = -1;
|
||||||
|
for (i = mLocations.size()-1; i>=0; --i)
|
||||||
|
{
|
||||||
|
if (!mLocations[i]->Placed() && // node has not been placed
|
||||||
|
mLocations[i]->MinDepth() <= mDepth && // our current depth is in the proper range
|
||||||
|
mLocations[i]->MaxDepth() >= mDepth &&
|
||||||
|
mLocations[i]->MinPaths() <= count_paths && // our path count is in the proper range
|
||||||
|
mLocations[i]->MaxPaths() >= count_paths &&
|
||||||
|
mLocations[i]->MaxDepth() > deepest_depth) // and this is the deepest location of the ones that match
|
||||||
|
{
|
||||||
|
deepest_loc = i;
|
||||||
|
deepest_depth = mLocations[i]->MaxDepth();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deepest_loc >= 0 && deepest_loc < mLocations.size())
|
||||||
|
{ // found a location to place at this node / cell
|
||||||
|
const char * name = mLocations[deepest_loc]->GetName();
|
||||||
|
Node(c_x,c_y)->SetName(name);
|
||||||
|
mLocations[deepest_loc]->SetPlaced(true);
|
||||||
|
|
||||||
|
// need a new max depth
|
||||||
|
int max_depth = -1;
|
||||||
|
for (i = mLocations.size()-1; i>=0; --i)
|
||||||
|
{
|
||||||
|
// figure out new max depth based on the max depth of unplaced locations
|
||||||
|
if (!mLocations[i]->Placed() && // node has not been placed
|
||||||
|
mLocations[i]->MaxDepth() > max_depth) // and this is the deepest
|
||||||
|
{
|
||||||
|
max_depth = mLocations[i]->MaxDepth();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mMaxDepth = max_depth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMPathManager::PathVisit
|
||||||
|
* This method is called recursively to create a network of nodes connected with paths.
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* c_x, c_y - cell to visit
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMPathManager::PathVisit(const int c_x, const int c_y)
|
||||||
|
{
|
||||||
|
// does this cell have any neighbors with all walls intact?
|
||||||
|
int i,off;
|
||||||
|
|
||||||
|
// look at neighbors in random order
|
||||||
|
off = TheRandomMissionManager->GetLandScape()->irand(DIR_FIRST, DIR_MAX-1);
|
||||||
|
|
||||||
|
++mDepth; // track our depth of recursion
|
||||||
|
|
||||||
|
for (i = DIR_FIRST; i<DIR_MAX && mDepth <= mMaxDepth; i++)
|
||||||
|
{
|
||||||
|
int d = (i + off) % DIR_MAX;
|
||||||
|
if ( !Cell(c_x, c_y).Border(d) )
|
||||||
|
{ // we can move this way, since no border
|
||||||
|
int new_c_x = c_x + neighbor_x[d];
|
||||||
|
int new_c_y = c_y + neighbor_y[d];
|
||||||
|
if (Cell(new_c_x,new_c_y).Wall() == DIR_ALL)
|
||||||
|
{ // we have a new cell that has not been visited!
|
||||||
|
int new_dir;
|
||||||
|
// d is the direction relative to the current cell
|
||||||
|
// new_dir is the direction relative to the next cell (N becomes S, NE becomes SW, etc...)
|
||||||
|
if( d < HALF_DIR_MAX )
|
||||||
|
{
|
||||||
|
new_dir = d + HALF_DIR_MAX;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new_dir = d - HALF_DIR_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
// knock down walls
|
||||||
|
Cell(c_x,c_y).RemoveWall(d);
|
||||||
|
Cell(new_c_x,new_c_y).RemoveWall(new_dir); //DIR_MAX - d);
|
||||||
|
|
||||||
|
// set path id
|
||||||
|
Node(c_x, c_y)->SetPath(d, mPathCount);
|
||||||
|
Node(new_c_x, new_c_y)->SetPath(new_dir, mPathCount); //DIR_MAX - d, mPathCount);
|
||||||
|
|
||||||
|
// create path between cells
|
||||||
|
mTerrain->CreatePath( mPathCount++,
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
mPathPoints,
|
||||||
|
GetNodePos(c_x,c_y)[0],
|
||||||
|
GetNodePos(c_x,c_y)[1],
|
||||||
|
GetNodePos(new_c_x,new_c_y)[0],
|
||||||
|
GetNodePos(new_c_x,new_c_y)[1],
|
||||||
|
mPathMinWidth,
|
||||||
|
mPathMaxWidth,
|
||||||
|
mPathDepth,
|
||||||
|
mPathDeviation,
|
||||||
|
mPathBreadth );
|
||||||
|
|
||||||
|
// flatten a small spot
|
||||||
|
CArea area;
|
||||||
|
float flat_radius = mPathMaxWidth *
|
||||||
|
fabs(TheRandomMissionManager->GetLandScape()->GetBounds()[1][0] - TheRandomMissionManager->GetLandScape()->GetBounds()[0][0]);
|
||||||
|
area.Init( GetNodePos(c_x,c_y), flat_radius, 0.0f, AT_NONE, 0, 0 );
|
||||||
|
TheRandomMissionManager->GetLandScape()->FlattenArea(&area, 255 * mPathDepth, false, true, true );
|
||||||
|
|
||||||
|
// recurse
|
||||||
|
PathVisit(new_c_x, new_c_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
--mDepth;
|
||||||
|
|
||||||
|
// NOTE: *whoop* hack alert, the first time this is reached, it should be the very last placed node.
|
||||||
|
if( !mCrossed && TheRandomMissionManager->GetMission()->GetSymmetric() &&
|
||||||
|
TheRandomMissionManager->GetMission()->GetBackUpPath() )
|
||||||
|
{
|
||||||
|
mCrossed = true;
|
||||||
|
|
||||||
|
int directionSet[3][3] = {DIR_NW,DIR_W,DIR_SW,DIR_N,-1,DIR_S,DIR_NE,DIR_E,DIR_SE};
|
||||||
|
int ncx = (mXNodes-1)-c_x;
|
||||||
|
int ncy = (mYNodes-1)-c_y;
|
||||||
|
|
||||||
|
int x_delta = ncx - c_x;
|
||||||
|
int y_delta = ncy - c_y;
|
||||||
|
|
||||||
|
if( x_delta < -1 )
|
||||||
|
{
|
||||||
|
x_delta = -1;
|
||||||
|
}
|
||||||
|
else if( x_delta > 1 )
|
||||||
|
{
|
||||||
|
x_delta = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( y_delta < -1 )
|
||||||
|
{
|
||||||
|
y_delta = -1;
|
||||||
|
}
|
||||||
|
else if( y_delta > 1 )
|
||||||
|
{
|
||||||
|
y_delta = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure the mirror is actually in a different position than then un-mirrored node
|
||||||
|
if( x_delta || y_delta )
|
||||||
|
{
|
||||||
|
|
||||||
|
int d = directionSet[x_delta][y_delta];
|
||||||
|
int new_dir;
|
||||||
|
// d is the direction relative to the current cell
|
||||||
|
// new_dir is the direction relative to the next cell (N becomes S, NE becomes SW, etc...)
|
||||||
|
if( d < HALF_DIR_MAX )
|
||||||
|
{
|
||||||
|
new_dir = d + HALF_DIR_MAX;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new_dir = d - HALF_DIR_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
//NOTE: Knocking down these walls will cause instances to be created on this new artificial path
|
||||||
|
// Since this path could span more than just the normal 1 cell, these walls being knocked down are not exactly correct... but get the job done
|
||||||
|
|
||||||
|
// knock down walls
|
||||||
|
Cell(c_x,c_y).RemoveWall(d);
|
||||||
|
Cell(ncx,ncy).RemoveWall(new_dir); //DIR_MAX - d);
|
||||||
|
|
||||||
|
// set path id
|
||||||
|
Node(c_x, c_y)->SetPath(d, mPathCount);
|
||||||
|
Node(ncx, ncy)->SetPath(new_dir, mPathCount); //DIR_MAX - d, mPathCount);
|
||||||
|
|
||||||
|
// create an artificial path that crosses over to connect the symmetric and non-symmetric map parts
|
||||||
|
mTerrain->CreatePath( mPathCount++,
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
mPathPoints,
|
||||||
|
GetNodePos(c_x,c_y)[0],
|
||||||
|
GetNodePos(c_x,c_y)[1],
|
||||||
|
GetNodePos(ncx,ncy)[0],
|
||||||
|
GetNodePos(ncx,ncy)[1],
|
||||||
|
mPathMinWidth,
|
||||||
|
mPathMaxWidth,
|
||||||
|
mPathDepth,
|
||||||
|
mPathDeviation,
|
||||||
|
mPathBreadth );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PlaceLocation(c_x, c_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMPathManager::FindNodeByName
|
||||||
|
* Finds the managed node with the matching case-insensivity name
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* name - name of the node to find
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* a pointer to the found node or NULL if the node couldn't be found
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
CRMNode* CRMPathManager::FindNodeByName ( const char* name )
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
|
||||||
|
for ( j = mNodes.size() - 1; j >=0; j-- )
|
||||||
|
{
|
||||||
|
if ( !stricmp ( name, mNodes[j]->GetName ( ) ) )
|
||||||
|
return mNodes[j];
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMPathManager::SetPathStyle
|
||||||
|
* sets style for all paths
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* settings for paths that are created
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMPathManager::SetPathStyle (
|
||||||
|
const int points,
|
||||||
|
const float minwidth,
|
||||||
|
const float maxwidth,
|
||||||
|
const float depth,
|
||||||
|
const float deviation,
|
||||||
|
const float breadth
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// save path style
|
||||||
|
mPathPoints = points ;
|
||||||
|
mPathMinWidth = minwidth;
|
||||||
|
mPathMaxWidth = maxwidth;
|
||||||
|
mPathDepth = depth ;
|
||||||
|
mPathDeviation= deviation;
|
||||||
|
mPathBreadth = breadth ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMPathManager::SetRiverStyle
|
||||||
|
* sets style for all rivers
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* settings for river paths that are created
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMPathManager::SetRiverStyle (const int depth,
|
||||||
|
const int points,
|
||||||
|
const float minwidth,
|
||||||
|
const float maxwidth,
|
||||||
|
const float beddepth,
|
||||||
|
const float deviation,
|
||||||
|
const float breadth,
|
||||||
|
string bridge_name)
|
||||||
|
{
|
||||||
|
// save river style
|
||||||
|
mRiverDepth = depth;
|
||||||
|
mRiverPoints = points ;
|
||||||
|
mRiverMinWidth = minwidth;
|
||||||
|
mRiverMaxWidth = maxwidth;
|
||||||
|
mRiverBedDepth = beddepth ;
|
||||||
|
mRiverDeviation= deviation;
|
||||||
|
mRiverBreadth = breadth ;
|
||||||
|
mRiverBridge = bridge_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3_t& CRMPathManager::GetRiverPos( const int x, const int y )
|
||||||
|
{
|
||||||
|
mRiverPos[0] = (float)(x + 1.0f) / (float)(mXNodes+2);
|
||||||
|
mRiverPos[1] = (float)(y + 1.0f) / (float)(mYNodes+2);
|
||||||
|
return mRiverPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CRMPathManager::RiverVisit(const int c_x, const int c_y)
|
||||||
|
{
|
||||||
|
// does this cell have any neighbors with all walls intact?
|
||||||
|
int i,off;
|
||||||
|
|
||||||
|
// look at neighbors in random order
|
||||||
|
off = TheRandomMissionManager->GetLandScape()->irand(DIR_FIRST, DIR_MAX-1);
|
||||||
|
|
||||||
|
++mDepth; // track our depth of recursion
|
||||||
|
|
||||||
|
for (i = DIR_FIRST; i<DIR_MAX && mDepth <= mMaxDepth; i+=2)
|
||||||
|
{
|
||||||
|
int d = (i + off) % DIR_MAX;
|
||||||
|
if ( !Cell(c_x, c_y).Border(d) )
|
||||||
|
{ // we can move this way, since no border
|
||||||
|
int new_c_x = c_x + neighbor_x[d];
|
||||||
|
int new_c_y = c_y + neighbor_y[d];
|
||||||
|
if (RiverCell(new_c_x,new_c_y).Wall() == DIR_ALL)
|
||||||
|
{ // we have a new cell that has not been visited!
|
||||||
|
|
||||||
|
int new_dir;
|
||||||
|
// d is the direction relative to the current cell
|
||||||
|
// new_dir is the direction relative to the next cell (N becomes S, NE becomes SW, etc...)
|
||||||
|
if( d < HALF_DIR_MAX )
|
||||||
|
{
|
||||||
|
new_dir = d + HALF_DIR_MAX;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new_dir = d - HALF_DIR_MAX;
|
||||||
|
}
|
||||||
|
// knock down walls
|
||||||
|
RiverCell(c_x,c_y).RemoveWall(d);
|
||||||
|
RiverCell(new_c_x,new_c_y).RemoveWall(new_dir); //DIR_MAX - d);
|
||||||
|
|
||||||
|
// create river between cells
|
||||||
|
mTerrain->CreatePath ( mPathCount++,
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
mRiverPoints,
|
||||||
|
GetRiverPos(c_x,c_y)[0],
|
||||||
|
GetRiverPos(c_x,c_y)[1],
|
||||||
|
GetRiverPos(new_c_x,new_c_y)[0],
|
||||||
|
GetRiverPos(new_c_x,new_c_y)[1],
|
||||||
|
mRiverMinWidth,
|
||||||
|
mRiverMaxWidth,
|
||||||
|
mRiverBedDepth,
|
||||||
|
mRiverDeviation,
|
||||||
|
mRiverBreadth );
|
||||||
|
|
||||||
|
// flatten a small spot
|
||||||
|
CArea area;
|
||||||
|
float flat_radius = mRiverMinWidth *
|
||||||
|
fabs(TheRandomMissionManager->GetLandScape()->GetBounds()[1][0] - TheRandomMissionManager->GetLandScape()->GetBounds()[0][0]);
|
||||||
|
area.Init( GetRiverPos(c_x,c_y), flat_radius, 0.0f, AT_NONE, 0, 0 );
|
||||||
|
TheRandomMissionManager->GetLandScape()->FlattenArea (&area, 255 * mRiverBedDepth, false, true, true );
|
||||||
|
|
||||||
|
// recurse
|
||||||
|
RiverVisit(new_c_x, new_c_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --mDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMPathManager::GenerateRivers
|
||||||
|
* Creates a river which intersects the main path
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMPathManager::GenerateRivers ()
|
||||||
|
{
|
||||||
|
if (mRiverBedDepth == 1)
|
||||||
|
// no rivers
|
||||||
|
return;
|
||||||
|
|
||||||
|
mMaxDepth = mRiverDepth;
|
||||||
|
mDepth = 0;
|
||||||
|
|
||||||
|
int cell_x = 0;
|
||||||
|
int cell_y = 0;
|
||||||
|
|
||||||
|
// choose starting cell along an edge
|
||||||
|
int edge = TheRandomMissionManager->GetLandScape()->irand(0, 7);
|
||||||
|
switch ( edge )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
cell_x = mXNodes / 2; cell_y = 0;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
cell_x = mXNodes; cell_y = 0;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
cell_x = mXNodes; cell_y = mYNodes / 2;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
cell_x = mXNodes; cell_y = mYNodes;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
cell_x = mXNodes / 2; cell_y = mYNodes;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
cell_x = 0; cell_y = mYNodes;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
cell_x = 0; cell_y = mYNodes / 2;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
cell_x = 0; cell_y = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearCells(mXNodes+1, mYNodes+1);
|
||||||
|
|
||||||
|
mRiverCount = mPathCount;
|
||||||
|
|
||||||
|
// visit the first cell
|
||||||
|
RiverVisit(cell_x,cell_y);
|
||||||
|
|
||||||
|
mRiverCount = mPathCount - mRiverCount;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************
|
||||||
|
* CRMPathManager::GeneratePaths
|
||||||
|
* Creates all paths
|
||||||
|
*
|
||||||
|
* inputs:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* none
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
void CRMPathManager::GeneratePaths ( symmetry_t symmetric )
|
||||||
|
{
|
||||||
|
int cell_x = 0;
|
||||||
|
int cell_y = 0;
|
||||||
|
|
||||||
|
switch ( symmetric )
|
||||||
|
{
|
||||||
|
case SYMMETRY_TOPLEFT:
|
||||||
|
cell_x = mXNodes-1;
|
||||||
|
cell_y = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SYMMETRY_BOTTOMRIGHT:
|
||||||
|
cell_x = 0;
|
||||||
|
cell_y = mYNodes-1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
case SYMMETRY_NONE:
|
||||||
|
// choose starting cell along an edge
|
||||||
|
switch ( TheRandomMissionManager->GetLandScape()->irand(0, 7) )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
cell_x = mXNodes / 2;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
cell_x = mXNodes-1;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
cell_x = mXNodes-1; cell_y = mYNodes / 2;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
cell_x = mXNodes-1; cell_y = mYNodes-1;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
cell_x = mXNodes / 2; cell_y = mYNodes-1;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
cell_y = mYNodes-1;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
cell_y = mYNodes / 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
case 7:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// visit the first cell
|
||||||
|
PathVisit(cell_x,cell_y);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,223 @@
|
||||||
|
/************************************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (C) 2001-2002 Raven Software
|
||||||
|
*
|
||||||
|
* RM_Path.h
|
||||||
|
*
|
||||||
|
************************************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#if !defined(RM_PATH_H_INC)
|
||||||
|
#define RM_PATH_H_INC
|
||||||
|
|
||||||
|
#ifdef DEBUG_LINKING
|
||||||
|
#pragma message("...including RM_Path.h")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(CM_RANDOMTERRAIN_H_INC)
|
||||||
|
#include "../qcommon/cm_randomterrain.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CRMPathManager;
|
||||||
|
|
||||||
|
// directions you can proceed from cells
|
||||||
|
enum ERMDir
|
||||||
|
{
|
||||||
|
DIR_FIRST= 0,
|
||||||
|
DIR_N = 0,
|
||||||
|
DIR_NE,
|
||||||
|
DIR_E ,
|
||||||
|
DIR_SE,
|
||||||
|
DIR_S ,
|
||||||
|
DIR_SW,
|
||||||
|
DIR_W ,
|
||||||
|
DIR_NW,
|
||||||
|
DIR_MAX,
|
||||||
|
DIR_ALL = 255
|
||||||
|
};
|
||||||
|
|
||||||
|
#define HALF_DIR_MAX (DIR_MAX/2)
|
||||||
|
|
||||||
|
class CRMNode
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
string mName; // name of node - "" if not used yet
|
||||||
|
vec3_t mPos; // where node is
|
||||||
|
int mPathID[DIR_MAX]; // path id's that lead from this node
|
||||||
|
bool mAreaPointPlaced; // false if no area point here yet.
|
||||||
|
|
||||||
|
int mFlattenHeight;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CRMNode ( );
|
||||||
|
|
||||||
|
bool IsLocation() {return strlen(mName.c_str())>0;};
|
||||||
|
const char* GetName ( ) { return mName.c_str(); }
|
||||||
|
vec3_t& GetPos ( ) { return mPos; }
|
||||||
|
const float PathExist( const int dir) { return (mPathID[dir % DIR_MAX] != -1); };
|
||||||
|
const float GetPath ( const int dir) { return mPathID[dir % DIR_MAX]; };
|
||||||
|
bool AreaPoint() {return mAreaPointPlaced;};
|
||||||
|
|
||||||
|
void SetName ( const char* name ) { mName = name; }
|
||||||
|
void SetPos ( const vec3_t& v ) { VectorCopy ( v, mPos ); }
|
||||||
|
void SetPath( const int dir, const int id) { mPathID[dir % DIR_MAX] = id; };
|
||||||
|
void SetAreaPoint(bool ap) {mAreaPointPlaced = ap;};
|
||||||
|
|
||||||
|
void SetFlattenHeight(int flattenHeight) {mFlattenHeight = flattenHeight; }
|
||||||
|
int GetFlattenHeight() {return mFlattenHeight; }
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef vector<CRMNode*> rmNodeVector_t;
|
||||||
|
|
||||||
|
// named spots on the map, should be placed into nodes
|
||||||
|
class CRMLoc
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
string mName; // name of location
|
||||||
|
int mMinDepth;
|
||||||
|
int mMaxDepth;
|
||||||
|
int mMinPaths;
|
||||||
|
int mMaxPaths;
|
||||||
|
bool mPlaced; // location has been placed at a node
|
||||||
|
|
||||||
|
public:
|
||||||
|
CRMLoc (const char *name, const int min_depth, const int max_depth, const int min_paths =1, const int max_paths=1 )
|
||||||
|
: mMinDepth(min_depth), mMaxDepth(max_depth), mPlaced(false), mMinPaths(min_paths), mMaxPaths(max_paths)
|
||||||
|
{ mName = name; };
|
||||||
|
|
||||||
|
const char* GetName ( ) { return mName.c_str(); }
|
||||||
|
void SetName ( const char* name ) { mName = name; }
|
||||||
|
|
||||||
|
int MinDepth() {return mMinDepth;};
|
||||||
|
void SetMinDepth(const int deep) {mMinDepth = deep;};
|
||||||
|
|
||||||
|
int MaxDepth() {return mMaxDepth;};
|
||||||
|
void SetMaxDepth(const int deep) {mMaxDepth = deep;};
|
||||||
|
|
||||||
|
int MinPaths() {return mMinPaths;};
|
||||||
|
void SetMinPaths(const int paths) {mMinPaths = paths;};
|
||||||
|
|
||||||
|
int MaxPaths() {return mMaxPaths;};
|
||||||
|
void SetMaxPaths(const int paths) {mMaxPaths = paths;};
|
||||||
|
|
||||||
|
bool Placed() { return mPlaced; };
|
||||||
|
void SetPlaced(bool p) { mPlaced = p;};
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef vector<CRMLoc*> rmLocVector_t;
|
||||||
|
|
||||||
|
|
||||||
|
// cells are used for figuring out node connections / paths
|
||||||
|
struct CRMCell
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
int border;
|
||||||
|
int wall;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CRMCell() { border = 0; wall = DIR_ALL; };
|
||||||
|
|
||||||
|
int Border() {return border;};
|
||||||
|
int Wall() {return wall;};
|
||||||
|
bool Border(const int dir) { return (border & (1<<dir))!=0; };
|
||||||
|
bool Wall(const int dir) { return (wall & (1<<dir))!=0; };
|
||||||
|
void SetBorder(const int dir) { border |= (1<<dir); };
|
||||||
|
void SetWall(const int dir) { wall |= (1<<dir); };
|
||||||
|
void RemoveWall(const int dir) { wall &= ~(1<<dir); };
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef vector<CRMCell> rmCellVector_t;
|
||||||
|
|
||||||
|
|
||||||
|
class CRMPathManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int mXNodes; // number of nodes in the x dimension
|
||||||
|
int mYNodes; // number of nodes in the y dimension
|
||||||
|
|
||||||
|
private:
|
||||||
|
rmLocVector_t mLocations; // location, named spots to be placed at nodes
|
||||||
|
rmNodeVector_t mNodes; // nodes, spots on map that *may* be connected by paths
|
||||||
|
rmCellVector_t mCells; // array of cells for doing path generation
|
||||||
|
|
||||||
|
int mPathCount;
|
||||||
|
int mRiverCount;
|
||||||
|
int mMaxDepth; // deepest any location wants to be
|
||||||
|
int mDepth; // current depth
|
||||||
|
|
||||||
|
bool mCrossed; // used to indicate if paths crossed the imaginary diagonal that cuts symmetric maps in half
|
||||||
|
|
||||||
|
// path style
|
||||||
|
int mPathPoints;
|
||||||
|
float mPathMinWidth;
|
||||||
|
float mPathMaxWidth;
|
||||||
|
float mPathDepth;
|
||||||
|
float mPathDeviation;
|
||||||
|
float mPathBreadth;
|
||||||
|
|
||||||
|
// river style
|
||||||
|
int mRiverDepth;
|
||||||
|
int mRiverPoints;
|
||||||
|
float mRiverMinWidth;
|
||||||
|
float mRiverMaxWidth;
|
||||||
|
float mRiverBedDepth;
|
||||||
|
float mRiverDeviation;
|
||||||
|
float mRiverBreadth;
|
||||||
|
string mRiverBridge;
|
||||||
|
vec3_t mRiverPos;
|
||||||
|
|
||||||
|
static int neighbor_x[DIR_MAX];
|
||||||
|
static int neighbor_y[DIR_MAX];
|
||||||
|
|
||||||
|
CRandomTerrain* mTerrain;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CRMPathManager ( CRandomTerrain* terrain );
|
||||||
|
~CRMPathManager ( );
|
||||||
|
|
||||||
|
void ClearCells (int x_nodes, int y_nodes);
|
||||||
|
bool CreateArray ( const int x_nodes, const int y_nodes );
|
||||||
|
|
||||||
|
CRMNode* FindNodeByName ( const char* name );
|
||||||
|
CRMNode* Node ( const int x, const int y ) {return mNodes[x + y*mXNodes];};
|
||||||
|
|
||||||
|
void CreateLocation ( const char* name, const int min_depth, int max_depth, const int min_paths =1, int max_paths =1 );
|
||||||
|
|
||||||
|
vec3_t& GetNodePos ( const int x, const int y ) { return mNodes[x + y*mXNodes]->GetPos(); };
|
||||||
|
void SetNodePos ( const int x, const int y, const vec3_t& pos) { mNodes[x + y*mXNodes]->SetPos(pos); };
|
||||||
|
int GetPathCount () {return mPathCount;};
|
||||||
|
int GetRiverCount () {return mRiverCount;};
|
||||||
|
float GetRiverDepth () {return mRiverBedDepth;};
|
||||||
|
float GetPathDepth () {return mPathDepth;};
|
||||||
|
const char *GetBridgeName () {return mRiverBridge.c_str();};
|
||||||
|
vec3_t& GetRiverPos ( const int x, const int y );
|
||||||
|
|
||||||
|
CRMCell& Cell ( const int x, const int y ) {return mCells[x + y*mXNodes];};
|
||||||
|
CRMCell& RiverCell ( const int x, const int y ) {return mCells[x + y*(mXNodes+1)];};
|
||||||
|
void PlaceLocation ( const int x, const int y );
|
||||||
|
void PathVisit ( const int x, const int y );
|
||||||
|
void RiverVisit ( const int x, const int y );
|
||||||
|
void SetPathStyle ( const int points = 10,
|
||||||
|
const float minwidth = 0.01f,
|
||||||
|
const float maxwidth = 0.05f,
|
||||||
|
const float depth = 0.3f,
|
||||||
|
const float deviation = 0.2f,
|
||||||
|
const float breadth = 5);
|
||||||
|
|
||||||
|
void SetRiverStyle ( const int depth = 5,
|
||||||
|
const int points = 10,
|
||||||
|
const float minwidth = 0.01,
|
||||||
|
const float maxwidth = 0.03,
|
||||||
|
const float beddepth = 0.0f,
|
||||||
|
const float deviation = 0.25f,
|
||||||
|
const float breadth = 7,
|
||||||
|
string bridge_name = "");
|
||||||
|
|
||||||
|
void GeneratePaths ( symmetry_t symmetric = SYMMETRY_NONE );
|
||||||
|
void GenerateRivers ( );
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,533 @@
|
||||||
|
#include "../server/exe_headers.h"
|
||||||
|
|
||||||
|
#include "../client/client.h"
|
||||||
|
#include "../qcommon/cm_local.h"
|
||||||
|
#include "../renderer/tr_types.h"
|
||||||
|
#include "rm_headers.h"
|
||||||
|
|
||||||
|
//#include "../qcommon/q_imath.h"
|
||||||
|
|
||||||
|
#pragma optimize("", off)
|
||||||
|
|
||||||
|
void R_LoadDataImage ( const char *name, byte **pic, int *width, int *height);
|
||||||
|
void R_InvertImage ( byte *data, int width, int height, int depth);
|
||||||
|
void R_Resample ( byte *source, int swidth, int sheight, byte *dest, int dwidth, int dheight, int components);
|
||||||
|
void RE_GetModelBounds (refEntity_t *refEnt, vec3_t bounds1, vec3_t bounds2);
|
||||||
|
|
||||||
|
static CRMLandScape *rm_landscape;
|
||||||
|
static CCMLandScape *origin_land;
|
||||||
|
|
||||||
|
CRMLandScape::CRMLandScape(void)
|
||||||
|
{
|
||||||
|
common = NULL;
|
||||||
|
mDensityMap = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
CRMLandScape::~CRMLandScape(void)
|
||||||
|
{
|
||||||
|
if(mDensityMap)
|
||||||
|
{
|
||||||
|
Z_Free(mDensityMap);
|
||||||
|
mDensityMap = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCGHeightDetails::AddModel(const CRandomModel *hd)
|
||||||
|
{
|
||||||
|
if(mNumModels < MAX_RANDOM_MODELS)
|
||||||
|
{
|
||||||
|
mTotalFrequency += hd->GetFrequency();
|
||||||
|
mModels[mNumModels++] = *hd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CRMLandScape::AddModel(const int height, int maxheight, const CRandomModel *hd)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(maxheight > HEIGHT_RESOLUTION)
|
||||||
|
{
|
||||||
|
maxheight = HEIGHT_RESOLUTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = height; hd->GetModel() && (i < maxheight); i++)
|
||||||
|
{
|
||||||
|
mHeightDetails[i].AddModel(hd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CRMLandScape::LoadMiscentDef(const char *td)
|
||||||
|
{
|
||||||
|
char miscentDef[MAX_QPATH];
|
||||||
|
CGenericParser2 parse;
|
||||||
|
CGPGroup *basegroup, *classes, *items, *model;
|
||||||
|
CGPValue *pair;
|
||||||
|
|
||||||
|
Com_sprintf(miscentDef, MAX_QPATH, "ext_data/RMG/%s.miscents", Info_ValueForKey(td, "miscentDef"));
|
||||||
|
Com_DPrintf("CG_Terrain: Loading and parsing miscentDef %s.....\n", Info_ValueForKey(td, "miscentDef"));
|
||||||
|
|
||||||
|
if(!Com_ParseTextFile(miscentDef, parse))
|
||||||
|
{
|
||||||
|
Com_sprintf(miscentDef, MAX_QPATH, "ext_data/arioche/%s.miscents", Info_ValueForKey(td, "miscentDef"));
|
||||||
|
if(!Com_ParseTextFile(miscentDef, parse))
|
||||||
|
{
|
||||||
|
Com_Printf("Could not open %s\n", miscentDef);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The whole file....
|
||||||
|
basegroup = parse.GetBaseParseGroup();
|
||||||
|
|
||||||
|
// The root { } struct
|
||||||
|
classes = basegroup->GetSubGroups();
|
||||||
|
while(classes)
|
||||||
|
{
|
||||||
|
items = classes->GetSubGroups();
|
||||||
|
while(items)
|
||||||
|
{
|
||||||
|
if(!stricmp(items->GetName(), "miscent"))
|
||||||
|
{
|
||||||
|
int height, maxheight;
|
||||||
|
|
||||||
|
// Height must exist - the rest are optional
|
||||||
|
height = atol(items->FindPairValue("height", "0"));
|
||||||
|
maxheight = atol(items->FindPairValue("maxheight", "255"));
|
||||||
|
|
||||||
|
model = items->GetSubGroups();
|
||||||
|
while(model)
|
||||||
|
{
|
||||||
|
if(!stricmp(model->GetName(), "model"))
|
||||||
|
{
|
||||||
|
CRandomModel hd;
|
||||||
|
|
||||||
|
// Set defaults
|
||||||
|
hd.SetModel("");
|
||||||
|
hd.SetFrequency(1.0f);
|
||||||
|
hd.SetMinScale(1.0f);
|
||||||
|
hd.SetMaxScale(1.0f);
|
||||||
|
|
||||||
|
pair = model->GetPairs();
|
||||||
|
while(pair)
|
||||||
|
{
|
||||||
|
if(!stricmp(pair->GetName(), "name"))
|
||||||
|
{
|
||||||
|
hd.SetModel(pair->GetTopValue());
|
||||||
|
}
|
||||||
|
else if(!stricmp(pair->GetName(), "frequency"))
|
||||||
|
{
|
||||||
|
hd.SetFrequency((float)atof(pair->GetTopValue()));
|
||||||
|
}
|
||||||
|
else if(!stricmp(pair->GetName(), "minscale"))
|
||||||
|
{
|
||||||
|
hd.SetMinScale((float)atof(pair->GetTopValue()));
|
||||||
|
}
|
||||||
|
else if(!stricmp(pair->GetName(), "maxscale"))
|
||||||
|
{
|
||||||
|
hd.SetMaxScale((float)atof(pair->GetTopValue()));
|
||||||
|
}
|
||||||
|
pair = (CGPValue *)pair->GetNext();
|
||||||
|
}
|
||||||
|
AddModel(height, maxheight, &hd);
|
||||||
|
}
|
||||||
|
model = (CGPGroup *)model->GetNext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items = (CGPGroup *)items->GetNext();
|
||||||
|
}
|
||||||
|
classes = (CGPGroup *)classes->GetNext();
|
||||||
|
}
|
||||||
|
Com_ParseTextFileDestroy(parse);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CG_Decrease(byte *work, float lerp, int *info)
|
||||||
|
{
|
||||||
|
int val;
|
||||||
|
|
||||||
|
val = *work - origin_land->irand(2, 5);
|
||||||
|
*work = (byte)Com_Clamp(1, 255, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CRMLandScape::CreateRandomDensityMap(byte *density, int width, int height, int seed)
|
||||||
|
{
|
||||||
|
// int i, border, inc;
|
||||||
|
int x, y, count;
|
||||||
|
// byte *work, *work2;
|
||||||
|
CArea *area;
|
||||||
|
vec3_t derxelSize, pos;
|
||||||
|
ivec3_t dmappos;
|
||||||
|
byte *hm_map = common->GetHeightMap();
|
||||||
|
int hm_width = common->GetRealWidth();
|
||||||
|
int hm_height = common->GetRealHeight();
|
||||||
|
int xpos, ypos, dx, dy;
|
||||||
|
byte *densityPos = density;
|
||||||
|
bool foundUneven;
|
||||||
|
|
||||||
|
// Init to linear spread
|
||||||
|
memset(density, 0, width * height);
|
||||||
|
|
||||||
|
/* // Make more prevalent towards the edges
|
||||||
|
border = Com_Clamp(6, 12, (width + height) >> 4);
|
||||||
|
|
||||||
|
for(i = 0; i < border; i++)
|
||||||
|
{
|
||||||
|
inc = (border - i + 1) * 9;
|
||||||
|
|
||||||
|
// Top line
|
||||||
|
work = density + i + (i * width);
|
||||||
|
for(x = i; x < width - i; x++, work++)
|
||||||
|
{
|
||||||
|
*work += (byte)common->irand(inc >> 1, inc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Left and right edges
|
||||||
|
work = density + i + ((i + 1) * width);
|
||||||
|
work2 = density + (width - i) + ((i + 1) * width);
|
||||||
|
for(y = i + 1; y < height - i - 2; y++, work += width, work2 += width)
|
||||||
|
{
|
||||||
|
*work += (byte)common->irand(inc >> 1, inc);
|
||||||
|
*work2 += (byte)common->irand(inc >> 1, inc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bottom line
|
||||||
|
work = density + i + ((height - i - 1) * width);
|
||||||
|
for(x = i; x < width - i; x++, work++)
|
||||||
|
{
|
||||||
|
*work += (byte)common->irand(inc >> 1, inc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
count = 0;
|
||||||
|
|
||||||
|
for(y=0;y<height;y++)
|
||||||
|
{
|
||||||
|
for(x=0;x<width;x++,densityPos++)
|
||||||
|
{
|
||||||
|
xpos = (x * hm_width / width);
|
||||||
|
ypos = (y * hm_height / height);
|
||||||
|
ypos = hm_height - ypos - 1;
|
||||||
|
|
||||||
|
if (hm_map[ypos*hm_width + xpos] < 150)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foundUneven = false;
|
||||||
|
for(dx=-4;(dx<=4 && !foundUneven);dx++)
|
||||||
|
{
|
||||||
|
for(dy=-4;(dy<=4 && !foundUneven);dy++)
|
||||||
|
{
|
||||||
|
if (dx == 0 && dy == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((xpos+dx) >= 0 && (xpos+dx) < hm_width && (ypos+dy) >= 0 && (ypos+dy) < hm_height)
|
||||||
|
{
|
||||||
|
if (hm_map[(ypos+dy)*hm_width + (xpos+dx)] < 190)
|
||||||
|
{
|
||||||
|
*densityPos = 205;
|
||||||
|
count++;
|
||||||
|
foundUneven = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FILE *FH;
|
||||||
|
|
||||||
|
FH = fopen("c:\o.raw", "wb");
|
||||||
|
fwrite(hm_map, 1, common->GetRealWidth() * common->GetRealHeight(), FH);
|
||||||
|
fclose(FH);
|
||||||
|
|
||||||
|
FH = fopen("c:\d.raw", "wb");
|
||||||
|
fwrite(density, 1, width*height, FH);
|
||||||
|
fclose(FH);
|
||||||
|
*/
|
||||||
|
// Reduce severely for any settlements/buildings/objectives
|
||||||
|
VectorScale(common->GetSize(), 1.0f / width, derxelSize);
|
||||||
|
|
||||||
|
origin_land = common;
|
||||||
|
area = common->GetFirstArea();
|
||||||
|
while(area)
|
||||||
|
{
|
||||||
|
// Skip group types since they encompass to much open area
|
||||||
|
if ( area->GetType ( ) == AT_GROUP )
|
||||||
|
{
|
||||||
|
area = common->GetNextArea();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
VectorSubtract(area->GetPosition(), common->GetMins(), pos);
|
||||||
|
VectorInverseScaleVector(pos, derxelSize, dmappos);
|
||||||
|
// Damn upside down gensurf
|
||||||
|
dmappos[1] = height - dmappos[1];
|
||||||
|
|
||||||
|
count = ceilf(area->GetRadius() / derxelSize[1]);
|
||||||
|
|
||||||
|
while(count > 0)
|
||||||
|
{
|
||||||
|
CM_CircularIterate(density, width, height, dmappos[0], dmappos[1], 0, count, NULL, CG_Decrease);
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
area = common->GetNextArea();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CRMLandScape::LoadDensityMap(const char *td)
|
||||||
|
{
|
||||||
|
char densityMap[MAX_QPATH];
|
||||||
|
byte *imageData;
|
||||||
|
int iWidth, iHeight, seed;
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
// Fill in with default values
|
||||||
|
mDensityMap = (byte *)Z_Malloc(common->GetBlockCount(), TAG_R_TERRAIN, qfalse);
|
||||||
|
memset(mDensityMap, 128, common->GetBlockCount());
|
||||||
|
|
||||||
|
// Load in density map (if any)
|
||||||
|
Com_sprintf(densityMap, MAX_QPATH, "%s", Info_ValueForKey(td, "densityMap"));
|
||||||
|
if(strlen(densityMap))
|
||||||
|
{
|
||||||
|
Com_DPrintf("CG_Terrain: Loading density map %s.....\n", densityMap);
|
||||||
|
R_LoadDataImage(densityMap, &imageData, &iWidth, &iHeight);
|
||||||
|
if(imageData)
|
||||||
|
{
|
||||||
|
if(strstr(densityMap, "density_"))
|
||||||
|
{
|
||||||
|
seed = strtoul(Info_ValueForKey(td, "seed"),&ptr,10);
|
||||||
|
CreateRandomDensityMap(imageData, iWidth, iHeight, seed);
|
||||||
|
}
|
||||||
|
R_Resample(imageData, iWidth, iHeight, mDensityMap, common->GetBlockWidth(), common->GetBlockHeight(), 1);
|
||||||
|
R_InvertImage(mDensityMap, common->GetBlockWidth(), common->GetBlockHeight(), 1);
|
||||||
|
Z_Free(imageData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CRandomModel *CCGHeightDetails::GetRandomModel(CCMLandScape *land)
|
||||||
|
{
|
||||||
|
int seek, i;
|
||||||
|
|
||||||
|
seek = land->irand(0, mTotalFrequency);
|
||||||
|
for(i = 0; i < mNumModels; i++)
|
||||||
|
{
|
||||||
|
seek -= mModels[i].GetFrequency();
|
||||||
|
if(seek <= 0)
|
||||||
|
{
|
||||||
|
return(mModels + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(0);
|
||||||
|
return(NULL);
|
||||||
|
}
|
||||||
|
#ifndef DEDICATED
|
||||||
|
void CRMLandScape::Sprinkle(CCMPatch *patch, CCGHeightDetails *hd, int level)
|
||||||
|
{
|
||||||
|
int i, count, px, py;
|
||||||
|
float density;
|
||||||
|
vec3_t origin, scale, angles, bounds[2];
|
||||||
|
refEntity_t refEnt;
|
||||||
|
CRandomModel *rm;
|
||||||
|
CArea area;
|
||||||
|
// int areaTypes[] = { AT_BSP, AT_OBJECTIVE };
|
||||||
|
// TCGMiscEnt *data = (TCGMiscEnt *)cl.mSharedMemory;
|
||||||
|
// TCGTrace *td = (TCGTrace *)cl.mSharedMemory;
|
||||||
|
|
||||||
|
// memset(&refEnt, 0, sizeof(refEntity_t));
|
||||||
|
|
||||||
|
px = patch->GetHeightMapX() / common->GetTerxels();
|
||||||
|
py = patch->GetHeightMapY() / common->GetTerxels();
|
||||||
|
// Get a number -5.3f to 5.3f
|
||||||
|
density = (mDensityMap[px + (common->GetBlockWidth() * py)] - 128) / 24.0f;
|
||||||
|
// ..and multiply that into the count
|
||||||
|
count = Round(common->GetPatchScalarSize() * hd->GetAverageFrequency() * powf(2.0f, density) * 0.001);
|
||||||
|
|
||||||
|
for(i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if(!common->irand(0, 10))
|
||||||
|
{
|
||||||
|
vec3_t temp;
|
||||||
|
trace_t tr;
|
||||||
|
float average;
|
||||||
|
|
||||||
|
rm = hd->GetRandomModel(common);
|
||||||
|
|
||||||
|
refEnt.hModel = re.RegisterModel(rm->GetModelName());
|
||||||
|
refEnt.frame = 0;
|
||||||
|
RE_GetModelBounds(&refEnt, bounds[0], bounds[1]);
|
||||||
|
|
||||||
|
// Calculate the scale using some magic to help ensure that the
|
||||||
|
// scales are never too different from eachother. Otherwise you
|
||||||
|
// could get an entity that is really small on one axis but huge
|
||||||
|
// on another.
|
||||||
|
temp[0] = common->flrand(rm->GetMinScale(), rm->GetMaxScale());
|
||||||
|
temp[1] = common->flrand(rm->GetMinScale(), rm->GetMaxScale());
|
||||||
|
temp[2] = common->flrand(rm->GetMinScale(), rm->GetMaxScale());
|
||||||
|
|
||||||
|
// Average of the three random numbers and divide that by two
|
||||||
|
average = ( ( temp[0] + temp[1] + temp[2] ) / 3) / 2;
|
||||||
|
|
||||||
|
// Add in half of the other two numbers and then subtract half the average to prevent.
|
||||||
|
// any number from going beyond the range. If all three numbers were the same then
|
||||||
|
// they would remain unchanged after this calculation.
|
||||||
|
scale[0] = temp[0] + (temp[1]+temp[2]) / 2 - average;
|
||||||
|
scale[1] = temp[1] + (temp[0]+temp[2]) / 2 - average;
|
||||||
|
scale[2] = temp[2] + (temp[0]+temp[1]) / 2 - average;
|
||||||
|
|
||||||
|
angles[0] = 0.0f;
|
||||||
|
angles[1] = common->flrand((float)-M_PI, (float)M_PI);
|
||||||
|
angles[2] = 0.0f;
|
||||||
|
|
||||||
|
VectorCopy(patch->GetMins(), origin);
|
||||||
|
origin[0] += common->flrand(0.0f, common->GetPatchWidth());
|
||||||
|
origin[1] += common->flrand(0.0f, common->GetPatchHeight());
|
||||||
|
// Get above world height
|
||||||
|
float slope = common->GetWorldHeight(origin, bounds, true);
|
||||||
|
|
||||||
|
if (slope > 1.33)
|
||||||
|
{ // spot has too steep of a slope
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(origin[2] < common->GetWaterHeight())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// very that we aren't dropped too low
|
||||||
|
if (origin[2] < common->CalcWorldHeight(level))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hack-ariffic, don't allow them to drop below the big player clip brush.
|
||||||
|
if (origin[2] < 1280 )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// FIXME: shouldn't be using a hard-coded 1280 number, only allow to spawn if inside player clip brush?
|
||||||
|
// if( !(CONTENTS_PLAYERCLIP & VM_Call( cgvm, CG_POINT_CONTENTS )) )
|
||||||
|
// {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// Simple radius check for buildings
|
||||||
|
/* area.Init(origin, VectorLength(bounds[0]));
|
||||||
|
if(common->AreaCollision(&area, areaTypes, sizeof(areaTypes) / sizeof(int)))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}*/
|
||||||
|
// Make sure there is no architecture around - doesn't work for ents though =(
|
||||||
|
|
||||||
|
/*
|
||||||
|
memset(td, sizeof(*td), 0);
|
||||||
|
VectorCopy(origin, td->mStart);
|
||||||
|
VectorCopy(bounds[0], td->mMins);
|
||||||
|
VectorCopy(bounds[1], td->mMaxs);
|
||||||
|
VectorCopy(origin, td->mEnd);
|
||||||
|
td->mSkipNumber = -1;
|
||||||
|
td->mMask = MASK_PLAYERSOLID;
|
||||||
|
*/
|
||||||
|
SV_Trace(&tr, origin, bounds[0], bounds[1], origin, -1, (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY|CONTENTS_TERRAIN));
|
||||||
|
|
||||||
|
/*
|
||||||
|
VM_Call( cgvm, CG_TRACE );
|
||||||
|
if(td->mResult.surfaceFlags & SURF_NOMISCENTS)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(td->mResult.startsolid)
|
||||||
|
{
|
||||||
|
// continue;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if (tr.surfaceFlags & SURF_NOMISCENTS)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (tr.startsolid)
|
||||||
|
{
|
||||||
|
// continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get minimum height of area
|
||||||
|
common->GetWorldHeight(origin, bounds, false);
|
||||||
|
// Account for relative origin
|
||||||
|
origin[2] -= bounds[0][2] * scale[2];
|
||||||
|
origin[2] -= common->flrand(2.0, (bounds[1][2] - bounds[0][2]) / 4);
|
||||||
|
|
||||||
|
//rwwFIXMEFIXME: Do this properly
|
||||||
|
// Spawn the client model
|
||||||
|
/*
|
||||||
|
strcpy(data->mModel, rm->GetModelName());
|
||||||
|
VectorCopy(origin, data->mOrigin);
|
||||||
|
VectorCopy(angles, data->mAngles);
|
||||||
|
VectorCopy(scale, data->mScale);
|
||||||
|
VM_Call( cgvm, CG_MISC_ENT);
|
||||||
|
*/
|
||||||
|
|
||||||
|
mModelCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // !DEDICATED
|
||||||
|
|
||||||
|
void CRMLandScape::SpawnPatchModels(CCMPatch *patch)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
CCGHeightDetails *hd;
|
||||||
|
|
||||||
|
// Rand_Init(10);
|
||||||
|
#ifndef DEDICATED
|
||||||
|
for(i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
hd = mHeightDetails + patch->GetHeight(i);
|
||||||
|
if(hd->GetNumModels())
|
||||||
|
{
|
||||||
|
Sprinkle(patch, hd, patch->GetHeight(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // !DEDICATED
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpawnPatchModelsWrapper(CCMPatch *patch, void *userdata)
|
||||||
|
{
|
||||||
|
CRMLandScape *landscape = (CRMLandScape *)userdata;
|
||||||
|
landscape->SpawnPatchModels(patch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RM_CreateRandomModels(int terrainId, const char *terrainInfo)
|
||||||
|
{
|
||||||
|
CRMLandScape *landscape;
|
||||||
|
|
||||||
|
landscape = rm_landscape = new CRMLandScape;
|
||||||
|
landscape->SetCommon(cmg.landScape);
|
||||||
|
|
||||||
|
Com_DPrintf("CG_Terrain: Creating random models.....\n");
|
||||||
|
landscape->LoadMiscentDef(terrainInfo);
|
||||||
|
landscape->LoadDensityMap(terrainInfo);
|
||||||
|
landscape->ClearModelCount();
|
||||||
|
CM_TerrainPatchIterate(landscape->GetCommon(), SpawnPatchModelsWrapper, landscape);
|
||||||
|
|
||||||
|
Com_DPrintf(".....%d random client models spawned\n", landscape->GetModelCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
void RM_InitTerrain(void)
|
||||||
|
{
|
||||||
|
rm_landscape = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RM_ShutdownTerrain(void)
|
||||||
|
{
|
||||||
|
CRMLandScape *landscape;
|
||||||
|
|
||||||
|
landscape = rm_landscape;
|
||||||
|
if(landscape)
|
||||||
|
{
|
||||||
|
// CM_ShutdownTerrain(i);
|
||||||
|
delete landscape;
|
||||||
|
rm_landscape = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// end
|
||||||
|
|
||||||
|
#pragma optimize("", on)
|
|
@ -0,0 +1,97 @@
|
||||||
|
#pragma once
|
||||||
|
#if !defined(RM_TERRAIN_H_INC)
|
||||||
|
#define RM_TERRAIN_H_INC
|
||||||
|
|
||||||
|
#define MAX_RANDOM_MODELS 8
|
||||||
|
|
||||||
|
class CRandomModel
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
char mModelName[MAX_QPATH];
|
||||||
|
float mFrequency;
|
||||||
|
float mMinScale;
|
||||||
|
float mMaxScale;
|
||||||
|
public:
|
||||||
|
CRandomModel(void) { }
|
||||||
|
~CRandomModel(void) { }
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
const bool GetModel( void ) const { return(!!strlen(mModelName)); }
|
||||||
|
const char *GetModelName( void ) const { return(mModelName); }
|
||||||
|
void SetModel(const char *name) { Com_sprintf(mModelName, MAX_QPATH, "%s.md3", name); }
|
||||||
|
const float GetFrequency(void) const { return(mFrequency); }
|
||||||
|
void SetFrequency(const float freq) { mFrequency = freq; }
|
||||||
|
const float GetMinScale(void) const { return(mMinScale); }
|
||||||
|
void SetMinScale(const float minscale) { mMinScale = minscale; }
|
||||||
|
const float GetMaxScale(void) const { return(mMaxScale); }
|
||||||
|
void SetMaxScale(const float maxscale) { mMaxScale = maxscale; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class CCGHeightDetails
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
int mNumModels;
|
||||||
|
int mTotalFrequency;
|
||||||
|
CRandomModel mModels[MAX_RANDOM_MODELS];
|
||||||
|
public:
|
||||||
|
// Constructors
|
||||||
|
CCGHeightDetails( void ) { memset(this, 0, sizeof(*this)); }
|
||||||
|
~CCGHeightDetails( void ) { }
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
const int GetNumModels(void) const { return(mNumModels); }
|
||||||
|
const int GetAverageFrequency(void) const { return(mTotalFrequency / mNumModels); }
|
||||||
|
|
||||||
|
// Prototypes
|
||||||
|
void AddModel(const CRandomModel *hd);
|
||||||
|
CRandomModel *GetRandomModel(CCMLandScape *land);
|
||||||
|
};
|
||||||
|
|
||||||
|
class CCGPatch
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
class CCMLandScape *owner;
|
||||||
|
class CCGLandScape *localowner;
|
||||||
|
CCMPatch *common;
|
||||||
|
public:
|
||||||
|
};
|
||||||
|
|
||||||
|
class CRMLandScape
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
CCMLandScape *common;
|
||||||
|
|
||||||
|
byte *mDensityMap; // Data image of model densities
|
||||||
|
int mModelCount; // Count of spawned client models
|
||||||
|
CCGHeightDetails mHeightDetails[HEIGHT_RESOLUTION]; // Array of info specific to height
|
||||||
|
|
||||||
|
public:
|
||||||
|
CRMLandScape(void);
|
||||||
|
~CRMLandScape(void);
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
void SetCommon(CCMLandScape *landscape) { common = landscape; }
|
||||||
|
const CCMLandScape *GetCommon( void ) const { return(common); }
|
||||||
|
const thandle_t GetCommonId( void ) const { return(common->GetTerrainId()); }
|
||||||
|
const int GetTerxels(void) const { return(common->GetTerxels()); }
|
||||||
|
const int GetRealWidth(void) const { return(common->GetRealWidth()); }
|
||||||
|
const float GetPatchScalarSize(void) const { return(common->GetPatchScalarSize()); }
|
||||||
|
const CCGHeightDetails *GetHeightDetail(int height) const { return(mHeightDetails + height); }
|
||||||
|
void ClearModelCount(void) { mModelCount = 0; }
|
||||||
|
const int GetModelCount(void) const { return(mModelCount); }
|
||||||
|
|
||||||
|
// Prototypes
|
||||||
|
void SetShaders(const int height, const qhandle_t shader);
|
||||||
|
void AddModel(const int height, int maxheight, const CRandomModel *hd);
|
||||||
|
void LoadMiscentDef(const char *td);
|
||||||
|
void LoadDensityMap(const char *td);
|
||||||
|
void SpawnPatchModels(CCMPatch *patch);
|
||||||
|
void Sprinkle(CCMPatch *patch, CCGHeightDetails *hd, int level);
|
||||||
|
void CreateRandomDensityMap(byte *imageData, int width, int height, int seed);
|
||||||
|
};
|
||||||
|
|
||||||
|
void RM_CreateRandomModels(int terrainId, const char *terrainInfo);
|
||||||
|
void RM_InitTerrain(void);
|
||||||
|
void RM_ShutdownTerrain(void);
|
||||||
|
|
||||||
|
#endif // RM_TERRAIN_H_INC
|
Binary file not shown.
|
@ -0,0 +1,419 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD TEMPLATE LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Graph Region
|
||||||
|
// ------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_GRAPH_REGION_INC)
|
||||||
|
#define RATL_GRAPH_REGION_INC
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Includes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if defined(RA_DEBUG_LINKING)
|
||||||
|
#pragma message("...including graph_region.h")
|
||||||
|
#endif
|
||||||
|
#if !defined(RAGL_COMMON_INC)
|
||||||
|
#include "ragl_common.h"
|
||||||
|
#endif
|
||||||
|
#if !defined(RAGL_GRAPH_VS_INC)
|
||||||
|
#include "graph_vs.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace ragl
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Graph Region Class
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
template <class TNODE, int MAXNODES, class TEDGE, int MAXEDGES, int NUM_EDGES_PER_NODE, int MAXREGIONS, int MAXREGIONEDGES>
|
||||||
|
class graph_region : public ratl::ratl_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Capacity Enum
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
NULL_REGION = -1,
|
||||||
|
NULL_EDGE = -1,
|
||||||
|
CAPACITY = MAXREGIONS
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Some Public Type Defines
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
typedef ragl::graph_vs<TNODE, MAXNODES, TEDGE, MAXEDGES, NUM_EDGES_PER_NODE> TGraph;
|
||||||
|
typedef ratl::vector_vs<int, MAXNODES> TRegions;
|
||||||
|
typedef ratl::vector_vs<short, MAXREGIONS> TRegionEdge; // List Of All Edges Which Connect RegionA<->RegionB
|
||||||
|
typedef ratl::pool_vs<TRegionEdge, MAXREGIONEDGES> TEdges; // Pool Of All RegionEdges
|
||||||
|
typedef ratl::grid2_vs<short, MAXREGIONS, MAXREGIONS> TLinks; // Graph Of Links From Region To Region, Each Points To A RegionEdge
|
||||||
|
typedef ratl::bits_vs<MAXREGIONS> TClosed;
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
graph_region(TGraph& Graph) : mGraph(Graph)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
~graph_region()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Clear Out All Temp Data So We Can Recalculate Regions
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
mRegions.resize(0, (int)NULL_REGION);
|
||||||
|
mRegions.resize(MAXNODES, (int)NULL_REGION);
|
||||||
|
mRegionCount = 0;
|
||||||
|
mReservedRegionCount = 0;
|
||||||
|
|
||||||
|
mLinks.init(NULL_EDGE);
|
||||||
|
|
||||||
|
for (int i=0; i<MAXREGIONEDGES; i++)
|
||||||
|
{
|
||||||
|
if (mEdges.is_used(i))
|
||||||
|
{
|
||||||
|
mEdges[i].resize(0, NULL_EDGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mEdges.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// How Many Regions Have Been Created
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int size()
|
||||||
|
{
|
||||||
|
return mRegionCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get The Region For A Given Node
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int get_node_region(int Node)
|
||||||
|
{
|
||||||
|
return mRegions[mGraph.node_index(Node)];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Call this function to find out if it is at all possible to get from nodeA to
|
||||||
|
// nodeB. If there is no possible connection, or there is one, but the connection
|
||||||
|
// is not valid at the current time, this routine will return false. Use it as
|
||||||
|
// a quick cull routine before a search.
|
||||||
|
//
|
||||||
|
// In order to use this function, you must have an EdgeQuery class (use the default
|
||||||
|
// above, or derive your own for more specialized behavior).
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool has_valid_edge(int NodeA, int NodeB, const typename TGraph::user& user)
|
||||||
|
{
|
||||||
|
int RegionA = mRegions[NodeA];
|
||||||
|
int RegionB = mRegions[NodeB];
|
||||||
|
|
||||||
|
if (RegionA==RegionB)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mClosed.clear();
|
||||||
|
|
||||||
|
return has_valid_region_edge(RegionA, RegionB, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Reserve Region
|
||||||
|
//
|
||||||
|
// Allows a user to pre-allocate a special region for a group of points
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int reserve()
|
||||||
|
{
|
||||||
|
assert(mRegionCount < (MAXREGIONS-1));
|
||||||
|
if (mRegionCount >= (MAXREGIONS-1) )
|
||||||
|
{//stop adding points, we're full, you MUST increase MAXREGIONS for this to work
|
||||||
|
return NULL_REGION;
|
||||||
|
}
|
||||||
|
mReservedRegionCount ++;
|
||||||
|
mRegionCount ++;
|
||||||
|
return (mRegionCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// assign_region
|
||||||
|
//
|
||||||
|
// Allows a user to pre-allocate a special region for a group of points
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void assign_region(int NodeIndex, int RegionIndex)
|
||||||
|
{
|
||||||
|
mRegions[NodeIndex] = RegionIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Define Regions
|
||||||
|
//
|
||||||
|
// Scan through all the nodes (calling the depth first recursive traversal below),
|
||||||
|
// and mark regions of nodes which can traverse to one another without needing to check
|
||||||
|
// for valid edges.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool find_regions(const typename TGraph::user& user)
|
||||||
|
{
|
||||||
|
int CurNodeIndex;
|
||||||
|
for (TGraph::TNodes::iterator i=mGraph.nodes_begin(); i!=mGraph.nodes_end(); i++)
|
||||||
|
{
|
||||||
|
CurNodeIndex = i.index();
|
||||||
|
if (mRegions[CurNodeIndex] == NULL_REGION)
|
||||||
|
{
|
||||||
|
assert(mRegionCount < (MAXREGIONS-1));
|
||||||
|
if (mRegionCount >= (MAXREGIONS-1) )
|
||||||
|
{//stop adding points, we're full, you MUST increase MAXREGIONS for this to work
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mRegionCount ++; // Allocate The New Region
|
||||||
|
assign(CurNodeIndex, user); // Assign All Points To It
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mRegionCount ++; // Size is actually 1 greater than the number of regions
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Search For All Possible Edges Which Connect Regions
|
||||||
|
//
|
||||||
|
// Once called, this class will have reference data for how to get from one region
|
||||||
|
// to another.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool find_region_edges()
|
||||||
|
{
|
||||||
|
int RegionA;
|
||||||
|
int RegionB;
|
||||||
|
int RegionLink;
|
||||||
|
bool Success = true;
|
||||||
|
bool ReservedRegionLink;
|
||||||
|
|
||||||
|
for (int indexA=0; indexA<MAXNODES; indexA++)
|
||||||
|
{
|
||||||
|
RegionA = mRegions[indexA];
|
||||||
|
if (RegionA!=NULL_REGION)
|
||||||
|
{
|
||||||
|
for (int indexB=0; indexB<MAXNODES; indexB++)
|
||||||
|
{
|
||||||
|
RegionB = mRegions[indexB];
|
||||||
|
ReservedRegionLink = (RegionA<=mReservedRegionCount || RegionB<=mReservedRegionCount);
|
||||||
|
if (RegionB!=NULL_REGION && RegionB!=RegionA && mGraph.get_edge_across(indexA, indexB))
|
||||||
|
{
|
||||||
|
RegionLink = mLinks.get(RegionA, RegionB);
|
||||||
|
|
||||||
|
// Do We Need To Allocate A New Region Link Vector?
|
||||||
|
//--------------------------------------------------
|
||||||
|
if (RegionLink==-1)
|
||||||
|
{
|
||||||
|
if (ReservedRegionLink)
|
||||||
|
{
|
||||||
|
mLinks.get(RegionA, RegionB) = -2; // Special Flag For Reserved Regions - they have no edges
|
||||||
|
mLinks.get(RegionB, RegionA) = -2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (mEdges.full())
|
||||||
|
{
|
||||||
|
assert("graph_region: Too Many Region Edges"==0);
|
||||||
|
Success = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RegionLink = mEdges.alloc();
|
||||||
|
mEdges[RegionLink].resize(0, NULL_EDGE);
|
||||||
|
mEdges[RegionLink].push_back(mGraph.get_edge_across(indexA, indexB));
|
||||||
|
|
||||||
|
mLinks.get(RegionA, RegionB) = RegionLink;
|
||||||
|
mLinks.get(RegionB, RegionA) = RegionLink;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Add This Edge To The Other Region Links
|
||||||
|
//-----------------------------------------
|
||||||
|
else if (!ReservedRegionLink)
|
||||||
|
{
|
||||||
|
mEdges[RegionLink].push_back(mGraph.get_edge_across(indexA, indexB));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// This Routine Is A Depth First Recursive Traversal
|
||||||
|
//
|
||||||
|
// It will visit all neighbors for each node which have not already been visited
|
||||||
|
// and assigned to a region. Neighbors must always be valid.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void assign(int Node, const typename TGraph::user& user)
|
||||||
|
{
|
||||||
|
mRegions[Node] = mRegionCount;
|
||||||
|
for (int i=0; i<MAXNODES; i++)
|
||||||
|
{
|
||||||
|
if (mRegions[i]==-1)
|
||||||
|
{
|
||||||
|
int edgeNum = mGraph.get_edge_across(Node, i);
|
||||||
|
if (edgeNum && !user.can_be_invalid(mGraph.get_edge(edgeNum)))
|
||||||
|
{
|
||||||
|
assign(i, user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// This Routine Is A Depth First Recursive Search For Target Region
|
||||||
|
//
|
||||||
|
// Visited regions are makred on the "closed" bit field.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool has_valid_region_edge(int CurRegion, int TargetRegion, const typename TGraph::user& user)
|
||||||
|
{
|
||||||
|
// Mark The Cur Region As Visited, So We Don't Try To Return To It
|
||||||
|
//-----------------------------------------------------------------
|
||||||
|
mClosed.set_bit(CurRegion);
|
||||||
|
|
||||||
|
// If The Two Nodes Are In The Same Region, Then This Is Valid
|
||||||
|
//-------------------------------------------------------------
|
||||||
|
if (CurRegion==TargetRegion)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan Through The Cur Region's Neighbors With Currently Valid Region Edges
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
int CurRegionEdge;
|
||||||
|
for (int NextRegion=0; NextRegion<mRegionCount; NextRegion++)
|
||||||
|
{
|
||||||
|
// Check If The Link Exists And We Have Not Already Visited The Next Region
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
CurRegionEdge = mLinks.get(CurRegion, NextRegion);
|
||||||
|
if (CurRegionEdge!=NULL_EDGE && !mClosed.get_bit(NextRegion))
|
||||||
|
{
|
||||||
|
if (CurRegion<=mReservedRegionCount)
|
||||||
|
{
|
||||||
|
// Great, So We Have Found A Valid Neighboring Region, Search There
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
if (has_valid_region_edge(NextRegion, TargetRegion, user))
|
||||||
|
{
|
||||||
|
return true; // HEY! Somehow, Going To Next Region Got Us To The Target Region!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Scan Through This Region Edge List Of Graph Edges For Any Valid One
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
assert(mEdges[CurRegionEdge].size()>0);
|
||||||
|
for (int j=0; j<mEdges[CurRegionEdge].size(); j++)
|
||||||
|
{
|
||||||
|
if (user.is_valid(
|
||||||
|
mGraph.get_edge(mEdges[CurRegionEdge][j]),
|
||||||
|
(NextRegion==TargetRegion)?(-1):(0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Great, So We Have Found A Valid Neighboring Region, Search There
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
if (has_valid_region_edge(NextRegion, TargetRegion, user))
|
||||||
|
{
|
||||||
|
return true; // HEY! Somehow, Going To Next Region Got Us To The Target Region!
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ok, The Target Region Turned Out To Be A Dead End, We Can Stop Trying To Get There
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nope, We Failed To Find Any Valid Region Edges Which Lead To The Target Region
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TGraph& mGraph;
|
||||||
|
|
||||||
|
TRegions mRegions;
|
||||||
|
int mRegionCount;
|
||||||
|
int mReservedRegionCount;
|
||||||
|
|
||||||
|
TLinks mLinks;
|
||||||
|
TEdges mEdges;
|
||||||
|
TClosed mClosed;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
#if !defined(FINAL_BUILD)
|
||||||
|
void ProfileSpew()
|
||||||
|
{
|
||||||
|
ProfilePrint("");
|
||||||
|
ProfilePrint("");
|
||||||
|
ProfilePrint("--------------------------------------------------------");
|
||||||
|
ProfilePrint("RAVEN STANDARD LIBRARY - COMPUTATIONAL GEOMETRY MODULE");
|
||||||
|
ProfilePrint(" Region Profile Results ");
|
||||||
|
ProfilePrint("--------------------------------------------------------");
|
||||||
|
ProfilePrint("");
|
||||||
|
ProfilePrint("REGION SIZE (Bytes): (%d) (KiloBytes): (%5.3f)", sizeof(*this), ((float)(sizeof(*this))/1024.0f));
|
||||||
|
ProfilePrint("REGION COUNT: (%d) Regions (%d) Edges", mRegionCount, mEdges.size());
|
||||||
|
if (mRegionCount)
|
||||||
|
{
|
||||||
|
int RegionEdges = 0;
|
||||||
|
for (TEdges::iterator it=mEdges.begin(); it!=mEdges.end(); it++)
|
||||||
|
{
|
||||||
|
RegionEdges += (*it).size();
|
||||||
|
}
|
||||||
|
ProfilePrint("REGION COUNT: (%f) Ave Edges Size", (float)RegionEdges / (float)mRegionCount);
|
||||||
|
}
|
||||||
|
ProfilePrint("");
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,833 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD TEMPLATE LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Graph Triangulate
|
||||||
|
// -----------------
|
||||||
|
// Triangulation is the process of generating graph edges between "nearby" points.
|
||||||
|
//
|
||||||
|
// This class is designed to work with the ragl_graph template class, and requires that
|
||||||
|
// the same template parameters for that class be used here. The memory requirements
|
||||||
|
// of this class are not inconsequential, so it is best to allocate this class during
|
||||||
|
// a preprocess step and then throw it away.
|
||||||
|
//
|
||||||
|
// NOTE: This is a 2D triangulation! All Z Coordinates are ignored!
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// How Do I Triangulate A Raw Set Of Points?
|
||||||
|
// -----------------------------------------
|
||||||
|
// First of all, in order to construct a triangulation, you need to have your graph and
|
||||||
|
// pass it in to the constructor:
|
||||||
|
//
|
||||||
|
// typedef ragl::graph_triangulate<TNODE, MAXNODES, TEDGE, MAXEDGES> TTriangulation
|
||||||
|
// TTriangulation MyTriangulation(mMyGraph);
|
||||||
|
//
|
||||||
|
// Next, you are free to call any of the public functions in any order, but the best use
|
||||||
|
// is to call them in this order:
|
||||||
|
//
|
||||||
|
// MyTriangulation.insertion_hull();
|
||||||
|
// MyTriangulation.delaunay_edge_flip();
|
||||||
|
// MyTriangulation.alpha_shape(MyGraphUser, <MIN>, <MAX>);
|
||||||
|
//
|
||||||
|
// For documentation on the above functions, look at their def below. Also, the doc on
|
||||||
|
// the Graph User class is in graph_vs.h
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Finally, when you are ready, call the finish() function. That will populate your
|
||||||
|
// graph (which has not been altered in any way up until now). After calling finish()
|
||||||
|
// you can dump the triangulation class, as it has done it's job and all the data is
|
||||||
|
// now stored in the class.
|
||||||
|
//
|
||||||
|
// MyTriangulation.finish();
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// How Does It Work? (Overview)
|
||||||
|
// -----------------------------
|
||||||
|
// The details of how each step works are outlined below, however, here is the general
|
||||||
|
// idea:
|
||||||
|
//
|
||||||
|
// - Call insertion hull to generate a "rough and dirty" triangulation of the point set.
|
||||||
|
// The algorithm is relativly fast, and as a handy bi-product, generates the convex
|
||||||
|
// hull of the points. The resulting mesh is ugly though. You probably won't want
|
||||||
|
// to use it in the rough state. The basic idea of this algorithm is to iterativly
|
||||||
|
// add points which have been presorted along the x-axis into the triangulation. It
|
||||||
|
// is easy to do so, because you always know it will be on the right side of any edge
|
||||||
|
// it needs to connect with.
|
||||||
|
//
|
||||||
|
// - Now that you have a functional triangulation with edges and faces, there is fairly
|
||||||
|
// simple and fast algorithm to "clean it up" called EdgeFlipping. The idea is simple.
|
||||||
|
// Just scan through the edges, if you find one that is "bad", flip it! Continue until
|
||||||
|
// you find no "bad" edges. NOTE: This algorithm can lock up if any four points are
|
||||||
|
// colinear!
|
||||||
|
//
|
||||||
|
// - Finally, Alpha Shape is just a simple prune scan of the edges for anything that is
|
||||||
|
// too big or too small. This step is totally optional.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_GRAPH_TRIANGULATE_INC)
|
||||||
|
#define RATL_GRAPH_TRIANGULATE_INC
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Includes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if defined(RA_DEBUG_LINKING)
|
||||||
|
#pragma message("...including graph_triangulate.h")
|
||||||
|
#endif
|
||||||
|
#if !defined(RAGL_COMMON_INC)
|
||||||
|
#include "ragl_common.h"
|
||||||
|
#endif
|
||||||
|
#if !defined(RAGL_GRAPH_VS_INC)
|
||||||
|
#include "graph_vs.h"
|
||||||
|
#endif
|
||||||
|
#if !defined(RATL_LIST_VS_INC)
|
||||||
|
#include "..\Ratl\list_vs.h"
|
||||||
|
#endif
|
||||||
|
namespace ragl
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Graph Class
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
template <class TNODE, int MAXNODES, class TEDGE, int MAXEDGES, int MAXNODENEIGHBORS>
|
||||||
|
class graph_triangulate : public ratl::ratl_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Capacity Enum
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = MAXNODES,
|
||||||
|
MAXFACES = MAXEDGES*2,
|
||||||
|
NULLEDGE = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef graph_vs<TNODE, MAXNODES, TEDGE, MAXEDGES, MAXNODENEIGHBORS> TGraph;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
graph_triangulate(TGraph& Graph) : mGraph(Graph), mHull(), mHullIter(mHull.begin())
|
||||||
|
{
|
||||||
|
mLinks.init(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Clear Out All Temp Data So We Can Triangulate Again
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
mLinks.init(0);
|
||||||
|
mEdges.clear();
|
||||||
|
mFaces.clear();
|
||||||
|
|
||||||
|
mHull.clear();
|
||||||
|
mHullIter = mHull.begin();
|
||||||
|
|
||||||
|
mSortNodes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Insertion Hull
|
||||||
|
//
|
||||||
|
// This is a "quick and dirty" triangulation technique. It does not give you a very
|
||||||
|
// nice looking or terribly useful mesh, but it is a good place to start. Once
|
||||||
|
// you have an insertion hull triangulation, you can call delauny_edge_flip() to
|
||||||
|
// clean it up some.
|
||||||
|
//
|
||||||
|
// This algorithm's complexity isbounded in the worst case where all the points in
|
||||||
|
// the mesh are on the "hull", in which case it is O(n^2). However the number of
|
||||||
|
// points on the hull for most common point clouds is more likely to be log n.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void insertion_hull()
|
||||||
|
{
|
||||||
|
assert(mGraph.size_nodes()>3); // We Need More Than 3 Points To Triangulate
|
||||||
|
|
||||||
|
// STEP ONE: Sort all points along the x axis in increasing order
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// COMPLEXITY: O(n log n) Heapsort
|
||||||
|
|
||||||
|
sort_points();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// STEP TWO: Manually constructe the first face of the triangulation out of the 3 rightmost points
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// COMPLEXITY: O(1)
|
||||||
|
|
||||||
|
add_face(mSortNodes[0].mNodeHandle, mSortNodes[1].mNodeHandle, mSortNodes[2].mNodeHandle);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// STEP THREE: Add each remaining point to the hull, constructing new faces as we go
|
||||||
|
//-----------------------------------------------------------------------------------
|
||||||
|
// COMPLEXITY: O(n*c) (n = num nodes, c = num nodes on hull)
|
||||||
|
|
||||||
|
for (int i=3; i<mSortNodes.size(); i++)
|
||||||
|
{
|
||||||
|
insert_point(mSortNodes[i].mNodeHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Delaunay Edge Flipping
|
||||||
|
//
|
||||||
|
// This algorithm iterativly rotates edges which do not fit the "delaunay" criterion
|
||||||
|
// of all points on two adjacent faces containment within the circumscribed circles
|
||||||
|
// of the two faces. It solves the all pairs nearest neighbors problem.
|
||||||
|
//
|
||||||
|
// The routine is sadly bounded by n^2 complexity, but in practice perfromes very
|
||||||
|
// well - much better than n^2 (closer to n log n).
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void delaunay_edge_flip()
|
||||||
|
{
|
||||||
|
int CurFlipped;
|
||||||
|
int TotalFlipped = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
CurFlipped = flip();
|
||||||
|
TotalFlipped += CurFlipped;
|
||||||
|
}
|
||||||
|
while (CurFlipped!=0 && TotalFlipped<10000 /*Sanity Condition*/);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// This function attempts to prune out edges which connect across "floors" and
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void floor_shape(typename TGraph::user& user, float maxzdelta)
|
||||||
|
{
|
||||||
|
ratl::vector_vs<int, MAXEDGES> CullEdges;
|
||||||
|
int nEdge;
|
||||||
|
TEdges::iterator stop=mEdges.end();
|
||||||
|
for (TEdges::iterator it=mEdges.begin(); it!=mEdges.end(); it++)
|
||||||
|
{
|
||||||
|
if (!(*it).mOnHull)
|
||||||
|
{
|
||||||
|
edge& EdgeAt = *it;
|
||||||
|
face& FaceR = mFaces[EdgeAt.mRight];
|
||||||
|
face& FaceL = mFaces[EdgeAt.mLeft];
|
||||||
|
|
||||||
|
// int Edge = mEdges.index_to_handle(it.index());
|
||||||
|
int R = FaceR.opposing_node(EdgeAt.mA, EdgeAt.mB);
|
||||||
|
int L = FaceL.opposing_node(EdgeAt.mA, EdgeAt.mB);
|
||||||
|
int RInd = mGraph.node_index(R);
|
||||||
|
int LInd = mGraph.node_index(L);
|
||||||
|
|
||||||
|
TNODE& PtA = mGraph.get_node(EdgeAt.mA);
|
||||||
|
TNODE& PtB = mGraph.get_node(EdgeAt.mB);
|
||||||
|
TNODE& PtR = mGraph.get_node(R);
|
||||||
|
TNODE& PtL = mGraph.get_node(L);
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
(user.on_same_floor(PtR, PtL)) &&
|
||||||
|
(mLinks.get(RInd, LInd)==0) &&
|
||||||
|
(mLinks.get(LInd, RInd)==0) &&
|
||||||
|
(!user.on_same_floor(PtL, PtA) || !user.on_same_floor(PtL, PtB))
|
||||||
|
)
|
||||||
|
{
|
||||||
|
nEdge= mEdges.alloc();
|
||||||
|
|
||||||
|
mEdges[nEdge].mA = R;
|
||||||
|
mEdges[nEdge].mB = L;
|
||||||
|
mEdges[nEdge].mHullLoc = mHullIter;
|
||||||
|
mEdges[nEdge].mOnHull = true;
|
||||||
|
mEdges[nEdge].mFlips = 0;
|
||||||
|
mEdges[nEdge].mLeft = 0;
|
||||||
|
mEdges[nEdge].mRight = 0;
|
||||||
|
|
||||||
|
|
||||||
|
mLinks.get(RInd, LInd) = nEdge;
|
||||||
|
mLinks.get(LInd, RInd) = nEdge;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!user.on_same_floor(PtA, PtB))
|
||||||
|
{
|
||||||
|
mLinks.get(mGraph.node_index(EdgeAt.mA), mGraph.node_index(EdgeAt.mB)) = 0;
|
||||||
|
mLinks.get(mGraph.node_index(EdgeAt.mB), mGraph.node_index(EdgeAt.mA)) = 0;
|
||||||
|
|
||||||
|
CullEdges.push_back(it.index());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<CullEdges.size(); i++)
|
||||||
|
{
|
||||||
|
mEdges.free_index(CullEdges[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// This function is a simple routine to prune out any edges which are larger or
|
||||||
|
// smaller than the desired range (min, max).
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void alpha_shape(typename TGraph::user& user, float max, float min=0)
|
||||||
|
{
|
||||||
|
ratl::vector_vs<int, MAXEDGES> CullEdges;
|
||||||
|
float cost;
|
||||||
|
for (TEdges::iterator it=mEdges.begin(); it!=mEdges.end(); it++)
|
||||||
|
{
|
||||||
|
cost = user.cost(mGraph.get_node((*it).mA), mGraph.get_node((*it).mB));
|
||||||
|
if (cost<min || cost>max)
|
||||||
|
{
|
||||||
|
mLinks.get(mGraph.node_index((*it).mA), mGraph.node_index((*it).mB)) = 0;
|
||||||
|
mLinks.get(mGraph.node_index((*it).mB), mGraph.node_index((*it).mA)) = 0;
|
||||||
|
|
||||||
|
CullEdges.push_back(it.index());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<CullEdges.size(); i++)
|
||||||
|
{
|
||||||
|
mEdges.free_index(CullEdges[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Call this function when you are done with the triangulation and want to copy all
|
||||||
|
// the temp data into your graph.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void finish(typename TGraph::user& user)
|
||||||
|
{
|
||||||
|
mGraph.clear_edges();
|
||||||
|
TEDGE DefaultEdge;
|
||||||
|
for (TEdges::iterator it=mEdges.begin(); it!=mEdges.end(); it++)
|
||||||
|
{
|
||||||
|
user.setup_edge(DefaultEdge, (*it).mA, (*it).mB, (*it).mOnHull, mGraph.get_node((*it).mA), mGraph.get_node((*it).mB));
|
||||||
|
mGraph.connect_node(DefaultEdge, (*it).mA, (*it).mB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
typedef typename ratl::list_vs<int, MAXNODES> THull;
|
||||||
|
typedef typename ratl::list_vs<int, MAXNODES>::iterator THullIter;
|
||||||
|
typedef typename ratl::grid2_vs<int, MAXNODES, MAXNODES> TLinks;
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Local Edge Class
|
||||||
|
//
|
||||||
|
// RIGHT
|
||||||
|
// B<-<-<-<-<-<-A
|
||||||
|
// LEFT
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
class edge
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int mA;
|
||||||
|
int mB;
|
||||||
|
|
||||||
|
int mLeft;
|
||||||
|
int mRight;
|
||||||
|
int mFlips;
|
||||||
|
|
||||||
|
THullIter mHullLoc;
|
||||||
|
bool mOnHull;
|
||||||
|
|
||||||
|
void flip_face(int OldFace, int NewFace)
|
||||||
|
{
|
||||||
|
assert(mRight!=mLeft);
|
||||||
|
assert(mLeft!=NewFace && mRight!=NewFace);
|
||||||
|
if (mLeft==OldFace)
|
||||||
|
{
|
||||||
|
mLeft=NewFace;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(mRight==OldFace);
|
||||||
|
mRight = NewFace;
|
||||||
|
}
|
||||||
|
assert(mRight!=mLeft);
|
||||||
|
}
|
||||||
|
void verify(int PtA, int PtB, int Edge)
|
||||||
|
{
|
||||||
|
assert(PtA==mA || PtA==mB);
|
||||||
|
assert(PtB==mA || PtB==mB);
|
||||||
|
assert(mRight==Edge || mLeft==Edge);
|
||||||
|
assert(mRight!=mLeft);
|
||||||
|
assert(mA!=mB);
|
||||||
|
}
|
||||||
|
void verify(int PtA, int PtB, int PtC, int Edge)
|
||||||
|
{
|
||||||
|
assert((PtC==mA && (PtA==mB || PtB==mB)) || (PtC==mB && (PtA==mA || PtB==mA)));
|
||||||
|
|
||||||
|
assert(mRight==Edge || mLeft==Edge);
|
||||||
|
assert(mRight!=mLeft);
|
||||||
|
assert(mA!=mB);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Local Face Class
|
||||||
|
//
|
||||||
|
// _ C
|
||||||
|
// /| \
|
||||||
|
// LEFT/ \RIGHT
|
||||||
|
// / \
|
||||||
|
// B-<-<-<-<-A
|
||||||
|
// BOTTOM
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
class face
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int mA;
|
||||||
|
int mB;
|
||||||
|
int mC;
|
||||||
|
|
||||||
|
int mLeft;
|
||||||
|
int mRight;
|
||||||
|
int mBottom;
|
||||||
|
|
||||||
|
int mFlips;
|
||||||
|
|
||||||
|
int& opposing_node(int A, int B)
|
||||||
|
{
|
||||||
|
if (mA!=A && mA!=B)
|
||||||
|
{
|
||||||
|
return mA;
|
||||||
|
}
|
||||||
|
if (mB!=A && mB!=B)
|
||||||
|
{
|
||||||
|
return mB;
|
||||||
|
}
|
||||||
|
assert(mC!=A && mC!=B);
|
||||||
|
return mC;
|
||||||
|
}
|
||||||
|
|
||||||
|
int& relative_left(int edge)
|
||||||
|
{
|
||||||
|
if (edge==mLeft)
|
||||||
|
{
|
||||||
|
return mRight;
|
||||||
|
}
|
||||||
|
if (edge==mRight)
|
||||||
|
{
|
||||||
|
return mBottom;
|
||||||
|
}
|
||||||
|
assert(edge==mBottom); // If you hit this assert, then the edge is not in this face
|
||||||
|
return mLeft;
|
||||||
|
}
|
||||||
|
int& relative_right(int edge)
|
||||||
|
{
|
||||||
|
if (edge==mLeft)
|
||||||
|
{
|
||||||
|
return mBottom;
|
||||||
|
}
|
||||||
|
if (edge==mRight)
|
||||||
|
{
|
||||||
|
return mLeft;
|
||||||
|
}
|
||||||
|
assert(edge==mBottom); // If you hit this assert, then the edge is not in this face
|
||||||
|
return mRight;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Sort Node Class
|
||||||
|
//
|
||||||
|
// Used To Sort Nodes In Increasing X Order
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
class sort_node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool operator<(const sort_node& r) const
|
||||||
|
{
|
||||||
|
return ((*r.mNodePointer)[0] < (*mNodePointer)[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mNodeHandle;
|
||||||
|
TNODE* mNodePointer;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
typedef typename ratl::handle_pool_vs<edge, MAXEDGES> TEdges;
|
||||||
|
typedef typename ratl::handle_pool_vs<edge, MAXEDGES>::iterator TEdgesIter;
|
||||||
|
typedef typename ratl::handle_pool_vs<face, MAXFACES> TFaces;
|
||||||
|
typedef typename ratl::vector_vs<sort_node, MAXNODES> TSortNodes;
|
||||||
|
|
||||||
|
|
||||||
|
TGraph& mGraph; // A Reference To The Graph Points To Triangulate
|
||||||
|
|
||||||
|
TLinks mLinks;
|
||||||
|
TEdges mEdges;
|
||||||
|
TFaces mFaces;
|
||||||
|
|
||||||
|
THull mHull; // The Convex Hull
|
||||||
|
THullIter mHullIter;
|
||||||
|
|
||||||
|
TSortNodes mSortNodes; // Need To Presort Nodes On (x-Axis) For Insertion Hull
|
||||||
|
sort_node mSortNode;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copy All The Graph Nodes To Our Sort Node Class And Run Heap Sort
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void sort_points()
|
||||||
|
{
|
||||||
|
mSortNodes.clear();
|
||||||
|
for (TGraph::TNodes::iterator i=mGraph.nodes_begin(); i!=mGraph.nodes_end(); i++)
|
||||||
|
{
|
||||||
|
mSortNode.mNodeHandle = mGraph.node_handle(i);
|
||||||
|
mSortNode.mNodePointer = &(*i);
|
||||||
|
mSortNodes.push_back(mSortNode);
|
||||||
|
}
|
||||||
|
mSortNodes.sort();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Create A New Edge A->B, And Fix Up The Face
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int add_edge(int A, int B, int Face=0, bool OnHull=true)
|
||||||
|
{
|
||||||
|
assert(A!=B );
|
||||||
|
|
||||||
|
int nEdge = mLinks.get(mGraph.node_index(A), mGraph.node_index(B));
|
||||||
|
|
||||||
|
// Apparently This Edge Does Not Exist, So Make A New One
|
||||||
|
//--------------------------------------------------------
|
||||||
|
if (nEdge==0)
|
||||||
|
{
|
||||||
|
nEdge= mEdges.alloc();
|
||||||
|
|
||||||
|
mHull.insert_after(mHullIter, nEdge);
|
||||||
|
assert(mHullIter!=mHull.end());
|
||||||
|
|
||||||
|
mEdges[nEdge].mA = A;
|
||||||
|
mEdges[nEdge].mB = B;
|
||||||
|
mEdges[nEdge].mHullLoc = mHullIter;
|
||||||
|
mEdges[nEdge].mOnHull = true;
|
||||||
|
mEdges[nEdge].mFlips = 0;
|
||||||
|
mEdges[nEdge].mLeft = 0;
|
||||||
|
mEdges[nEdge].mRight = 0;
|
||||||
|
|
||||||
|
|
||||||
|
mLinks.get(mGraph.node_index(A), mGraph.node_index(B)) = nEdge;
|
||||||
|
mLinks.get(mGraph.node_index(B), mGraph.node_index(A)) = nEdge;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If This Edge DOES Already Exist, Then We Need To Remove It From The Hull
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
else if (mEdges[nEdge].mOnHull)
|
||||||
|
{
|
||||||
|
assert(mEdges[nEdge].mHullLoc!=mHull.end());
|
||||||
|
|
||||||
|
if (mHullIter==mEdges[nEdge].mHullLoc)
|
||||||
|
{
|
||||||
|
mHull.erase(mHullIter); // Make Sure To Fix Up The Hull Iter If That Is What We Are Removing
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mHull.erase(mEdges[nEdge].mHullLoc);
|
||||||
|
}
|
||||||
|
mEdges[nEdge].mOnHull = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If The Edge Was Made With The Same Orientation Currently Asked For (A->B), Then Mark Face As Right
|
||||||
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
if (mEdges[nEdge].mA==A)
|
||||||
|
{
|
||||||
|
mEdges[nEdge].mRight = Face;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mEdges[nEdge].mLeft = Face;
|
||||||
|
}
|
||||||
|
return nEdge;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Create A New Face A->B->C, And Fix Up The Edges & Neighboring Faces
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int add_face(int A, int B, int C)
|
||||||
|
{
|
||||||
|
int Temp = 0;
|
||||||
|
int nFace = mFaces.alloc();
|
||||||
|
|
||||||
|
// First, Make Sure Node A.x Is Greater Than B and C. If Not, Swap With B or C
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
if (mGraph.get_node(B)[0]>mGraph.get_node(A)[0])
|
||||||
|
{
|
||||||
|
Temp = A;
|
||||||
|
A = B;
|
||||||
|
B = Temp;
|
||||||
|
}
|
||||||
|
if (mGraph.get_node(C)[0]>mGraph.get_node(A)[0])
|
||||||
|
{
|
||||||
|
Temp = A;
|
||||||
|
A = C;
|
||||||
|
C = Temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Similarly, Make Sure Node B.y Is Greater Than Node C.y
|
||||||
|
//--------------------------------------------------------
|
||||||
|
if (mGraph.get_node(C).LRTest(mGraph.get_node(A), mGraph.get_node(B))==Side_Left)
|
||||||
|
{
|
||||||
|
Temp = C;
|
||||||
|
C = B;
|
||||||
|
B = Temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEBUG ASSERTS
|
||||||
|
//====================================================================================
|
||||||
|
// IF YOU HIT THESE ASSERTS, CHANCES ARE THAT YOU ARE TRYING TO TRIANGULATE OVER A SET
|
||||||
|
// WITH MORE THAN 2 COLINEAR POINTS ON THE SAME FACE. INSERT HULL WILL FAIL IN THIS
|
||||||
|
// FACE. INSERT HULL WILL FAIL IN THIS SITUATION
|
||||||
|
|
||||||
|
assert(mGraph.get_node(C).LRTest(mGraph.get_node(A), mGraph.get_node(B))==Side_Right);
|
||||||
|
assert(mGraph.get_node(A).LRTest(mGraph.get_node(B), mGraph.get_node(C))==Side_Right);
|
||||||
|
assert(mGraph.get_node(B).LRTest(mGraph.get_node(C), mGraph.get_node(A))==Side_Right);
|
||||||
|
//====================================================================================
|
||||||
|
|
||||||
|
mFaces[nFace].mA = A;
|
||||||
|
mFaces[nFace].mB = B;
|
||||||
|
mFaces[nFace].mC = C;
|
||||||
|
|
||||||
|
mFaces[nFace].mRight = add_edge(C, A, nFace);
|
||||||
|
mFaces[nFace].mBottom = add_edge(A, B, nFace);
|
||||||
|
mFaces[nFace].mLeft = add_edge(B, C, nFace);
|
||||||
|
|
||||||
|
mFaces[nFace].mFlips = 0;
|
||||||
|
|
||||||
|
return nFace;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Insertion Hull Triangulation
|
||||||
|
//
|
||||||
|
// This algorithm works by scanning the outer convex hull of the set of points that
|
||||||
|
// have already been triangulated. When encountering a hull edge which evaluates
|
||||||
|
// LEFT in a left right test (remember, the triangles always have clockwise orientation)
|
||||||
|
// it adds a face to the triangulation including the edge as one side of the triangle
|
||||||
|
// and two new edges to the node handle. It's very important to traverse the convex
|
||||||
|
// hull in counter clockwise order (backwards).
|
||||||
|
//
|
||||||
|
// In the example below, we assume the convex hull starts at the edge (CA). (nodeHandle) is
|
||||||
|
// RIGHT of (C->A), so it skips that edge and moves on to (D->C). (nodeHandle) is in fact
|
||||||
|
// LEFT of (D->C), so we would add a new face that would go (D->nodeHandle->C), and we remove
|
||||||
|
// (D->C) from the hull.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// (C)-------------(A)
|
||||||
|
// / \ __/ \
|
||||||
|
// (nodeHandle) / \ __/ \
|
||||||
|
// / \ / \
|
||||||
|
// (D)----____(B)_ \
|
||||||
|
// \ | \ __
|
||||||
|
// \ | \__
|
||||||
|
// \ | \
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void insert_point(int nodeHandle)
|
||||||
|
{
|
||||||
|
// Iterate Over The Existing Convex Hull
|
||||||
|
//---------------------------------------
|
||||||
|
for (mHullIter = mHull.begin(); mHullIter!=mHull.end(); mHullIter++)
|
||||||
|
{
|
||||||
|
edge& curEdge = mEdges[*mHullIter];
|
||||||
|
|
||||||
|
// Can This Edge "See" The node Handle We Have Passed In?
|
||||||
|
//---------------------------------------------------------
|
||||||
|
if ( mGraph.get_node(nodeHandle).LRTest(mGraph.get_node(curEdge.mA), mGraph.get_node(curEdge.mB))==Side_Left )
|
||||||
|
{
|
||||||
|
// Then Add The Face And Remove This Edge From The Hull
|
||||||
|
//------------------------------------------------------
|
||||||
|
add_face(curEdge.mA, curEdge.mB, nodeHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Edge Flip Function
|
||||||
|
//
|
||||||
|
// This function scans the edge list for any edge that is "bad" (defined as not
|
||||||
|
// fitting within the circumscribed circle of either adjoining face). When it
|
||||||
|
// encounters one, it "flips" the edge in question and fixes up the adjoining faces
|
||||||
|
// which were altered.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// The Flip Edge (PtA->PtB):
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// BEFORE AFTER
|
||||||
|
//
|
||||||
|
// (PtR) (PtA)
|
||||||
|
// / \ / | \
|
||||||
|
// / \ / | \
|
||||||
|
// / (FaceR) \ / V \
|
||||||
|
// / \ / | \
|
||||||
|
// (PtB)-<---------<-(PtA) (PtR) | (PtL)
|
||||||
|
// \ / \ | /
|
||||||
|
// \ (FaceL) / \ V /
|
||||||
|
// \ / \ | /
|
||||||
|
// \ / \ | /
|
||||||
|
// (PtL) (PtB)
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int flip()
|
||||||
|
{
|
||||||
|
int Flipped = 0;
|
||||||
|
|
||||||
|
int EdgeHandle;
|
||||||
|
int PtR, PtL, PtA, PtB;
|
||||||
|
int EdgeRL, EdgeRR, EdgeLL, EdgeLR;
|
||||||
|
|
||||||
|
|
||||||
|
// Iterate Through All The Edges Looking For Potential NON-Delauney Edges
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
for (TEdgesIter CurEdge=mEdges.begin(); CurEdge!=mEdges.end(); CurEdge++)
|
||||||
|
{
|
||||||
|
// If It Is On The Hull, We Don't Even Need To Look At It
|
||||||
|
//--------------------------------------------------------
|
||||||
|
if (!(*CurEdge).mOnHull)
|
||||||
|
{
|
||||||
|
edge& EdgeAt = *CurEdge;
|
||||||
|
face& FaceR = mFaces[EdgeAt.mRight];
|
||||||
|
face& FaceL = mFaces[EdgeAt.mLeft];
|
||||||
|
|
||||||
|
EdgeHandle = mEdges.index_to_handle(CurEdge.index());
|
||||||
|
PtA = EdgeAt.mA;
|
||||||
|
PtB = EdgeAt.mB;
|
||||||
|
PtR = FaceR.opposing_node(PtA, PtB);
|
||||||
|
PtL = FaceL.opposing_node(PtA, PtB);
|
||||||
|
|
||||||
|
assert(EdgeAt.mRight!=EdgeAt.mLeft);
|
||||||
|
assert(PtA!=PtB);
|
||||||
|
assert(PtR!=PtL);
|
||||||
|
assert(PtA!=PtR && PtA!=PtL);
|
||||||
|
assert(PtB!=PtR && PtB!=PtL);
|
||||||
|
|
||||||
|
// Is This Edge Invalid For Delaunay?
|
||||||
|
//-------------------------------------
|
||||||
|
if (!mGraph.get_node(PtB).InCircle(mGraph.get_node(PtR), mGraph.get_node(PtL), mGraph.get_node(PtA)) &&
|
||||||
|
!mGraph.get_node(PtA).InCircle(mGraph.get_node(PtR), mGraph.get_node(PtB), mGraph.get_node(PtL))
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Change The Link: Remove The Old, Add The New
|
||||||
|
//----------------------------------------------
|
||||||
|
mLinks.get(mGraph.node_index(PtA), mGraph.node_index(PtB)) = 0;
|
||||||
|
mLinks.get(mGraph.node_index(PtB), mGraph.node_index(PtA)) = 0;
|
||||||
|
|
||||||
|
mLinks.get(mGraph.node_index(PtR), mGraph.node_index(PtL)) = EdgeHandle;
|
||||||
|
mLinks.get(mGraph.node_index(PtL), mGraph.node_index(PtR)) = EdgeHandle;
|
||||||
|
|
||||||
|
|
||||||
|
Flipped++;
|
||||||
|
EdgeAt.mFlips++;
|
||||||
|
FaceL.mFlips++;
|
||||||
|
FaceR.mFlips++;
|
||||||
|
|
||||||
|
// Flip The Edge We Found
|
||||||
|
//------------------------
|
||||||
|
EdgeAt.mA = PtR;
|
||||||
|
EdgeAt.mB = PtL;
|
||||||
|
|
||||||
|
// Calculate Relatave Edges And Points Assuming (EdgeAt) Were mBottom For The Two Faces
|
||||||
|
//--------------------------------------------------------------------------------------
|
||||||
|
EdgeRL = FaceR.relative_left(EdgeHandle);
|
||||||
|
EdgeRR = FaceR.relative_right(EdgeHandle);
|
||||||
|
|
||||||
|
EdgeLL = FaceL.relative_left(EdgeHandle);
|
||||||
|
EdgeLR = FaceL.relative_right(EdgeHandle);
|
||||||
|
|
||||||
|
|
||||||
|
// Fix Edges Which Had Been Rotated To New Faces
|
||||||
|
//-----------------------------------------------
|
||||||
|
mEdges[EdgeLR].flip_face(EdgeAt.mLeft, EdgeAt.mRight);
|
||||||
|
mEdges[EdgeRR].flip_face(EdgeAt.mRight, EdgeAt.mLeft);
|
||||||
|
|
||||||
|
// Rotate The Edges Clockwise
|
||||||
|
//----------------------------
|
||||||
|
FaceR.mLeft = EdgeLR;
|
||||||
|
FaceR.mRight = EdgeRL;
|
||||||
|
FaceR.mBottom = EdgeHandle;
|
||||||
|
|
||||||
|
FaceL.mLeft = EdgeRR;
|
||||||
|
FaceL.mRight = EdgeLL;
|
||||||
|
FaceL.mBottom = EdgeHandle;
|
||||||
|
|
||||||
|
FaceR.mA = PtR;
|
||||||
|
FaceR.mB = PtL;
|
||||||
|
FaceR.mC = PtB;
|
||||||
|
|
||||||
|
FaceL.mA = PtR;
|
||||||
|
FaceL.mB = PtL;
|
||||||
|
FaceL.mC = PtA;
|
||||||
|
|
||||||
|
|
||||||
|
// DEBUG VERIFICATION
|
||||||
|
//========================================================================
|
||||||
|
#ifdef _DEBUG
|
||||||
|
mEdges[FaceR.mLeft ].verify(FaceR.mA, FaceR.mB, FaceR.mC, EdgeAt.mRight);
|
||||||
|
mEdges[FaceR.mRight ].verify(FaceR.mA, FaceR.mB, FaceR.mC, EdgeAt.mRight);
|
||||||
|
mEdges[FaceR.mBottom].verify(FaceR.mA, FaceR.mB, EdgeAt.mRight);
|
||||||
|
|
||||||
|
mEdges[FaceL.mLeft ].verify(FaceL.mA, FaceL.mB, FaceL.mC, EdgeAt.mLeft);
|
||||||
|
mEdges[FaceL.mRight ].verify(FaceL.mA, FaceL.mB, FaceL.mC, EdgeAt.mLeft);
|
||||||
|
mEdges[FaceL.mBottom].verify(FaceL.mA, FaceL.mB, EdgeAt.mLeft);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assert(EdgeAt.mRight!=EdgeAt.mLeft);
|
||||||
|
assert(PtA!=PtB);
|
||||||
|
assert(PtR!=PtL);
|
||||||
|
//========================================================================
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Flipped;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,458 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD TEMPLATE LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// KD Tree
|
||||||
|
// -------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// NOTES:
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_KDTREE_VS_INC)
|
||||||
|
#define RATL_KDTREE_VS_INC
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Includes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if defined(RA_DEBUG_LINKING)
|
||||||
|
#pragma message("...including kdtree_vs.h")
|
||||||
|
#endif
|
||||||
|
#if !defined(RAGL_COMMON_INC)
|
||||||
|
#include "ragl_common.h"
|
||||||
|
#endif
|
||||||
|
namespace ragl
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The List Class
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
template <class T, int DIMENSION, int SIZE>
|
||||||
|
class kdtree_vs : public ratl::ratl_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Capacity Enum
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = SIZE,
|
||||||
|
NULL_NODE = SIZE+2, // Invalid Node ID
|
||||||
|
TARG_NODE = SIZE+3 // Used To Mark Nodes Add Location
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
kdtree_vs() : mRoot(NULL_NODE)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// How Many Objects Are In This Tree
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int size() const
|
||||||
|
{
|
||||||
|
return (mPool.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Are There Any Objects In This Tree?
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return (mRoot==NULL_NODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Is This List Filled?
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool full() const
|
||||||
|
{
|
||||||
|
return (mPool.full());
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Clear All Elements
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
mRoot = NULL_NODE;
|
||||||
|
mPool.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Add A New Element To The Tree
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void add(const T& data)
|
||||||
|
{
|
||||||
|
// CREATE: New
|
||||||
|
//--------------------------------------------
|
||||||
|
int nNew = mPool.alloc();
|
||||||
|
mPool[nNew].mData = data;
|
||||||
|
mPool[nNew].mLeft = NULL_NODE;
|
||||||
|
mPool[nNew].mRight = NULL_NODE;
|
||||||
|
|
||||||
|
// LINK: (nNew)->(Parent)
|
||||||
|
//--------------------------------------------
|
||||||
|
if (mRoot==NULL_NODE)
|
||||||
|
{
|
||||||
|
mRoot = nNew;
|
||||||
|
mPool[nNew].mParent = NULL_NODE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LINK: (nNew)->(Parent)
|
||||||
|
//--------------------------------------------
|
||||||
|
mPool[nNew].mParent = find_index(data, mRoot, 0, true, true);
|
||||||
|
|
||||||
|
|
||||||
|
// LINK: (Parent)->(nNew)
|
||||||
|
//--------------------------------------------
|
||||||
|
if (mPool[mPool[nNew].mParent].mLeft==TARG_NODE)
|
||||||
|
{
|
||||||
|
mPool[mPool[nNew].mParent].mLeft = nNew;
|
||||||
|
}
|
||||||
|
else if (mPool[mPool[nNew].mParent].mRight==TARG_NODE)
|
||||||
|
{
|
||||||
|
mPool[mPool[nNew].mParent].mRight = nNew;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hey! It Didn't Mark Any Targets, Which Means We Found An Exact match To This Data
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mPool.free(nNew);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Does (data) Exist In The Tree?
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool find(const T& data)
|
||||||
|
{
|
||||||
|
assert(mRoot!=NULL_NODE); // If You Hit This Assert, You Are Asking For Data On An Empty Tree
|
||||||
|
|
||||||
|
int node = find_index(data, mRoot, 0, true, true);
|
||||||
|
|
||||||
|
// Exact Find, Or Found Root?
|
||||||
|
//----------------------------
|
||||||
|
if (mPool[node].mData==data || mPool[node].mParent==NULL_NODE)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
class range_query
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
range_query() {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
ratl::vector_vs<T, SIZE> mReported;
|
||||||
|
T mMins;
|
||||||
|
T mMaxs;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void find(range_query& query)
|
||||||
|
{
|
||||||
|
if (mRoot!=NULL_NODE)
|
||||||
|
{
|
||||||
|
query.mReported.clear();
|
||||||
|
tree_search(query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
class node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int mParent;
|
||||||
|
int mLeft;
|
||||||
|
int mRight;
|
||||||
|
|
||||||
|
T mData;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
class range_bounds
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int mMins[DIMENSION];
|
||||||
|
int mMaxs[DIMENSION];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// This Private Function Of The Class Does A Standard Binary Tree Search
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int find_index(const T& data, int curNode, int curDimension, bool returnClosest, bool markTarget)
|
||||||
|
{
|
||||||
|
// Did We Just Go Off The End Of The Tree Or Find The Data We Were Looking For?
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
if (curNode==NULL_NODE || mPool[curNode].mData==data)
|
||||||
|
{
|
||||||
|
return curNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Calculate The Next Dimension For Searching
|
||||||
|
//--------------------------------------------
|
||||||
|
int nextDimension = curDimension+1;
|
||||||
|
if (nextDimension>=DIMENSION)
|
||||||
|
{
|
||||||
|
nextDimension = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Search Recursivly Down The Tree Either Left (For Data > Current Node), Or Right
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
int findRecursive;
|
||||||
|
bool goLeft = (data[curDimension] < mPool[curNode].mData[curDimension]);
|
||||||
|
if (goLeft)
|
||||||
|
{
|
||||||
|
findRecursive = find_index(data, mPool[curNode].mLeft, nextDimension, returnClosest, markTarget);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
findRecursive = find_index(data, mPool[curNode].mRight, nextDimension, returnClosest, markTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success!
|
||||||
|
//----------
|
||||||
|
if (findRecursive!=NULL_NODE)
|
||||||
|
{
|
||||||
|
return findRecursive;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If We Want To Return The CLOSEST Node, And We Went Off The End, Then Return This One
|
||||||
|
//--------------------------------------------------------------------------------------
|
||||||
|
if (returnClosest)
|
||||||
|
{
|
||||||
|
// If We Are Asked To Mark The Target, We Mark (TARG_NODE) At Either mLeft or mRight,
|
||||||
|
// Depending On Where The Node Should Have Been
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
if (markTarget)
|
||||||
|
{
|
||||||
|
if (goLeft)
|
||||||
|
{
|
||||||
|
mPool[curNode].mLeft = TARG_NODE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mPool[curNode].mRight = TARG_NODE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go Ahead And Return This Node, It's The One We Would Have Put As The Child
|
||||||
|
return curNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return The Results Of The Recursive Call
|
||||||
|
//------------------------------------------
|
||||||
|
return NULL_NODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// This function just sets up the range bounds and starts the recursive tree search
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void tree_search(range_query& query)
|
||||||
|
{
|
||||||
|
range_bounds bounds;
|
||||||
|
for (int i=0; i<DIMENSION; i++)
|
||||||
|
{
|
||||||
|
bounds.mMins[i] = 0;
|
||||||
|
bounds.mMaxs[i] = 0;
|
||||||
|
}
|
||||||
|
tree_search(query, mRoot, 0, bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void tree_search(range_query& query, int curNode, int curDimension, range_bounds bounds)
|
||||||
|
{
|
||||||
|
assert(curNode<SIZE);
|
||||||
|
|
||||||
|
// Is This Node In The Query Range? If So, Report It
|
||||||
|
//----------------------------------------------------
|
||||||
|
if (curNode!=NULL_NODE && tree_search_node_in_range(query, mPool[curNode]))
|
||||||
|
{
|
||||||
|
query.mReported.push_back(mPool[curNode].mData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If This Is A Leaf Node, We're Done Here
|
||||||
|
//-----------------------------------------
|
||||||
|
if (curNode==NULL_NODE || (mPool[curNode].mLeft==NULL_NODE && mPool[curNode].mRight==NULL_NODE))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate The Next Dimension For Searching
|
||||||
|
//--------------------------------------------
|
||||||
|
int nextDimension = curDimension+1;
|
||||||
|
if (nextDimension>=DIMENSION)
|
||||||
|
{
|
||||||
|
nextDimension = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Test To See If Our Subtree Is In Range
|
||||||
|
//----------------------------------------
|
||||||
|
ESide Side = tree_search_bounds_in_range(query, bounds);
|
||||||
|
|
||||||
|
// If The Bounds Are Contained Entirely Within The Query Range, We Report The Sub Tree
|
||||||
|
//-------------------------------------------------------------------------------------
|
||||||
|
if (Side==Side_AllIn)
|
||||||
|
{
|
||||||
|
tree_search_report_sub_tree(query, curNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, If Our Bounds Intersect The Query Range, We Need To Look Further
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
else if (Side==Side_In)
|
||||||
|
{
|
||||||
|
// Test The Left Child
|
||||||
|
//---------------------
|
||||||
|
if (mPool[curNode].mLeft!=NULL_NODE)
|
||||||
|
{
|
||||||
|
int OldMaxs = bounds.mMaxs[curDimension];
|
||||||
|
if ( !bounds.mMins[curDimension] || ((mPool[curNode].mData[curDimension]) < (mPool[bounds.mMins[curDimension]].mData[curDimension])) )
|
||||||
|
{
|
||||||
|
bounds.mMins[curDimension] = curNode;
|
||||||
|
}
|
||||||
|
tree_search(query, mPool[curNode].mLeft, nextDimension, bounds);
|
||||||
|
bounds.mMaxs[curDimension] = OldMaxs; // Restore Old Maxs For The Right Child Search
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test The Right Child
|
||||||
|
//----------------------
|
||||||
|
if (mPool[curNode].mRight!=NULL_NODE)
|
||||||
|
{
|
||||||
|
if ( !bounds.mMaxs[curDimension] || ((mPool[bounds.mMaxs[curDimension]].mData[curDimension]) < (mPool[curNode].mData[curDimension])) )
|
||||||
|
{
|
||||||
|
bounds.mMaxs[curDimension] = curNode;
|
||||||
|
}
|
||||||
|
tree_search(query, mPool[curNode].mRight, nextDimension, bounds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// This Function Returns True If The Node Is Within The Query Range
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool tree_search_node_in_range(range_query& query, node& n)
|
||||||
|
{
|
||||||
|
for (int dim=0; dim<DIMENSION; dim++)
|
||||||
|
{
|
||||||
|
if (n.mData[dim]<query.mMins[dim] || query.mMaxs[dim]<n.mData[dim])
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
ESide tree_search_bounds_in_range(range_query& query, range_bounds& bounds)
|
||||||
|
{
|
||||||
|
ESide S = Side_AllIn;
|
||||||
|
for (int dim=0; dim<DIMENSION; dim++)
|
||||||
|
{
|
||||||
|
// If Any Of Our Dimensions Are Undefined Right Now, Always Return INTERSECT
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
if (!bounds.mMaxs[dim] || !bounds.mMins[dim])
|
||||||
|
{
|
||||||
|
return Side_In;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check To See If They Intersect At All?
|
||||||
|
//----------------------------------------
|
||||||
|
if ((mPool[bounds.mMaxs[dim]].mData[dim]<query.mMins[dim]) ||
|
||||||
|
(query.mMaxs[dim]<mPool[bounds.mMins[dim]].mData[dim]))
|
||||||
|
{
|
||||||
|
return Side_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check To See If It Is Contained
|
||||||
|
//---------------------------------
|
||||||
|
if ((mPool[bounds.mMins[dim]].mData[dim]<query.mMins[dim]) ||
|
||||||
|
(query.mMaxs[dim]<mPool[bounds.mMaxs[dim]].mData[dim]))
|
||||||
|
{
|
||||||
|
S = Side_In;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return S;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Add The Cur Node And All Childeren Of The Cur Node
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void tree_search_report_sub_tree(range_query& query, int curNode)
|
||||||
|
{
|
||||||
|
assert(curNode<SIZE);
|
||||||
|
|
||||||
|
if (mPool[curNode].mLeft!=NULL_NODE)
|
||||||
|
{
|
||||||
|
query.mReported.push_back(mPool[mPool[curNode].mLeft].mData);
|
||||||
|
tree_search_report_sub_tree(query, mPool[curNode].mRight);
|
||||||
|
}
|
||||||
|
if (mPool[curNode].mRight!=NULL_NODE)
|
||||||
|
{
|
||||||
|
query.mReported.push_back(mPool[mPool[curNode].mRight].mData);
|
||||||
|
tree_search_report_sub_tree(query, mPool[curNode].mRight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Data
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
private:
|
||||||
|
ratl::handle_pool_vs<node, SIZE> mPool; // The Allocation Data Pool
|
||||||
|
int mRoot; // The Beginning Of The Tree
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,232 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD TEMPLATE LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Common
|
||||||
|
// ------
|
||||||
|
// The raven libraries contain a number of common defines, enums, and typedefs which
|
||||||
|
// need to be accessed by all templates. Each of these is included here.
|
||||||
|
//
|
||||||
|
// Also included is a safeguarded assert file for all the asserts in RTL.
|
||||||
|
//
|
||||||
|
// This file is included in EVERY TEMPLATE, so it should be very light in order to
|
||||||
|
// reduce compile times.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Format
|
||||||
|
// ------
|
||||||
|
// In order to simplify code and provide readability, the template library has some
|
||||||
|
// standard formats. Any new templates or functions should adhere to these formats:
|
||||||
|
//
|
||||||
|
// - All memory is statically allocated, usually by parameter SIZE
|
||||||
|
// - All classes provide an enum which defines constant variables, including CAPACITY
|
||||||
|
// - All classes which moniter the number of items allocated provide the following functions:
|
||||||
|
// size() - the number of objects
|
||||||
|
// empty() - does the container have zero objects
|
||||||
|
// full() - does the container have any room left for more objects
|
||||||
|
// clear() - remove all objects
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// - Functions are defined in the following order:
|
||||||
|
// Capacity
|
||||||
|
// Constructors (copy, from string, etc...)
|
||||||
|
// Range (size(), empty(), full(), clear(), etc...)
|
||||||
|
// Access (operator[], front(), back(), etc...)
|
||||||
|
// Modification (add(), remove(), push(), pop(), etc...)
|
||||||
|
// Iteration (begin(), end(), insert(), erase(), find(), etc...)
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// NOTES:
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RAGL_COMMON_INC)
|
||||||
|
#define RAGL_COMMON_INC
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Includes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if defined(RA_DEBUG_LINKING)
|
||||||
|
#pragma message("...including ragl_common.h")
|
||||||
|
#endif
|
||||||
|
#if !defined(RAGL_ASSERT_INC)
|
||||||
|
#define RAGL_ASSERT_INC
|
||||||
|
#include <assert.h>
|
||||||
|
#endif
|
||||||
|
#if !defined(FINAL_BUILD)
|
||||||
|
#if !defined(RAGL_PROFILE_INC) && !defined(_XBOX)
|
||||||
|
#define RAGL_PROFILE_INC
|
||||||
|
#include "Windows.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if !defined(RAVL_VEC_INC)
|
||||||
|
#include "..\Ravl\CVec.h"
|
||||||
|
#endif
|
||||||
|
#if !defined(RATL_COMMON_INC)
|
||||||
|
#include "..\Ratl\ratl_common.h"
|
||||||
|
#endif
|
||||||
|
namespace ragl
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Enums
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Typedefs
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Defines
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Graph Node Class
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
class CNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CNode() {}
|
||||||
|
CNode(const CVec3& Pt) : mPoint(Pt) {}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Access Operator (For Triangulation)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
float operator[](int dimension)
|
||||||
|
{
|
||||||
|
return mPoint[dimension];
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Equality Operator (For KDTree)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool operator==(const CNode& t) const
|
||||||
|
{
|
||||||
|
return (t.mPoint==mPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Left Right Test (For Triangulation)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
virtual ESide LRTest(const CNode& A, const CNode& B) const
|
||||||
|
{
|
||||||
|
return (mPoint.LRTest(A.mPoint, B.mPoint));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Point In Circle (For Triangulation)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
virtual bool InCircle(const CNode& A, const CNode& B, const CNode& C) const
|
||||||
|
{
|
||||||
|
return (mPoint.PtInCircle(A.mPoint, B.mPoint, C.mPoint));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
CVec3 mPoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Graph Edge Class
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
class CEdge
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int mNodeA;
|
||||||
|
int mNodeB;
|
||||||
|
bool mOnHull;
|
||||||
|
float mDistance;
|
||||||
|
bool mCanBeInval;
|
||||||
|
bool mValid;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Geometric Reference Class
|
||||||
|
//
|
||||||
|
// This adds one additional function to the common ratl_ref class to allow access for
|
||||||
|
// various dimensions. It is used in both Triangulation and KDTree
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
template <class TDATA, class TDATAREF>
|
||||||
|
class ragl_ref
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructors
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
ragl_ref() {}
|
||||||
|
ragl_ref(const ragl_ref & r) {mDataRef = (TDATAREF)(r.mDataRef);}
|
||||||
|
ragl_ref(const TDATA & r) {mDataRef = (TDATAREF)(& r);}
|
||||||
|
ragl_ref(const TDATAREF r) {mDataRef = (TDATAREF)(r);}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Assignment Operators
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void operator=(const ragl_ref & r) {mDataRef = (TDATAREF)(r.mDataRef);}
|
||||||
|
void operator=(const TDATA & r) {mDataRef = (TDATAREF)(& r);}
|
||||||
|
void operator=(const TDATAREF r) {mDataRef = (TDATAREF)(r);}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Access Operator (For Triangulation)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
float operator[](int dimension) const {return (*mDataRef)[dimension];}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Dereference Operator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TDATA & operator*() {return (*mDataRef);}
|
||||||
|
const TDATA & operator*() const {return (*mDataRef);}
|
||||||
|
|
||||||
|
TDATAREF handle() const {return mDataRef;}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Equality / Inequality Operators
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool operator== (const ragl_ref& t) const {return (*mDataRef)==(*(t.mDataRef));}
|
||||||
|
bool operator!= (const ragl_ref& t) const {return (*mDataRef)!=(*(t.mDataRef));}
|
||||||
|
bool operator< (const ragl_ref& t) const {return (*mDataRef)< (*(t.mDataRef));}
|
||||||
|
bool operator> (const ragl_ref& t) const {return (*mDataRef)> (*(t.mDataRef));}
|
||||||
|
bool operator<= (const ragl_ref& t) const {return (*mDataRef)<=(*(t.mDataRef));}
|
||||||
|
bool operator>= (const ragl_ref& t) const {return (*mDataRef)>=(*(t.mDataRef));}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Equality / Inequality Operators
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool operator== (const TDATA& t) const {return (*mDataRef)==t;}
|
||||||
|
bool operator!= (const TDATA& t) const {return (*mDataRef)!=t;}
|
||||||
|
bool operator< (const TDATA& t) const {return (*mDataRef)< t;}
|
||||||
|
bool operator> (const TDATA& t) const {return (*mDataRef)> t;}
|
||||||
|
bool operator<= (const TDATA& t) const {return (*mDataRef)<=t;}
|
||||||
|
bool operator>= (const TDATA& t) const {return (*mDataRef)>=t;}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Data Reference
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
private:
|
||||||
|
TDATAREF mDataRef;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
Binary file not shown.
|
@ -0,0 +1,73 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD TEMPLATE LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Array
|
||||||
|
// -----
|
||||||
|
// This array class is little more than an assert loaded wrapper around a standard
|
||||||
|
// array.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// NOTES:
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_ARRAY_VS)
|
||||||
|
#define RATL_ARRAY_VS
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Includes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_COMMON_INC)
|
||||||
|
#include "ratl_common.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace ratl
|
||||||
|
{
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY>
|
||||||
|
class array_vs : public array_base<storage::value_semantics<T,ARG_CAPACITY> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::value_semantics<T,ARG_CAPACITY> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY
|
||||||
|
};
|
||||||
|
array_vs() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY>
|
||||||
|
class array_os : public array_base<storage::object_semantics<T,ARG_CAPACITY> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::object_semantics<T,ARG_CAPACITY> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY
|
||||||
|
};
|
||||||
|
array_os() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY, int ARG_MAX_CLASS_SIZE>
|
||||||
|
class array_is : public array_base<storage::virtual_semantics<T,ARG_CAPACITY,ARG_MAX_CLASS_SIZE> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::virtual_semantics<T,ARG_CAPACITY,ARG_MAX_CLASS_SIZE> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY,
|
||||||
|
MAX_CLASS_SIZE = ARG_MAX_CLASS_SIZE
|
||||||
|
};
|
||||||
|
array_is() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,218 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD TEMPLATE LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Bit Field
|
||||||
|
// ---------
|
||||||
|
// The bits class is a bit field of any length which supports all the
|
||||||
|
// standard bitwize operations in addition to some operators for adding & removing
|
||||||
|
// individual bits by their integer indicies and a string conversion method.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// NOTES:
|
||||||
|
// - The SIZE template variable determines how many BITS are available in this template,
|
||||||
|
// not how much memory (number of ints) were used to store it.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_BITS_INC)
|
||||||
|
#define RATL_BITS_INC
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Includes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_COMMON_INC)
|
||||||
|
#include "ratl_common.h"
|
||||||
|
#endif
|
||||||
|
namespace ratl
|
||||||
|
{
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Bit Field Class
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
template <int SZ>
|
||||||
|
class bits_vs : public bits_base<SZ>
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Call This Function To Set All Bits Beyond SIZE to Zero
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void clear_trailing_bits()
|
||||||
|
{
|
||||||
|
for (int i=SIZE; i<ARRAY_SIZE*BITS_INT_SIZE; i++)
|
||||||
|
{
|
||||||
|
mV[i>>BITS_SHIFT] &= ~(1<<(i&BITS_AND));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Capacity Enum
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SIZE = SZ,
|
||||||
|
CAPACITY = SZ,
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Standard Constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bits_vs(bool init=true,bool initValue=false) : bits_base<SZ>(init,initValue)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copy Constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bits_vs(const bits_vs &B)
|
||||||
|
{
|
||||||
|
mem::cpy(mV, B.mV,BYTE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// String Constructor (Format: "100010100101")
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bits_vs(const char* Str)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
|
||||||
|
for (int b=0; b<SIZE; b++)
|
||||||
|
{
|
||||||
|
if (!Str[b])
|
||||||
|
{
|
||||||
|
return; // Reached The End Of The String
|
||||||
|
}
|
||||||
|
if (Str[b]=='1')
|
||||||
|
{
|
||||||
|
set_bit(b); // Found A True Bit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Checks If There Are Any Values At All In This Bit Field (Same as operator !())
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
for (int i=0; i<ARRAY_SIZE; i++)
|
||||||
|
{
|
||||||
|
if (mV[i])
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get The Number Of Bits Represented Here
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int size() const
|
||||||
|
{
|
||||||
|
return SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Execute A Bitwise Flip On All The Bits
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void invert()
|
||||||
|
{
|
||||||
|
for (int i=0; i<ARRAY_SIZE; i++)
|
||||||
|
{
|
||||||
|
mV[i] = ~mV[i];
|
||||||
|
}
|
||||||
|
clear_trailing_bits();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Execute A Bitwise Flip On All The Bits
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void operator~()
|
||||||
|
{
|
||||||
|
invert();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Query
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool get_bit(const int i) const
|
||||||
|
{
|
||||||
|
// If you hit this assert, then you are trying
|
||||||
|
// to query a bit that goes beyond the number
|
||||||
|
// of bits this object can hold.
|
||||||
|
//--------------------------------------------
|
||||||
|
assert(i>=0 && i < SIZE);
|
||||||
|
return ( (mV[i>>BITS_SHIFT] & (1<<(i&BITS_AND)))!=0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Checks If There Are Any Values At All In This Bit Field
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool operator!() const
|
||||||
|
{
|
||||||
|
return empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Equality Operator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool operator==(const bits_vs &B) const
|
||||||
|
{
|
||||||
|
return (mem::eql(mV, B.mV,BYTE_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// InEquality Operator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool operator!=(const bits_vs &B) const
|
||||||
|
{
|
||||||
|
return !(operator==(B));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Or In From Another Bits Object
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void operator|=(const bits_vs &B)
|
||||||
|
{
|
||||||
|
for (int i=0; i<ARRAY_SIZE; i++)
|
||||||
|
{
|
||||||
|
mV[i] |= B.mV[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// And In From Another Bits Object
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void operator&=(const bits_vs &B)
|
||||||
|
{
|
||||||
|
for (int i=0; i<ARRAY_SIZE; i++)
|
||||||
|
{
|
||||||
|
mV[i] &= B.mV[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// xor In From Another Bits Object
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void operator^=(const bits_vs &B)
|
||||||
|
{
|
||||||
|
for (int i=0; i<ARRAY_SIZE; i++)
|
||||||
|
{
|
||||||
|
mV[i] ^= B.mV[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Assignment Operator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void operator=(const bits_vs &B)
|
||||||
|
{
|
||||||
|
mem::cpy(mV, B.mV,BYTE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,526 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD TEMPLATE LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Grid
|
||||||
|
// ----
|
||||||
|
// There are two versions of the Grid class. Simply, they apply a discreet function
|
||||||
|
// mapping from a n dimensional space to a linear aray.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// NOTES:
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_GRID_VS_INC)
|
||||||
|
#define RATL_GRID_VS_INC
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Includes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_COMMON_INC)
|
||||||
|
#include "ratl_common.h"
|
||||||
|
#endif
|
||||||
|
#if !defined(RATL_ARRAY_VS)
|
||||||
|
#include "array_vs.h"
|
||||||
|
#endif
|
||||||
|
namespace ratl
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The 2D Grid Class
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
template <class T, int XSIZE_MAX, int YSIZE_MAX>
|
||||||
|
class grid2_vs : public ratl_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
grid2_vs()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
RANGE_NULL = 12345,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Assignment Operator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
grid2_vs& operator=(const grid2_vs& other)
|
||||||
|
{
|
||||||
|
mData = other.mData;
|
||||||
|
for (int i=0; i<2; i++)
|
||||||
|
{
|
||||||
|
mSize[i] = other.mSize[i];
|
||||||
|
mMins[i] = other.mMins[i];
|
||||||
|
mMaxs[i] = other.mMaxs[i];
|
||||||
|
mScale[i] = other.mScale[i];
|
||||||
|
}
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_size(int xSize, int ySize)
|
||||||
|
{
|
||||||
|
if (xSize<XSIZE_MAX)
|
||||||
|
{
|
||||||
|
mSize[0] = xSize;
|
||||||
|
}
|
||||||
|
if (ySize<YSIZE_MAX)
|
||||||
|
{
|
||||||
|
mSize[1] = ySize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void snap_scale()
|
||||||
|
{
|
||||||
|
mScale[0] = (float)((int)(mScale[0]));
|
||||||
|
mScale[1] = (float)((int)(mScale[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_size(int& xSize, int& ySize)
|
||||||
|
{
|
||||||
|
xSize = mSize[0];
|
||||||
|
ySize = mSize[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Clear
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
mSize[0] = XSIZE_MAX;
|
||||||
|
mSize[1] = YSIZE_MAX;
|
||||||
|
mData.clear();
|
||||||
|
for (int i=0; i<2; i++)
|
||||||
|
{
|
||||||
|
mMins[i] = RANGE_NULL;
|
||||||
|
mMaxs[i] = RANGE_NULL;
|
||||||
|
mScale[i] = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Initialize The Entire Grid To A Value
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void init(const T& val)
|
||||||
|
{
|
||||||
|
for (int i=0; i<(XSIZE_MAX*YSIZE_MAX); i++)
|
||||||
|
{
|
||||||
|
mData[i] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copy The Bounds Of Another Grid
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void copy_bounds(const grid2_vs& other)
|
||||||
|
{
|
||||||
|
for (int i=0; i<2; i++)
|
||||||
|
{
|
||||||
|
mSize[i] = other.mSize[i];
|
||||||
|
mMins[i] = other.mMins[i];
|
||||||
|
mMaxs[i] = other.mMaxs[i];
|
||||||
|
mScale[i] = other.mScale[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Accessor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
T& get(const int x, const int y)
|
||||||
|
{
|
||||||
|
assert(x>=0 && y>=0 && x<mSize[0] && y<mSize[1]);
|
||||||
|
return mData[(x + y*XSIZE_MAX)];
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Accessor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
T& get(float x, float y)
|
||||||
|
{
|
||||||
|
assert(mScale[0]!=0.0f && mScale[1]!=0.0f);
|
||||||
|
truncate_position_to_bounds(x, y);
|
||||||
|
|
||||||
|
int xint = (int)( (x-mMins[0]) / mScale[0] );
|
||||||
|
int yint = (int)( (y-mMins[1]) / mScale[1] );
|
||||||
|
|
||||||
|
assert(xint>=0 && yint>=0 && xint<mSize[0] && yint<mSize[1]);
|
||||||
|
return mData[(xint + yint*XSIZE_MAX)];
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Convert The Scaled Coordinates To A Grid Coordinate
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void get_cell_coords(float x, float y, int& xint, int& yint)
|
||||||
|
{
|
||||||
|
assert(mScale[0]!=0.0f && mScale[1]!=0.0f);
|
||||||
|
truncate_position_to_bounds(x, y);
|
||||||
|
|
||||||
|
xint = (int)( (x-mMins[0]) / mScale[0] );
|
||||||
|
yint = (int)( (y-mMins[1]) / mScale[1] );
|
||||||
|
|
||||||
|
assert(xint>=0 && yint>=0 && xint<mSize[0] && yint<mSize[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Expand
|
||||||
|
//
|
||||||
|
// NOTE: This MUST be at least a 2 dimensional point
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void expand_bounds(float xReal, float yReal)
|
||||||
|
{
|
||||||
|
float point[2] = {xReal, yReal};
|
||||||
|
for (int i=0; i<2; i++)
|
||||||
|
{
|
||||||
|
if (point[i]<mMins[i] || mMins[i]==RANGE_NULL)
|
||||||
|
{
|
||||||
|
mMins[i] = point[i];
|
||||||
|
}
|
||||||
|
if (point[i]>mMaxs[i] || mMaxs[i]==RANGE_NULL)
|
||||||
|
{
|
||||||
|
mMaxs[i] = point[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(mSize[0]>0 && mSize[1]>0);
|
||||||
|
|
||||||
|
mScale[0] = ((mMaxs[0] - mMins[0])/mSize[0]);
|
||||||
|
mScale[1] = ((mMaxs[1] - mMins[1])/mSize[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void truncate_position_to_bounds(float& xReal, float& yReal)
|
||||||
|
{
|
||||||
|
if (xReal<mMins[0])
|
||||||
|
{
|
||||||
|
xReal = mMins[0];
|
||||||
|
}
|
||||||
|
if (xReal>(mMaxs[0]-1.0f))
|
||||||
|
{
|
||||||
|
xReal = mMaxs[0]-1.0f;
|
||||||
|
}
|
||||||
|
if (yReal<mMins[1])
|
||||||
|
{
|
||||||
|
yReal = mMins[1];
|
||||||
|
}
|
||||||
|
if (yReal>(mMaxs[1]-1.0f))
|
||||||
|
{
|
||||||
|
yReal = mMaxs[1]-1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void get_cell_position(int x, int y, float& xReal, float& yReal)
|
||||||
|
{
|
||||||
|
// assert(mScale[0]!=0.0f && mScale[1]!=0.0f);
|
||||||
|
xReal = (x * mScale[0]) + mMins[0] + (mScale[0] * 0.5f);
|
||||||
|
yReal = (y * mScale[1]) + mMins[1] + (mScale[1] * 0.5f);
|
||||||
|
}
|
||||||
|
void get_cell_upperleft(int x, int y, float& xReal, float& yReal)
|
||||||
|
{
|
||||||
|
// assert(mScale[0]!=0.0f && mScale[1]!=0.0f);
|
||||||
|
xReal = (x * mScale[0]) + mMins[0];
|
||||||
|
yReal = (y * mScale[1]) + mMins[1];
|
||||||
|
}
|
||||||
|
void get_cell_lowerright(int x, int y, float& xReal, float& yReal)
|
||||||
|
{
|
||||||
|
// assert(mScale[0]!=0.0f && mScale[1]!=0.0f);
|
||||||
|
xReal = (x * mScale[0]) + mMins[0] + (mScale[0]);
|
||||||
|
yReal = (y * mScale[1]) + mMins[1] + (mScale[1]);
|
||||||
|
}
|
||||||
|
void scale_by_largest_axis(float& dist)
|
||||||
|
{
|
||||||
|
assert(mScale[0]!=0.0f && mScale[1]!=0.0f);
|
||||||
|
if (mScale[0]>mScale[1])
|
||||||
|
{
|
||||||
|
dist /= mScale[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dist /= mScale[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Data
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
private:
|
||||||
|
array_vs<T, XSIZE_MAX*YSIZE_MAX> mData;
|
||||||
|
|
||||||
|
int mSize[2];
|
||||||
|
float mMins[2];
|
||||||
|
float mMaxs[2];
|
||||||
|
float mScale[2];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Raw Get - For The Iterator Dereference Function
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
T& rawGet(int Loc)
|
||||||
|
{
|
||||||
|
assert(Loc>=0 && Loc<XSIZE_MAX*YSIZE_MAX);
|
||||||
|
return mData[Loc];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
class iterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
//--------------
|
||||||
|
iterator() {}
|
||||||
|
iterator(grid2_vs* p, int t) : mOwner(p), mLoc(t) {}
|
||||||
|
|
||||||
|
// Assignment Operator
|
||||||
|
//---------------------
|
||||||
|
void operator= (const iterator &t) {mOwner=t.mOwner; mLoc=t.mLoc;}
|
||||||
|
|
||||||
|
// Equality & Inequality Operators
|
||||||
|
//---------------------------------
|
||||||
|
bool operator!=(const iterator &t) {return (mLoc!=t.mLoc);}
|
||||||
|
bool operator==(const iterator &t) {return (mLoc==t.mLoc);}
|
||||||
|
|
||||||
|
// Dereference Operator
|
||||||
|
//----------------------
|
||||||
|
T& operator* () {return (mOwner->rawGet(mLoc));}
|
||||||
|
|
||||||
|
// Inc Operator
|
||||||
|
//--------------
|
||||||
|
void operator++(int) {mLoc++;}
|
||||||
|
|
||||||
|
|
||||||
|
// Row & Col Offsets
|
||||||
|
//-------------------
|
||||||
|
void offsetRows(int num) {mLoc += (YSIZE_MAX*num);}
|
||||||
|
void offsetCols(int num) {mLoc += (num);}
|
||||||
|
|
||||||
|
|
||||||
|
// Return True If On Frist Column Of A Row
|
||||||
|
//-----------------------------------------
|
||||||
|
bool onColZero()
|
||||||
|
{
|
||||||
|
return (mLoc%XSIZE_MAX)==0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evaluate The XY Position Of This Iterator
|
||||||
|
//-------------------------------------------
|
||||||
|
void position(int& X, int& Y)
|
||||||
|
{
|
||||||
|
Y = mLoc / XSIZE_MAX;
|
||||||
|
X = mLoc - (Y*XSIZE_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int mLoc;
|
||||||
|
grid2_vs* mOwner;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator Begin
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
iterator begin(int x=0, int y=0)
|
||||||
|
{
|
||||||
|
assert(x>=0 && y>=0 && x<mSize[0] && y<mSize[1]);
|
||||||
|
|
||||||
|
return iterator(this, (x + y*XSIZE_MAX));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator Begin (scaled position, use mins and maxs to calc real position)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
iterator begin(float xReal, float yReal)
|
||||||
|
{
|
||||||
|
assert(mScale[0]!=0.0f && mScale[1]!=0.0f);
|
||||||
|
truncate_position_to_bounds(xReal, yReal);
|
||||||
|
|
||||||
|
int x = (int)( (xReal-mMins[0]) / mScale[0] );
|
||||||
|
int y = (int)( (yReal-mMins[1]) / mScale[1] );
|
||||||
|
|
||||||
|
return begin(x,y);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator End
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
iterator end()
|
||||||
|
{
|
||||||
|
return iterator(this, (XSIZE_MAX*YSIZE_MAX));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Ranged Iterator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
class riterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
//--------------
|
||||||
|
riterator()
|
||||||
|
{}
|
||||||
|
riterator(grid2_vs* p, int Range, int SX, int SY) :
|
||||||
|
mOwner(p)
|
||||||
|
{
|
||||||
|
int Start[2] = {SX, SY};
|
||||||
|
int Bounds[2] = {XSIZE_MAX-1, YSIZE_MAX-1};
|
||||||
|
|
||||||
|
for (int i=0; i<2; i++)
|
||||||
|
{
|
||||||
|
mMins[i] = Start[i] - Range;
|
||||||
|
mMaxs[i] = Start[i] + Range;
|
||||||
|
|
||||||
|
if (mMins[i]<0)
|
||||||
|
{
|
||||||
|
mMins[i] = 0;
|
||||||
|
}
|
||||||
|
if (mMaxs[i] > Bounds[i])
|
||||||
|
{
|
||||||
|
mMaxs[i] = Bounds[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
mLoc[i] = mMins[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assignment Operator
|
||||||
|
//---------------------
|
||||||
|
void operator= (const riterator &t)
|
||||||
|
{
|
||||||
|
mOwner = t.mOwner;
|
||||||
|
for (int i=0; i<2; i++)
|
||||||
|
{
|
||||||
|
mMins[i] = t.mMins[i];
|
||||||
|
mMaxs[i] = t.mMaxs[i];
|
||||||
|
mLoc[i] = t.mLoc[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equality & Inequality Operators
|
||||||
|
//---------------------------------
|
||||||
|
bool operator!=(const riterator &t)
|
||||||
|
{
|
||||||
|
return (mLoc[0]!=t.mLoc[0] || mLoc[1]!=t.mLoc[1]);
|
||||||
|
}
|
||||||
|
bool operator==(const riterator &t)
|
||||||
|
{
|
||||||
|
return (mLoc[0]==t.mLoc[0] && mLoc[1]==t.mLoc[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dereference Operator
|
||||||
|
//----------------------
|
||||||
|
T& operator* ()
|
||||||
|
{
|
||||||
|
return (mOwner->get(mLoc[0], mLoc[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inc Operator
|
||||||
|
//--------------
|
||||||
|
void operator++(int)
|
||||||
|
{
|
||||||
|
if (mLoc[1] <= mMaxs[1])
|
||||||
|
{
|
||||||
|
mLoc[0]++;
|
||||||
|
if (mLoc[0]>(mMaxs[0]))
|
||||||
|
{
|
||||||
|
mLoc[0] = mMins[0];
|
||||||
|
mLoc[1]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool at_end()
|
||||||
|
{
|
||||||
|
return (mLoc[1]>mMaxs[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Return True If On Frist Column Of A Row
|
||||||
|
//-----------------------------------------
|
||||||
|
bool onColZero()
|
||||||
|
{
|
||||||
|
return (mLoc[0]==mMins[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evaluate The XY Position Of This Iterator
|
||||||
|
//-------------------------------------------
|
||||||
|
void position(int& X, int& Y)
|
||||||
|
{
|
||||||
|
Y = mLoc[1];
|
||||||
|
X = mLoc[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int mMins[2];
|
||||||
|
int mMaxs[2];
|
||||||
|
int mLoc[2];
|
||||||
|
grid2_vs* mOwner;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Ranged Iterator Begin (x and y are the center of the range)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
riterator rangeBegin(int range, int x, int y)
|
||||||
|
{
|
||||||
|
assert(x>=0 && y>=0 && x<XSIZE_MAX && y<YSIZE_MAX);
|
||||||
|
return riterator(this, range, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
riterator rangeBegin(int range, float xReal, float yReal)
|
||||||
|
{
|
||||||
|
float position[2] = {xReal, yReal};
|
||||||
|
assert(mScale[0]!=0.0f && mScale[1]!=0.0f);
|
||||||
|
truncate_position_to_bounds(xReal, yReal);
|
||||||
|
int x = ( (position[0]-mMins[0]) / mScale[0] );
|
||||||
|
int y = ( (position[1]-mMins[1]) / mScale[1] );
|
||||||
|
|
||||||
|
assert(x>=0 && y>=0 && x<XSIZE_MAX && y<YSIZE_MAX);
|
||||||
|
return riterator(this, range, x, y);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,291 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD TEMPLATE LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Handle Pool
|
||||||
|
// -----------
|
||||||
|
// The memory pool class is a simple routine for constant time allocation and deallocation
|
||||||
|
// from a fixed size pool of objects. The class uses a simple array to hold the actual
|
||||||
|
// data, a queue for the free list, and a bit field to mark which spots in the array
|
||||||
|
// are allocated.
|
||||||
|
//
|
||||||
|
// In addition to the standard memory pool features, this Handle Pool provides a fast
|
||||||
|
// iterator, asserts on attempting to access unused data, and a unique ID "handle" for
|
||||||
|
// the external system to use.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// NOTES:
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_HANDLE_POOL_VS_INC)
|
||||||
|
#define RATL_HANDLE_POOL_VS_INC
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Includes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_COMMON_INC)
|
||||||
|
#include "ratl_common.h"
|
||||||
|
#endif
|
||||||
|
#if !defined(RATL_POOL_VS_INC)
|
||||||
|
#include "pool_vs.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace ratl
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class handle_pool_base : public pool_root<T>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename T TStorageTraits;
|
||||||
|
typedef typename T::TValue TTValue;
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Capacity Enum
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = T::CAPACITY
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
int mHandles[CAPACITY];
|
||||||
|
int mMASK_HANDLE_TO_INDEX;
|
||||||
|
int mMASK_NUM_BITS;
|
||||||
|
|
||||||
|
void IncHandle(int index)
|
||||||
|
{
|
||||||
|
mHandles[index] += (1<<mMASK_NUM_BITS);
|
||||||
|
if (mHandles[index]<0)
|
||||||
|
{
|
||||||
|
// we rolled over
|
||||||
|
mHandles[index] = index; // Reset The ID Counter
|
||||||
|
mHandles[index] |= (1<<mMASK_NUM_BITS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor
|
||||||
|
//
|
||||||
|
// We need a routine to calculate the MASK used to convert a handle to an index and
|
||||||
|
// the number of bits needed to shift by.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
handle_pool_base()
|
||||||
|
{
|
||||||
|
mMASK_HANDLE_TO_INDEX = 0;
|
||||||
|
mMASK_NUM_BITS = 0;
|
||||||
|
|
||||||
|
int value=CAPACITY-1;
|
||||||
|
while(value)
|
||||||
|
{
|
||||||
|
value>>= 1;
|
||||||
|
|
||||||
|
mMASK_HANDLE_TO_INDEX <<= 1;
|
||||||
|
mMASK_HANDLE_TO_INDEX |= 1;
|
||||||
|
mMASK_NUM_BITS++;
|
||||||
|
}
|
||||||
|
for (int i=0; i<CAPACITY; i++)
|
||||||
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
|
mHandles[i] = i; // Reset The ID Counter
|
||||||
|
mHandles[i] |= ((++HandleSaltValue)<<mMASK_NUM_BITS);
|
||||||
|
#else
|
||||||
|
mHandles[i] = i; // Reset The ID Counter
|
||||||
|
mHandles[i] |= (1<<mMASK_NUM_BITS);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Clear - Removes all allocation information
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
pool_root<T>::clear();
|
||||||
|
// note that we do not refill the handles cause we want old handles to still be stale
|
||||||
|
for (int i=0; i<CAPACITY; i++)
|
||||||
|
{
|
||||||
|
IncHandle(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constant Accessor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const TTValue& operator[](int handle) const
|
||||||
|
{
|
||||||
|
assert(is_used(handle)); //typically this is a stale handle (already been freed)
|
||||||
|
return value_at_index(handle&mMASK_HANDLE_TO_INDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Accessor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TTValue& operator[](int i)
|
||||||
|
{
|
||||||
|
assert(is_used(i)); //typically this is a stale handle (already been freed)
|
||||||
|
return value_at_index(i&mMASK_HANDLE_TO_INDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_used(int i) const
|
||||||
|
{
|
||||||
|
if (mHandles[i&mMASK_HANDLE_TO_INDEX]==i)
|
||||||
|
{
|
||||||
|
return is_used_index(i&mMASK_HANDLE_TO_INDEX);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Swap two items based on handle
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void swap(int i,int j)
|
||||||
|
{
|
||||||
|
assert(is_used(i)); //typically this is a stale handle (already been freed)
|
||||||
|
assert(is_used(j)); //typically this is a stale handle (already been freed)
|
||||||
|
swap_index(handle_to_index(i),handle_to_index(j));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Allocator returns a handle
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int alloc()
|
||||||
|
{
|
||||||
|
int index=alloc_index();
|
||||||
|
return mHandles[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Allocator, with value, returns a handle
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int alloc(const TTValue &v)
|
||||||
|
{
|
||||||
|
int index=alloc_index(v);
|
||||||
|
return mHandles[index];
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Deallocator, by index, not something generally needed
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void free_index(int index)
|
||||||
|
{
|
||||||
|
pool_root<T>::free_index(index);
|
||||||
|
IncHandle(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Deallocator, by handle
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void free(int handle)
|
||||||
|
{
|
||||||
|
assert(is_used(handle));
|
||||||
|
free_index(handle&mMASK_HANDLE_TO_INDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Deallocator, by pointer
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void free(TTValue *me)
|
||||||
|
{
|
||||||
|
free_index(pointer_to_index(me));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Convert a handle to a raw index, not generally something you should use
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int handle_to_index(int handle) const
|
||||||
|
{
|
||||||
|
assert(is_used(handle));
|
||||||
|
return (handle&mMASK_HANDLE_TO_INDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// FInd the handle for a given index, this cannot check for stale handles, so it is ill advised
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int index_to_handle(int index) const
|
||||||
|
{
|
||||||
|
assert(index>=0 && index<CAPACITY && is_used_index(index)); //disallowing this on stale handles
|
||||||
|
return (mHandles[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// converts a T pointer to a handle, generally not something you need, cannot check for stale handles
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int pointer_to_handle(const TTValue *me) const
|
||||||
|
{
|
||||||
|
return index_to_handle(pointer_to_index(me));
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// converts a T pointer to a handle, generally not something you need, cannot check for stale handles
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int pointer_to_handle(const TRatlNew *me) const
|
||||||
|
{
|
||||||
|
return index_to_handle(pointer_to_index(me));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get An Iterator To The Object At handle
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
pool_root<T>::iterator at(int handle)
|
||||||
|
{
|
||||||
|
assert(is_used(handle));
|
||||||
|
return at_index(handle&mMASK_HANDLE_TO_INDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get An Iterator To The Object At handle
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
pool_root<T>::const_iterator at(int handle) const
|
||||||
|
{
|
||||||
|
assert(is_used(handle));
|
||||||
|
return at_index(handle&mMASK_HANDLE_TO_INDEX);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY>
|
||||||
|
class handle_pool_vs : public handle_pool_base<storage::value_semantics<T,ARG_CAPACITY> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::value_semantics<T,ARG_CAPACITY> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY
|
||||||
|
};
|
||||||
|
handle_pool_vs() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY>
|
||||||
|
class handle_pool_os : public handle_pool_base<storage::object_semantics<T,ARG_CAPACITY> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::object_semantics<T,ARG_CAPACITY> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY
|
||||||
|
};
|
||||||
|
handle_pool_os() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY, int ARG_MAX_CLASS_SIZE>
|
||||||
|
class handle_pool_is : public handle_pool_base<storage::virtual_semantics<T,ARG_CAPACITY,ARG_MAX_CLASS_SIZE> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::virtual_semantics<T,ARG_CAPACITY,ARG_MAX_CLASS_SIZE> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY,
|
||||||
|
MAX_CLASS_SIZE = ARG_MAX_CLASS_SIZE
|
||||||
|
};
|
||||||
|
handle_pool_is() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,200 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD TEMPLATE LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Hash Pool
|
||||||
|
// ---------
|
||||||
|
// The hash pool stores raw data of variable size. It uses a hash table to check for
|
||||||
|
// redundant data, and upon finding any, will return the existing handle. Otherwise
|
||||||
|
// it copies the data to memory and returns a new handle.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// NOTES:
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_HASH_POOL_VS_INC)
|
||||||
|
#define RATL_HASH_POOL_VS_INC
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Includes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_COMMON_INC)
|
||||||
|
#include "ratl_common.h"
|
||||||
|
#endif
|
||||||
|
namespace ratl
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Hash Pool
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
template <int SIZE, int SIZE_HANDLES>
|
||||||
|
class hash_pool
|
||||||
|
{
|
||||||
|
int mHandles[SIZE_HANDLES]; // each handle holds the start index of it's data
|
||||||
|
|
||||||
|
int mDataAlloc; // where the next chunck of data will go
|
||||||
|
char mData[SIZE];
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
int mFinds; // counts how many total finds have run
|
||||||
|
int mCurrentCollisions; // counts how many collisions on the last find
|
||||||
|
int mTotalCollisions; // counts the total number of collisions
|
||||||
|
int mTotalAllocs;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// This function searches for a handle which already stores the data (assuming the
|
||||||
|
// handle is a hash within range SIZE_HANDLES).
|
||||||
|
//
|
||||||
|
// If it failes, it returns false, and the handle passed in points to the next
|
||||||
|
// free slot.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool find_existing(int& handle, const void* data, int datasize)
|
||||||
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
|
mFinds++;
|
||||||
|
mCurrentCollisions = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while (mHandles[handle]) // So long as a handle exists there
|
||||||
|
{
|
||||||
|
if (mem::eql((void*)(&mData[mHandles[handle]]), data, datasize))
|
||||||
|
{
|
||||||
|
return true; // found
|
||||||
|
}
|
||||||
|
handle=(handle+1)&(SIZE_HANDLES-1); // incriment the handle
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
mCurrentCollisions ++;
|
||||||
|
mTotalCollisions ++;
|
||||||
|
|
||||||
|
//assert(mCurrentCollisions < 16); // If We Had 16+ Collisions, Hash May Be Inefficient.
|
||||||
|
// Evaluate SIZE and SIZEHANDLES
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return false; // failed to find
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// A simple hash function for the range of [0, SIZE_HANDLES]
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int hash(const void* data, int datasize)
|
||||||
|
{
|
||||||
|
int h=0;
|
||||||
|
for (int i=0; i<datasize; i++)
|
||||||
|
{
|
||||||
|
h += ((const char*)(data))[i] * (i + 119); // 119. Prime Number?
|
||||||
|
}
|
||||||
|
h &= SIZE_HANDLES - 1; // zero out bits beyoned SIZE_HANDLES
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
hash_pool()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Number Of Bytes Allocated
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int size() const
|
||||||
|
{
|
||||||
|
return mDataAlloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Check To See If This Memory Pool Is Empty
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return (mDataAlloc==1);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Check To See If This Memory Pool Has Enough Space Left For (minimum) Bytes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool full(int minimum) const
|
||||||
|
{
|
||||||
|
return ((SIZE - mDataAlloc)<minimum);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Clear - Removes all allocation information - Note! DOES NOT CLEAR MEMORY
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
mData[0] = 0;
|
||||||
|
mDataAlloc = 1;
|
||||||
|
for (int i=0; i<SIZE_HANDLES; i++)
|
||||||
|
{
|
||||||
|
mHandles[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
mFinds = 0;
|
||||||
|
mCurrentCollisions = 0;
|
||||||
|
mTotalCollisions = 0;
|
||||||
|
mTotalAllocs = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// This is the primary functionality of the hash pool. It will search for existing
|
||||||
|
// data of the same size, and failing to find any, it will append the data to the
|
||||||
|
// memory.
|
||||||
|
//
|
||||||
|
// In both cases, it gives you a handle to look up the data later.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int get_handle(const void* data, int datasize)
|
||||||
|
{
|
||||||
|
int handle = hash(data, datasize); // Initialize Our Handle By Hash Fcn
|
||||||
|
if (!find_existing(handle, data, datasize))
|
||||||
|
{
|
||||||
|
assert(mDataAlloc+datasize < SIZE); // Is There Enough Memory?
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
mTotalAllocs++;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mem::cpy((void*)(&mData[mDataAlloc]), data, datasize);// Copy Data To Memory
|
||||||
|
mHandles[handle] = mDataAlloc; // Mark Memory In Hash Tbl
|
||||||
|
mDataAlloc += datasize; // Adjust Next Alloc Location
|
||||||
|
}
|
||||||
|
return handle; // Return The Hash Tbl handleess
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constant Access Operator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const void* operator[](int handle) const
|
||||||
|
{
|
||||||
|
assert(handle>=0 && handle<SIZE_HANDLES);
|
||||||
|
|
||||||
|
return &(mData[mHandles[handle]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
float average_collisions() {return ((float)mTotalCollisions / (float)mFinds);}
|
||||||
|
int total_allocs() {return mTotalAllocs;}
|
||||||
|
int total_finds() {return mFinds;}
|
||||||
|
int total_collisions() {return mTotalCollisions;}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,324 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD TEMPLATE LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Heap
|
||||||
|
// ------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// TODO:
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// NOTES:
|
||||||
|
//
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_HEAP_VS_INC)
|
||||||
|
#define RATL_HEAP_VS_INC
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Includes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_COMMON_INC)
|
||||||
|
#include "ratl_common.h"
|
||||||
|
#endif
|
||||||
|
namespace ratl
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Vector Class
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
template<class T>
|
||||||
|
class heap_base : public ratl_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename T TStorageTraits;
|
||||||
|
typedef typename T::TValue TTValue;
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Capacity Enum
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = T::CAPACITY
|
||||||
|
};
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Data
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
private:
|
||||||
|
array_base<TStorageTraits> mData; // The Memory
|
||||||
|
int mPush; // Address Of Next Add Location
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Returns The Location Of Node (i)'s Parent Node (The Parent Node Of Zero Is Zero)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
static int parent(int i)
|
||||||
|
{
|
||||||
|
return ((i-1)/2);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Returns The Location Of Node (i)'s Left Child (The Child Of A Leaf Is The Leaf)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
static int left(int i)
|
||||||
|
{
|
||||||
|
return (2*i)+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Returns The Location Of Node (i)'s Right Child (The Child Of A Leaf Is The Leaf)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
static int right(int i)
|
||||||
|
{
|
||||||
|
return (2*i)+2;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Returns The Location Of Largest Child Of Node (i)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int largest_child(int i) const
|
||||||
|
{
|
||||||
|
if (left(i)<mPush)
|
||||||
|
{
|
||||||
|
if (right(i)<mPush)
|
||||||
|
{
|
||||||
|
return ( (mData[right(i)] < mData[left(i)]) ? (left(i)) : (right(i)) );
|
||||||
|
}
|
||||||
|
return left(i); // Node i only has a left child, so by default it is the biggest
|
||||||
|
}
|
||||||
|
return i; // Node i is a leaf, so just return it
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Swaps Two Element Locations
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void swap(int a, int b)
|
||||||
|
{
|
||||||
|
if (a==b)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert(a>=0 && b>=0 && a<CAPACITY && b<CAPACITY);
|
||||||
|
mData.swap(a,b);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Swaps The Data Up The Heap Until It Reaches A Valid Location
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void reheapify_upward(int Pos)
|
||||||
|
{
|
||||||
|
while (Pos && mData[parent(Pos)]<mData[Pos])
|
||||||
|
{
|
||||||
|
swap(parent(Pos), Pos);
|
||||||
|
Pos = parent(Pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Swaps The Data Down The Heap Until It Reaches A Valid Location
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void reheapify_downward(int Pos)
|
||||||
|
{
|
||||||
|
int largestChild = largest_child(Pos);
|
||||||
|
while (largestChild!=Pos && mData[Pos]<mData[largestChild])
|
||||||
|
{
|
||||||
|
swap(largestChild, Pos);
|
||||||
|
Pos = largestChild;
|
||||||
|
largestChild = largest_child(Pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Validate Will Run Through The Heap And Make Sure The Top Element Is Smallest
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool valid()
|
||||||
|
{
|
||||||
|
for (int i=1; i<mPush; i++)
|
||||||
|
{
|
||||||
|
if (mData[0]<mData[i])
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
heap_base() : mPush(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get The Size (The Difference Between The Push And Pop "Pointers")
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int size() const
|
||||||
|
{
|
||||||
|
return mPush;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Check To See If The Size Is Zero
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return !size();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Check To See If The Size Is Full
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool full() const
|
||||||
|
{
|
||||||
|
return size()==CAPACITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Empty Out The Entire Heap
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
mPush = 0;
|
||||||
|
mData.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get The Data Value At The Top Of The Heap
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const TTValue & top() const
|
||||||
|
{
|
||||||
|
assert(mPush>0); // Don't Try To Look At This If There Is Nothing In Here
|
||||||
|
return mData[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Add A Value To The Queue
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void push(const TTValue& nValue)
|
||||||
|
{
|
||||||
|
assert(size()<CAPACITY);
|
||||||
|
|
||||||
|
// Add It
|
||||||
|
//--------
|
||||||
|
mData.construct(mPush,nValue);
|
||||||
|
|
||||||
|
// Fix Possible Heap Inconsistancies
|
||||||
|
//-----------------------------------
|
||||||
|
reheapify_upward(mPush);
|
||||||
|
|
||||||
|
mPush++;
|
||||||
|
assert(valid());
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Alloc A Value, call push_alloced to add
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TTValue& alloc()
|
||||||
|
{
|
||||||
|
assert(size()<CAPACITY);
|
||||||
|
|
||||||
|
// Add It
|
||||||
|
//--------
|
||||||
|
mData.construct(mPush);
|
||||||
|
|
||||||
|
return mData[mPush];
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Alloc A Raw Value for placement new, call push_alloced to add
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TRatlNew * alloc_raw()
|
||||||
|
{
|
||||||
|
assert(size()<CAPACITY);
|
||||||
|
|
||||||
|
return mData.alloc_raw(mPush);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Add A Value To The Queue, after filling an alloced slot
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void push_alloced()
|
||||||
|
{
|
||||||
|
assert(size()<CAPACITY);
|
||||||
|
// Fix Possible Heap Inconsistancies
|
||||||
|
//-----------------------------------
|
||||||
|
reheapify_upward(mPush);
|
||||||
|
|
||||||
|
mPush++;
|
||||||
|
assert(valid());
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Remove A Value From The Queue
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void pop()
|
||||||
|
{
|
||||||
|
assert(size()>0);
|
||||||
|
|
||||||
|
mPush--;
|
||||||
|
|
||||||
|
// Swap The Lowest Element Up To The Spot We Just "Erased"
|
||||||
|
//---------------------------------------------------------
|
||||||
|
swap(0, mPush);
|
||||||
|
mData.destruct(mPush);
|
||||||
|
|
||||||
|
// Fix Possible Heap Inconsistancies
|
||||||
|
//-----------------------------------
|
||||||
|
reheapify_downward(0);
|
||||||
|
assert(valid());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
template<class T, int ARG_CAPACITY>
|
||||||
|
class heap_vs : public heap_base<storage::value_semantics<T,ARG_CAPACITY> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::value_semantics<T,ARG_CAPACITY> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY
|
||||||
|
};
|
||||||
|
heap_vs() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY>
|
||||||
|
class heap_os : public heap_base<storage::object_semantics<T,ARG_CAPACITY> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::object_semantics<T,ARG_CAPACITY> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY
|
||||||
|
};
|
||||||
|
heap_os() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY, int ARG_MAX_CLASS_SIZE>
|
||||||
|
class heap_is : public heap_base<storage::virtual_semantics<T,ARG_CAPACITY,ARG_MAX_CLASS_SIZE> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::virtual_semantics<T,ARG_CAPACITY,ARG_MAX_CLASS_SIZE> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY,
|
||||||
|
MAX_CLASS_SIZE = ARG_MAX_CLASS_SIZE
|
||||||
|
};
|
||||||
|
heap_is() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,751 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD TEMPLATE LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// List
|
||||||
|
// ----
|
||||||
|
// The list class supports ordered insertion and deletion in O(1) constant time.
|
||||||
|
// It simulates a linked list of pointers by allocating free spots in a pool and
|
||||||
|
// maintaining "links" as indicies to the pool array objects.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// NOTES:
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_LIST_VS_INC)
|
||||||
|
#define RATL_LIST_VS_INC
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Includes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if defined(RA_DEBUG_LINKING)
|
||||||
|
#pragma message("...including list_vs.h")
|
||||||
|
#endif
|
||||||
|
#if !defined(RATL_COMMON_INC)
|
||||||
|
#include "ratl_common.h"
|
||||||
|
#endif
|
||||||
|
#if !defined(RATL_POOL_VS_INC)
|
||||||
|
#include "pool_vs.h"
|
||||||
|
#endif
|
||||||
|
namespace ratl
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
// this is private to the list, but you have no access to it, soooo..
|
||||||
|
class list_node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int mNext;
|
||||||
|
int mPrev;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The List Class
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
template <class T>
|
||||||
|
class list_base : public ratl_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename T TStorageTraits;
|
||||||
|
typedef typename T::TValue TTValue;
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Capacity Enum
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = T::CAPACITY
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Data
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
pool_base<TStorageTraits> mPool; // The Allocation Data Pool
|
||||||
|
|
||||||
|
int mFront; // The Beginning Of The List
|
||||||
|
int mBack; // The End Of The List
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
NULL_NODE = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
list_base() : mFront(NULL_NODE), mBack(NULL_NODE)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// How Many Objects Are In This List
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int size() const
|
||||||
|
{
|
||||||
|
return (mPool.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Are There Any Objects In This List?
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
assert(mFront!=NULL_NODE || size()==0);
|
||||||
|
return (mFront==NULL_NODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Is This List Filled?
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool full() const
|
||||||
|
{
|
||||||
|
return (mPool.full());
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Clear All Elements
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
mFront = NULL_NODE;
|
||||||
|
mBack = NULL_NODE;
|
||||||
|
mPool.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get The First Object In The List
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TTValue & front()
|
||||||
|
{
|
||||||
|
assert(mFront!=NULL_NODE); // this is empty
|
||||||
|
return mPool[mFront];
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get The Last Object In The List
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TTValue & back()
|
||||||
|
{
|
||||||
|
assert(mBack!=NULL_NODE);
|
||||||
|
return mPool[mBack];
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get The First Object In The List
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const TTValue & front() const
|
||||||
|
{
|
||||||
|
assert(mFront!=NULL_NODE); // this is empty
|
||||||
|
return mPool[mFront];
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get The Last Object In The List
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const TTValue & back() const
|
||||||
|
{
|
||||||
|
assert(mBack!=NULL_NODE);
|
||||||
|
return mPool[mBack];
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
class const_iterator;
|
||||||
|
class iterator
|
||||||
|
{
|
||||||
|
friend class list_base<T>;
|
||||||
|
friend class const_iterator;
|
||||||
|
|
||||||
|
int mLoc;
|
||||||
|
list_base<T>* mOwner;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructors
|
||||||
|
//--------------
|
||||||
|
iterator() : mOwner(0), mLoc(0)
|
||||||
|
{}
|
||||||
|
iterator(list_base* p, int t) : mOwner(p), mLoc(t)
|
||||||
|
{}
|
||||||
|
iterator(const iterator &t) : mOwner(t.mOwner), mLoc(t.mLoc)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Assignment Operator
|
||||||
|
//---------------------
|
||||||
|
void operator= (const iterator &t)
|
||||||
|
{
|
||||||
|
mOwner = t.mOwner;
|
||||||
|
mLoc = t.mLoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Equality Operators
|
||||||
|
//--------------------
|
||||||
|
bool operator!=(const iterator &t) const
|
||||||
|
{
|
||||||
|
return (mLoc!=t.mLoc || mOwner!=t.mOwner);
|
||||||
|
}
|
||||||
|
bool operator==(const iterator &t) const
|
||||||
|
{
|
||||||
|
return (mLoc==t.mLoc && mOwner==t.mOwner);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeReference Operator
|
||||||
|
//----------------------
|
||||||
|
TTValue& operator* () const
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<T::CAPACITY);
|
||||||
|
return (mOwner->mPool[mLoc]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeReference Operator
|
||||||
|
//----------------------
|
||||||
|
TTValue& value() const
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<T::CAPACITY);
|
||||||
|
return (mOwner->mPool[mLoc]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeReference Operator
|
||||||
|
//----------------------
|
||||||
|
TTValue* operator-> () const
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<T::CAPACITY);
|
||||||
|
return (&mOwner->mPool[mLoc]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefix Inc Operator
|
||||||
|
//--------------
|
||||||
|
iterator operator++(int)
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<T::CAPACITY);
|
||||||
|
iterator old(*this);
|
||||||
|
mLoc = T::node(mOwner->mPool[mLoc]).mNext;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
// postfix Inc Operator
|
||||||
|
//--------------
|
||||||
|
iterator operator++()
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<T::CAPACITY);
|
||||||
|
mLoc = T::node(mOwner->mPool[mLoc]).mNext;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
// prefix Inc Operator
|
||||||
|
//--------------
|
||||||
|
iterator operator--(int)
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<T::CAPACITY);
|
||||||
|
iterator old(*this);
|
||||||
|
mLoc = T::node(mOwner->mPool[mLoc]).mPrev;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------
|
||||||
|
// postfix Dec Operator
|
||||||
|
//--------------
|
||||||
|
iterator operator--()
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<T::CAPACITY);
|
||||||
|
mLoc = T::node(mOwner->mPool[mLoc]).mPrev;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constant Iterator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
class const_iterator
|
||||||
|
{
|
||||||
|
friend class list_base<T>;
|
||||||
|
|
||||||
|
int mLoc;
|
||||||
|
const list_base<T>* mOwner;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructors
|
||||||
|
//--------------
|
||||||
|
const_iterator() : mOwner(0), mLoc(0)
|
||||||
|
{}
|
||||||
|
const_iterator(const list_base* p, int t) : mOwner(p), mLoc(t)
|
||||||
|
{}
|
||||||
|
const_iterator(const const_iterator &t) : mOwner(t.mOwner), mLoc(t.mLoc)
|
||||||
|
{}
|
||||||
|
const_iterator(const iterator &t) : mOwner(t.mOwner), mLoc(t.mLoc)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Assignment Operator
|
||||||
|
//---------------------
|
||||||
|
void operator= (const const_iterator &t)
|
||||||
|
{
|
||||||
|
mOwner = t.mOwner;
|
||||||
|
mLoc = t.mLoc;
|
||||||
|
}
|
||||||
|
// Assignment Operator
|
||||||
|
//---------------------
|
||||||
|
void operator= (const iterator &t)
|
||||||
|
{
|
||||||
|
mOwner = t.mOwner;
|
||||||
|
mLoc = t.mLoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Equality Operators
|
||||||
|
//--------------------
|
||||||
|
bool operator!=(const iterator &t) const
|
||||||
|
{
|
||||||
|
return (mLoc!=t.mLoc || mOwner!=t.mOwner);
|
||||||
|
}
|
||||||
|
bool operator==(const iterator &t) const
|
||||||
|
{
|
||||||
|
return (mLoc==t.mLoc && mOwner==t.mOwner);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equality Operators
|
||||||
|
//--------------------
|
||||||
|
bool operator!=(const const_iterator &t) const
|
||||||
|
{
|
||||||
|
return (mLoc!=t.mLoc || mOwner!=t.mOwner);
|
||||||
|
}
|
||||||
|
bool operator==(const const_iterator &t) const
|
||||||
|
{
|
||||||
|
return (mLoc==t.mLoc && mOwner==t.mOwner);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeReference Operator
|
||||||
|
//----------------------
|
||||||
|
const TTValue& operator* () const
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<T::CAPACITY);
|
||||||
|
return (mOwner->mPool[mLoc]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeReference Operator
|
||||||
|
//----------------------
|
||||||
|
const TTValue* operator-> () const
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<T::CAPACITY);
|
||||||
|
return (&mOwner->mPool[mLoc]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeReference Operator
|
||||||
|
//----------------------
|
||||||
|
const TTValue& value() const
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<T::CAPACITY);
|
||||||
|
return (mOwner->mPool[mLoc]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefix Inc Operator
|
||||||
|
//--------------
|
||||||
|
const_iterator operator++(int)
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<T::CAPACITY);
|
||||||
|
const_iterator old(*this);
|
||||||
|
mLoc = T::node(mOwner->mPool[mLoc]).mNext;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
// postfix Inc Operator
|
||||||
|
//--------------
|
||||||
|
const_iterator operator++()
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<T::CAPACITY);
|
||||||
|
mLoc = T::node(mOwner->mPool[mLoc]).mNext;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
// prefix Inc Operator
|
||||||
|
//--------------
|
||||||
|
const_iterator operator--(int)
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<T::CAPACITY);
|
||||||
|
const_iterator old(*this);
|
||||||
|
mLoc = T::node(mOwner->mPool[mLoc]).mPrev;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------
|
||||||
|
// postfix Dec Operator
|
||||||
|
//--------------
|
||||||
|
const_iterator operator--()
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<T::CAPACITY);
|
||||||
|
mLoc = T::node(mOwner->mPool[mLoc]).mPrev;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
friend class iterator;
|
||||||
|
friend class const_iterator;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator Begin (Starts At Address mFront)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
iterator begin()
|
||||||
|
{
|
||||||
|
return iterator(this, mFront);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator Begin (Starts At Address mFront)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const_iterator begin() const
|
||||||
|
{
|
||||||
|
return const_iterator(this, mFront);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Reverse Iterator Begin (Starts At Address mBack)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
iterator rbegin()
|
||||||
|
{
|
||||||
|
return iterator(this, mBack);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Reverse Iterator Begin (Starts At Address mBack)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const_iterator rbegin() const
|
||||||
|
{
|
||||||
|
return const_iterator(this, mBack);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator End (Set To Address NULL_NODE) Should Work For Forward & Backward Iteration
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
iterator end()
|
||||||
|
{
|
||||||
|
return iterator(this, NULL_NODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator End (Set To Address NULL_NODE) Should Work For Forward & Backward Iteration
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const_iterator end() const
|
||||||
|
{
|
||||||
|
return const_iterator(this, NULL_NODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator Insert (BEFORE POINTED ELEMENT)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
T& insert(const iterator& it)
|
||||||
|
{
|
||||||
|
int nNew= mPool.alloc();
|
||||||
|
insert_low(it,nNew);
|
||||||
|
return mPool[mNew];
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator Insert Value(BEFORE POINTED ELEMENT)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void insert(const iterator& it, const TTValue& val)
|
||||||
|
{
|
||||||
|
int nNew= mPool.alloc(val);
|
||||||
|
insert_low(it,nNew);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator Insert Raw(BEFORE POINTED ELEMENT)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TRatlNew* insert_raw(const iterator& it)
|
||||||
|
{
|
||||||
|
TRatlNew *ret = mPool.alloc_raw();
|
||||||
|
insert_low(it,mPool.pointer_to_index(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator Insert (AFTER POINTED ELEMENT) (ALSO - NOT CONSTANT, WILL CHANGE it)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
T& insert_after(iterator& it)
|
||||||
|
{
|
||||||
|
int nNew= mPool.alloc();
|
||||||
|
insert_low_after(it,nNew);
|
||||||
|
it = iterator(this, nNew);
|
||||||
|
return mPool[mNew];
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator Insert Value(AFTER POINTED ELEMENT) (ALSO - NOT CONSTANT, WILL CHANGE it)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void insert_after(iterator& it, const TTValue& val)
|
||||||
|
{
|
||||||
|
int nNew= mPool.alloc(val);
|
||||||
|
insert_low_after(it,nNew);
|
||||||
|
it = iterator(this, nNew);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator Insert Raw(AFTER POINTED ELEMENT) (ALSO - NOT CONSTANT, WILL CHANGE it)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TRatlNew* insert_raw_after(iterator& it)
|
||||||
|
{
|
||||||
|
TRatlNew *ret = mPool.alloc_raw();
|
||||||
|
insert_low_after(it,mPool.pointer_to_index(ret));
|
||||||
|
it = iterator(this, mPool.pointer_to_index(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Front Insert (BEFORE POINTED ELEMENT)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
T& push_front()
|
||||||
|
{
|
||||||
|
int nNew= mPool.alloc();
|
||||||
|
insert_low(begin(),nNew);
|
||||||
|
return mPool[mNew];
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Front Insert Value(BEFORE POINTED ELEMENT)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void push_front(const TTValue& val)
|
||||||
|
{
|
||||||
|
int nNew= mPool.alloc(val);
|
||||||
|
insert_low(begin(),nNew);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Front Insert Raw(BEFORE POINTED ELEMENT)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TRatlNew * push_front_raw()
|
||||||
|
{
|
||||||
|
TRatlNew *ret = mPool.alloc_raw();
|
||||||
|
insert_low(begin(),mPool.pointer_to_index(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Front Insert (BEFORE POINTED ELEMENT)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
T& push_back()
|
||||||
|
{
|
||||||
|
int nNew= mPool.alloc();
|
||||||
|
insert_low(end(),nNew);
|
||||||
|
return mPool[mNew];
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Front Insert Value(BEFORE POINTED ELEMENT)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void push_back(const TTValue& val)
|
||||||
|
{
|
||||||
|
int nNew= mPool.alloc(val);
|
||||||
|
insert_low(end(),nNew);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Front Insert Raw(BEFORE POINTED ELEMENT)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TRatlNew * push_back_raw()
|
||||||
|
{
|
||||||
|
TRatlNew *ret = mPool.alloc_raw();
|
||||||
|
insert_low(end(),mPool.pointer_to_index(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator Erase
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void erase(iterator& it)
|
||||||
|
{
|
||||||
|
assert(it.mOwner==this); // Iterators must be mixed up, this is from a different list.
|
||||||
|
assert(it.mLoc!=NULL_NODE);
|
||||||
|
|
||||||
|
int At = it.mLoc;
|
||||||
|
int Prev = T::node(mPool[At]).mPrev;
|
||||||
|
int Next = T::node(mPool[At]).mNext;
|
||||||
|
|
||||||
|
// LINK: (Prev)<-(At)--(Next)
|
||||||
|
//--------------------------------------------
|
||||||
|
if (Next!=NULL_NODE)
|
||||||
|
{
|
||||||
|
T::node(mPool[Next]).mPrev = Prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LINK: (Prev)--(At)->(Next)
|
||||||
|
//--------------------------------------------
|
||||||
|
if (Prev!=NULL_NODE)
|
||||||
|
{
|
||||||
|
T::node(mPool[Prev]).mNext = Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UPDATE: Front & Back
|
||||||
|
//----------------------
|
||||||
|
if (At==mBack)
|
||||||
|
{
|
||||||
|
mBack = Prev;
|
||||||
|
}
|
||||||
|
if (At==mFront)
|
||||||
|
{
|
||||||
|
mFront = Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ERASE At
|
||||||
|
//--------------------------------------------
|
||||||
|
mPool.free(At);
|
||||||
|
it.mLoc = Prev;
|
||||||
|
}
|
||||||
|
template<class CAST_TO>
|
||||||
|
CAST_TO *verify_alloc(CAST_TO *p) const
|
||||||
|
{
|
||||||
|
return mPool.verify_alloc(p);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator Insert, returns pool index
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void insert_low(const iterator& it,int nNew)
|
||||||
|
{
|
||||||
|
assert(it.mOwner==this); // Iterators must be mixed up, this is from a different list.
|
||||||
|
|
||||||
|
int Next = it.mLoc;
|
||||||
|
int Prev = NULL_NODE;
|
||||||
|
if (Next!=NULL_NODE)
|
||||||
|
{
|
||||||
|
Prev = T::node(mPool[Next]).mPrev;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Prev = mBack;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
assert(nNew!=Next && nNew!=Prev);
|
||||||
|
|
||||||
|
|
||||||
|
// LINK: (Prev)<-(New)->(Next)
|
||||||
|
//--------------------------------------------
|
||||||
|
T::node(mPool[nNew]).mPrev = Prev;
|
||||||
|
T::node(mPool[nNew]).mNext = Next;
|
||||||
|
|
||||||
|
|
||||||
|
// LINK: (New)<-(Next)
|
||||||
|
//--------------------------------------------
|
||||||
|
if (Next!=NULL_NODE)
|
||||||
|
{
|
||||||
|
T::node(mPool[Next]).mPrev = nNew;
|
||||||
|
assert(T::node(mPool[Next]).mPrev!=T::node(mPool[Next]).mNext);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mBack = nNew;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// LINK: (Prev)->(New)
|
||||||
|
//--------------------------------------------
|
||||||
|
if (Prev!=NULL_NODE)
|
||||||
|
{
|
||||||
|
T::node(mPool[Prev]).mNext = nNew;
|
||||||
|
assert(T::node(mPool[Prev]).mPrev!=T::node(mPool[Prev]).mNext);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mFront = nNew;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator Insert, returns pool index (AFTER POINTED ELEMENT)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void insert_low_after(const iterator& it,int nNew)
|
||||||
|
{
|
||||||
|
assert(it.mOwner==this); // Iterators must be mixed up, this is from a different list.
|
||||||
|
|
||||||
|
int Next = NULL_NODE;//it.mLoc;
|
||||||
|
int Prev = it.mLoc;//NULL_NODE;
|
||||||
|
if (Prev!=NULL_NODE)
|
||||||
|
{
|
||||||
|
Next = T::node(mPool[Prev]).mNext;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Prev = mFront;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
assert(nNew!=Next && nNew!=Prev);
|
||||||
|
|
||||||
|
|
||||||
|
// LINK: (Prev)<-(New)->(Next)
|
||||||
|
//--------------------------------------------
|
||||||
|
T::node(mPool[nNew]).mPrev = Prev;
|
||||||
|
T::node(mPool[nNew]).mNext = Next;
|
||||||
|
|
||||||
|
|
||||||
|
// LINK: (New)<-(Next)
|
||||||
|
//--------------------------------------------
|
||||||
|
if (Next!=NULL_NODE)
|
||||||
|
{
|
||||||
|
T::node(mPool[Next]).mPrev = nNew;
|
||||||
|
assert(T::node(mPool[Next]).mPrev!=T::node(mPool[Next]).mNext);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mBack = nNew;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// LINK: (Prev)->(New)
|
||||||
|
//--------------------------------------------
|
||||||
|
if (Prev!=NULL_NODE)
|
||||||
|
{
|
||||||
|
T::node(mPool[Prev]).mNext = nNew;
|
||||||
|
assert(T::node(mPool[Prev]).mPrev!=T::node(mPool[Prev]).mNext);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mFront = nNew;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY>
|
||||||
|
class list_vs : public list_base<storage::value_semantics_node<T,ARG_CAPACITY,list_node> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::value_semantics_node<T,ARG_CAPACITY,list_node> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY
|
||||||
|
};
|
||||||
|
list_vs() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY>
|
||||||
|
class list_os : public list_base<storage::object_semantics_node<T,ARG_CAPACITY,list_node> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::object_semantics_node<T,ARG_CAPACITY,list_node> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY
|
||||||
|
};
|
||||||
|
list_os() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY, int ARG_MAX_CLASS_SIZE>
|
||||||
|
class list_is : public list_base<storage::virtual_semantics_node<T,ARG_CAPACITY,ARG_MAX_CLASS_SIZE,list_node> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::virtual_semantics_node<T,ARG_CAPACITY,ARG_MAX_CLASS_SIZE,list_node> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY,
|
||||||
|
MAX_CLASS_SIZE = ARG_MAX_CLASS_SIZE
|
||||||
|
};
|
||||||
|
list_is() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,570 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD TEMPLATE LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Memory Pool
|
||||||
|
// -----------
|
||||||
|
// The memory pool class is a simple routine for constant time allocation and deallocation
|
||||||
|
// from a fixed size pool of objects. The class uses a simple array to hold the actual
|
||||||
|
// data, a queue for the free list, and a bit field to mark which spots in the array
|
||||||
|
// are allocated.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// NOTES:
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_POOL_VS_INC)
|
||||||
|
#define RATL_POOL_VS_INC
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Includes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_COMMON_INC)
|
||||||
|
#include "ratl_common.h"
|
||||||
|
#endif
|
||||||
|
#if !defined(RATL_QUEUE_VS_INC)
|
||||||
|
#include "queue_vs.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace ratl
|
||||||
|
{
|
||||||
|
|
||||||
|
// fixme, this could be made more efficient by keepingtrack of the highest slot ever used
|
||||||
|
// then there is no need to fill the free list
|
||||||
|
template <class T>
|
||||||
|
class pool_root : public ratl_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename T TStorageTraits;
|
||||||
|
typedef typename T::TValue TTValue;
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Capacity Enum
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = T::CAPACITY
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Data
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
array_base<TStorageTraits> mData;
|
||||||
|
queue_vs<int, CAPACITY> mFree;
|
||||||
|
bits_base<CAPACITY> mUsed;
|
||||||
|
int mSize;
|
||||||
|
|
||||||
|
|
||||||
|
void FillFreeList()
|
||||||
|
{
|
||||||
|
mFree.clear();
|
||||||
|
int i;
|
||||||
|
for (i=0;i<CAPACITY;i++)
|
||||||
|
{
|
||||||
|
mFree.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int alloc_low()
|
||||||
|
{
|
||||||
|
assert(mSize<CAPACITY);
|
||||||
|
assert(!mUsed[mFree.top()]);
|
||||||
|
|
||||||
|
int NextIndex = mFree.top(); // Get The First Available Location
|
||||||
|
|
||||||
|
mUsed.set_bit(NextIndex);
|
||||||
|
mFree.pop();
|
||||||
|
mSize ++;
|
||||||
|
return NextIndex;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
pool_root() : mSize(0)
|
||||||
|
{
|
||||||
|
FillFreeList();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Number Of Objects Allocated
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int size() const
|
||||||
|
{
|
||||||
|
return (mSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Check To See If This Memory Pool Is Empty
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return (mSize==0);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Check To See If This Memory Pool Is Full
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool full() const
|
||||||
|
{
|
||||||
|
return (mSize==CAPACITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constant Accessor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const TTValue& value_at_index(int i) const
|
||||||
|
{
|
||||||
|
assert(mUsed[i]);
|
||||||
|
return (mData[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Accessor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TTValue& value_at_index(int i)
|
||||||
|
{
|
||||||
|
assert(mUsed[i]);
|
||||||
|
return (mData[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Clear - Removes all allocation information
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
mSize = 0;
|
||||||
|
mUsed.clear();
|
||||||
|
mData.clear();
|
||||||
|
FillFreeList();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Check If An Index Has Been Allocated
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool is_used_index(int i) const
|
||||||
|
{
|
||||||
|
return mUsed[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Convert a pointer back to an index
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int pointer_to_index(const TTValue *me) const
|
||||||
|
{
|
||||||
|
assert(mSize>0);
|
||||||
|
|
||||||
|
int index=mData.pointer_to_index(me);
|
||||||
|
|
||||||
|
assert(index>=0 && index<CAPACITY);
|
||||||
|
assert(mUsed[index]); // I am disallowing obtaining the index of a freed item
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Convert a pointer back to an index
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int pointer_to_index(const TRatlNew *me) const
|
||||||
|
{
|
||||||
|
assert(mSize>0);
|
||||||
|
|
||||||
|
int index=mData.pointer_to_index(me);
|
||||||
|
|
||||||
|
assert(index>=0 && index<CAPACITY);
|
||||||
|
assert(mUsed[index]); // I am disallowing obtaining the index of a freed item
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Swap two items based on index
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void swap_index(int i,int j)
|
||||||
|
{
|
||||||
|
assert(i>=0 && i<CAPACITY);
|
||||||
|
assert(j>=0 && j<CAPACITY);
|
||||||
|
mData.swap(i,j);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Allocator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int alloc_index()
|
||||||
|
{
|
||||||
|
int NextIndex = alloc_low();
|
||||||
|
mData.construct(NextIndex);
|
||||||
|
return NextIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Allocator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int alloc_index(const TTValue &v)
|
||||||
|
{
|
||||||
|
int NextIndex = alloc_low();
|
||||||
|
mData.construct(NextIndex,v);
|
||||||
|
return NextIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Allocator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TRatlNew * alloc_raw()
|
||||||
|
{
|
||||||
|
int NextIndex = alloc_low();
|
||||||
|
return mData.alloc_raw(NextIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Deallocator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void free_index(int i)
|
||||||
|
{
|
||||||
|
assert(mSize>0);
|
||||||
|
assert(i>=0 && i<CAPACITY);
|
||||||
|
assert(mUsed[i]);
|
||||||
|
|
||||||
|
mData.destruct(i);
|
||||||
|
|
||||||
|
mUsed.clear_bit(i);
|
||||||
|
mFree.push(i);
|
||||||
|
mSize --;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Deallocator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void free(TTValue *me)
|
||||||
|
{
|
||||||
|
free(pointer_to_index(me));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
class const_iterator;
|
||||||
|
class iterator
|
||||||
|
{
|
||||||
|
friend class pool_root<T>;
|
||||||
|
friend class const_iterator;
|
||||||
|
int mIndex;
|
||||||
|
pool_root<T>* mOwner;
|
||||||
|
public:
|
||||||
|
// Constructors
|
||||||
|
//--------------
|
||||||
|
iterator() : mOwner(0)
|
||||||
|
{}
|
||||||
|
iterator(pool_root<T>* p, int index) : mOwner(p), mIndex(index)
|
||||||
|
{}
|
||||||
|
iterator(const iterator &t) : mOwner(t.mOwner), mIndex(t.mIndex)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Assignment Operator
|
||||||
|
//---------------------
|
||||||
|
void operator= (const iterator &t)
|
||||||
|
{
|
||||||
|
mOwner = t.mOwner;
|
||||||
|
mIndex = t.mIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equality Operators
|
||||||
|
//--------------------
|
||||||
|
bool operator!=(const iterator& t) {assert(mOwner && mOwner==t.mOwner); return (mIndex!=t.mIndex);}
|
||||||
|
bool operator==(const iterator& t) {assert(mOwner && mOwner==t.mOwner); return (mIndex==t.mIndex);}
|
||||||
|
|
||||||
|
// Dereference Operators
|
||||||
|
//----------------------
|
||||||
|
TTValue& operator* () const {assert(mOwner && mOwner->is_used_index(mIndex)); return (mOwner->mData[mIndex]);}
|
||||||
|
TTValue* operator->() const {assert(mOwner && mOwner->is_used_index(mIndex)); return (&mOwner->mData[mIndex]);}
|
||||||
|
|
||||||
|
// Handle & Index Access
|
||||||
|
//-----------------------
|
||||||
|
int index() {assert(mOwner && mOwner->is_used_index(mIndex)); return mIndex;}
|
||||||
|
|
||||||
|
// Inc Operator
|
||||||
|
//-------------
|
||||||
|
iterator operator++(int) // postfix
|
||||||
|
{
|
||||||
|
assert(mIndex>=0&&mIndex<CAPACITY); // this typically means you did end()++
|
||||||
|
assert(mOwner && mOwner->is_used_index(mIndex));
|
||||||
|
|
||||||
|
iterator ret(*this);
|
||||||
|
mIndex = mOwner->mUsed.next_bit(mIndex+1);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
// Inc Operator
|
||||||
|
//-------------
|
||||||
|
iterator operator++() // prefix
|
||||||
|
{
|
||||||
|
assert(mIndex>=0&&mIndex<CAPACITY); // this typically means you did end()++
|
||||||
|
assert(mOwner && mOwner->is_used_index(mIndex));
|
||||||
|
mIndex = mOwner->mUsed.next_bit(mIndex+1);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
friend class iterator;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
class const_iterator
|
||||||
|
{
|
||||||
|
int mIndex;
|
||||||
|
const pool_root<T>* mOwner;
|
||||||
|
public:
|
||||||
|
// Constructors
|
||||||
|
//--------------
|
||||||
|
const_iterator() : mOwner(0)
|
||||||
|
{}
|
||||||
|
const_iterator(const pool_root<T>* p, int index) : mOwner(p), mIndex(index)
|
||||||
|
{}
|
||||||
|
const_iterator(const iterator &t) : mOwner(t.mOwner), mIndex(t.mIndex)
|
||||||
|
{}
|
||||||
|
const_iterator(const const_iterator &t) : mOwner(t.mOwner), mIndex(t.mIndex)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Equality Operators
|
||||||
|
//--------------------
|
||||||
|
bool operator!=(const const_iterator& t) const {assert(mOwner && mOwner==t.mOwner); return (mIndex!=t.mIndex);}
|
||||||
|
bool operator==(const const_iterator& t) const {assert(mOwner && mOwner==t.mOwner); return (mIndex==t.mIndex);}
|
||||||
|
bool operator!=(const iterator& t) const {assert(mOwner && mOwner==t.mOwner); return (mIndex!=t.mIndex);}
|
||||||
|
bool operator==(const iterator& t) const {assert(mOwner && mOwner==t.mOwner); return (mIndex==t.mIndex);}
|
||||||
|
|
||||||
|
// Dereference Operators
|
||||||
|
//----------------------
|
||||||
|
const TTValue& operator* () const {assert(mOwner && mOwner->is_used_index(mIndex)); return (mOwner->mData[mIndex]);}
|
||||||
|
const TTValue* operator->() const {assert(mOwner && mOwner->is_used_index(mIndex)); return (&mOwner->mData[mIndex]);}
|
||||||
|
|
||||||
|
// Handle & Index Access
|
||||||
|
//-----------------------
|
||||||
|
int index() const {assert(mOwner && mOwner->is_used_index(mIndex)); return mIndex;}
|
||||||
|
|
||||||
|
// Inc Operator
|
||||||
|
//-------------
|
||||||
|
const_iterator operator++(int) // postfix
|
||||||
|
{
|
||||||
|
assert(mIndex>=0&&mIndex<CAPACITY); // this typically means you did end()++
|
||||||
|
assert(mOwner && mOwner->is_used_index(mIndex));
|
||||||
|
|
||||||
|
const_iterator ret(*this);
|
||||||
|
mIndex = mOwner->mUsed.next_bit(mIndex+1);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
// Inc Operator
|
||||||
|
//-------------
|
||||||
|
const_iterator operator++() // prefix
|
||||||
|
{
|
||||||
|
assert(mIndex>=0&&mIndex<CAPACITY); // this typically means you did end()++
|
||||||
|
assert(mOwner && mOwner->is_used_index(mIndex));
|
||||||
|
mIndex = mOwner->mUsed.next_bit(mIndex+1);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
friend class const_iterator;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get An Iterator To The First Allocated Memory Block
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
iterator begin()
|
||||||
|
{
|
||||||
|
int idx=mUsed.next_bit(0);
|
||||||
|
return iterator(this,idx); // Find The First Allocated
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get An Iterator To The Object At index
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
iterator at_index(int index)
|
||||||
|
{
|
||||||
|
assert(mUsed[index]); // disallow iterators to non alloced things
|
||||||
|
return iterator(this, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get An Iterator To The End Of The Memroy (One Step Beyond)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
iterator end()
|
||||||
|
{
|
||||||
|
return iterator(this, CAPACITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get An Iterator To The First Allocated Memory Block
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const_iterator begin() const
|
||||||
|
{
|
||||||
|
int idx=mUsed.next_bit(0);
|
||||||
|
return iterator(this,idx); // Find The First Allocated
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get An Iterator To The Object At index
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const_iterator at_index(int index) const
|
||||||
|
{
|
||||||
|
assert(mUsed[index]); // disallow iterators to non alloced things
|
||||||
|
return iterator(this, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get An Iterator To The End Of The Memroy (One Step Beyond)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const_iterator end() const
|
||||||
|
{
|
||||||
|
return iterator(this, CAPACITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class CAST_TO>
|
||||||
|
CAST_TO *verify_alloc(CAST_TO *p) const
|
||||||
|
{
|
||||||
|
return mData.verify_alloc(p);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
pool_base, base class for the pools
|
||||||
|
|
||||||
|
operations:
|
||||||
|
|
||||||
|
size()
|
||||||
|
empty()
|
||||||
|
full()
|
||||||
|
clear() op[]
|
||||||
|
at_index() op[]
|
||||||
|
at_index() const
|
||||||
|
index pointer_to_index(ptr)
|
||||||
|
index alloc_index() alloc()
|
||||||
|
index alloc_index(ref) alloc()
|
||||||
|
ptr alloc_raw()
|
||||||
|
free_index(index)
|
||||||
|
free(ptr)
|
||||||
|
is_used_index(index)
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class pool_base : public pool_root<T>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename T::TValue TTValue;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constant Accessor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const TTValue& operator[](int i) const
|
||||||
|
{
|
||||||
|
return value_at_index(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Accessor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TTValue& operator[](int i)
|
||||||
|
{
|
||||||
|
return value_at_index(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_used(int i) const
|
||||||
|
{
|
||||||
|
return is_used_index(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Swap two items based on index
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void swap(int i,int j)
|
||||||
|
{
|
||||||
|
swap_index(i,j);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Allocator returns an index
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int alloc()
|
||||||
|
{
|
||||||
|
return alloc_index();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Allocator returns an index
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int alloc(const TTValue &v)
|
||||||
|
{
|
||||||
|
return alloc_index(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Deallocator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void free(int i)
|
||||||
|
{
|
||||||
|
free_index(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get An Iterator To The Object At index
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
pool_root<T>::iterator at(int index)
|
||||||
|
{
|
||||||
|
return at_index(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get An Iterator To The Object At index
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
pool_root<T>::const_iterator at(int index) const
|
||||||
|
{
|
||||||
|
return at_index(index);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY>
|
||||||
|
class pool_vs : public pool_base<storage::value_semantics<T,ARG_CAPACITY> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::value_semantics<T,ARG_CAPACITY> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY
|
||||||
|
};
|
||||||
|
pool_vs() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY>
|
||||||
|
class pool_os : public pool_base<storage::object_semantics<T,ARG_CAPACITY> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::object_semantics<T,ARG_CAPACITY> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY
|
||||||
|
};
|
||||||
|
pool_os() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY, int ARG_MAX_CLASS_SIZE>
|
||||||
|
class pool_is : public pool_base<storage::virtual_semantics<T,ARG_CAPACITY,ARG_MAX_CLASS_SIZE> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::virtual_semantics<T,ARG_CAPACITY,ARG_MAX_CLASS_SIZE> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY,
|
||||||
|
MAX_CLASS_SIZE = ARG_MAX_CLASS_SIZE
|
||||||
|
};
|
||||||
|
pool_is() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,231 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD TEMPLATE LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Queue Template
|
||||||
|
// --------------
|
||||||
|
// The queue is a circular buffer of objects which supports a push at the "front" and a
|
||||||
|
// pop at the "back". Therefore it is:
|
||||||
|
//
|
||||||
|
// First In, First Out
|
||||||
|
//
|
||||||
|
// As the pointers to the push and pop locations are changed it wrapps around the end
|
||||||
|
// of the array and back to the front. There are asserts to make sure it never goes
|
||||||
|
// beyond the capacity of the object.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// NOTES:
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_QUEUE_VS_INC)
|
||||||
|
#define RATL_QUEUE_VS_INC
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Includes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_COMMON_INC)
|
||||||
|
#include "ratl_common.h"
|
||||||
|
#endif
|
||||||
|
namespace ratl
|
||||||
|
{
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Queue Class
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
template <class T>
|
||||||
|
class queue_base : public ratl_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename T TStorageTraits;
|
||||||
|
typedef typename T::TValue TTValue;
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Capacity Enum
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = T::CAPACITY
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Data
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
array_base<TStorageTraits> mData; // The Memory
|
||||||
|
int mPush; // Address Of Next Add Location
|
||||||
|
int mPop; // Address Of Next Remove Location
|
||||||
|
int mSize;
|
||||||
|
|
||||||
|
|
||||||
|
int push_low()
|
||||||
|
{
|
||||||
|
assert(size()<CAPACITY);
|
||||||
|
|
||||||
|
// Add It
|
||||||
|
//--------
|
||||||
|
mPush++;
|
||||||
|
mSize++;
|
||||||
|
|
||||||
|
// Update Push Location
|
||||||
|
//----------------------
|
||||||
|
if (mPush>=CAPACITY)
|
||||||
|
{
|
||||||
|
mPush=0;
|
||||||
|
return CAPACITY-1;
|
||||||
|
}
|
||||||
|
return mPush-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef T TStorageTraits;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
queue_base() : mPush(0), mPop(0), mSize(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get The Size (The Difference Between The Push And Pop "Pointers")
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int size() const
|
||||||
|
{
|
||||||
|
return mSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Check To See If The Size Is Zero
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return !mSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Check To See If The Size Is Full
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool full() const
|
||||||
|
{
|
||||||
|
return mSize>=CAPACITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Empty Out The Entire Queue
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
mPush = 0;
|
||||||
|
mPop = 0;
|
||||||
|
mSize = 0;
|
||||||
|
mData.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Add A Value, returns a reference to the value in place
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TTValue & push()
|
||||||
|
{
|
||||||
|
int idx=push_low();
|
||||||
|
mData.construct(idx);
|
||||||
|
return mData[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Add A Value to the Queue
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void push(const TTValue& v)
|
||||||
|
{
|
||||||
|
mData.construct(push_low(),v);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Add A Value to the Queue, returning a void * to the memory
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TRatlNew *push_raw()
|
||||||
|
{
|
||||||
|
return mData.alloc_raw(push_low());
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Remove A Value From The Queue
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void pop()
|
||||||
|
{
|
||||||
|
assert(size()>0);
|
||||||
|
|
||||||
|
mData.destruct(mPop);
|
||||||
|
// Update Pop Location
|
||||||
|
//---------------------
|
||||||
|
mPop++;
|
||||||
|
if (mPop>=CAPACITY)
|
||||||
|
{
|
||||||
|
mPop=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mSize--;
|
||||||
|
}
|
||||||
|
|
||||||
|
TTValue & top()
|
||||||
|
{
|
||||||
|
assert(size()>0);
|
||||||
|
return mData[mPop];
|
||||||
|
}
|
||||||
|
|
||||||
|
const TTValue & top() const
|
||||||
|
{
|
||||||
|
assert(size()>0);
|
||||||
|
return mData[mPop];
|
||||||
|
}
|
||||||
|
template<class CAST_TO>
|
||||||
|
CAST_TO *verify_alloc(CAST_TO *p) const
|
||||||
|
{
|
||||||
|
return mData.verify_alloc(p);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY>
|
||||||
|
class queue_vs : public queue_base<storage::value_semantics<T,ARG_CAPACITY> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::value_semantics<T,ARG_CAPACITY> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY
|
||||||
|
};
|
||||||
|
queue_vs() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY>
|
||||||
|
class queue_os : public queue_base<storage::object_semantics<T,ARG_CAPACITY> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::object_semantics<T,ARG_CAPACITY> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY
|
||||||
|
};
|
||||||
|
queue_os() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY, int ARG_MAX_CLASS_SIZE>
|
||||||
|
class queue_is : public queue_base<storage::virtual_semantics<T,ARG_CAPACITY,ARG_MAX_CLASS_SIZE> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::virtual_semantics<T,ARG_CAPACITY,ARG_MAX_CLASS_SIZE> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY,
|
||||||
|
MAX_CLASS_SIZE = ARG_MAX_CLASS_SIZE
|
||||||
|
};
|
||||||
|
queue_is() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,130 @@
|
||||||
|
#if !defined(RATL_COMMON_INC)
|
||||||
|
#include "ratl_common.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#include "array_vs.h"
|
||||||
|
#include "bits_vs.h"
|
||||||
|
#include "heap_vs.h"
|
||||||
|
#include "pool_vs.h"
|
||||||
|
#include "list_vs.h"
|
||||||
|
#include "queue_vs.h"
|
||||||
|
#include "stack_vs.h"
|
||||||
|
#include "string_vs.h"
|
||||||
|
#include "vector_vs.h"
|
||||||
|
#include "handle_pool_vs.h"
|
||||||
|
#include "hash_pool_vs.h"
|
||||||
|
#include "map_vs.h"
|
||||||
|
#include "scheduler_vs.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(CTYPE_H_INC)
|
||||||
|
#include <ctype.h>
|
||||||
|
#define CTYPE_H_INC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(STDARG_H_INC)
|
||||||
|
#include <stdarg.h>
|
||||||
|
#define STDARG_H_INC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(STDIO_H_INC)
|
||||||
|
#include <stdio.h>
|
||||||
|
#define STDIO_H_INC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(RUFL_HFILE_INC)
|
||||||
|
#include "..\Rufl\hfile.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void* ratl::ratl_base::OutputPrint = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace ratl
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
int HandleSaltValue=1027; //this is used in debug for global uniqueness of handles
|
||||||
|
int FoolTheOptimizer=5; //this is used to make sure certain things aren't optimized out
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _XBOX
|
||||||
|
void ratl_base::save(hfile& file)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ratl_base::load(hfile& file)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// A Profile Print Function
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(FINAL_BUILD)
|
||||||
|
void ratl_base::ProfilePrint(const char * format, ...)
|
||||||
|
{
|
||||||
|
static char string[2][1024]; // in case this is called by nested functions
|
||||||
|
static int index = 0;
|
||||||
|
static char nFormat[300];
|
||||||
|
char* buf;
|
||||||
|
|
||||||
|
// Tack On The Standard Format Around The Given Format
|
||||||
|
//-----------------------------------------------------
|
||||||
|
sprintf(nFormat, "[PROFILE] %s\n", format);
|
||||||
|
|
||||||
|
|
||||||
|
// Resolve Remaining Elipsis Parameters Into Newly Formated String
|
||||||
|
//-----------------------------------------------------------------
|
||||||
|
buf = string[index & 1];
|
||||||
|
index++;
|
||||||
|
|
||||||
|
va_list argptr;
|
||||||
|
va_start (argptr, format);
|
||||||
|
vsprintf (buf, nFormat, argptr);
|
||||||
|
va_end (argptr);
|
||||||
|
|
||||||
|
// Print It To Debug Output Console
|
||||||
|
//----------------------------------
|
||||||
|
if (OutputPrint!=0)
|
||||||
|
{
|
||||||
|
void (*OutputPrintFcn)(const char* text) = (void (__cdecl*)(const char*))OutputPrint;
|
||||||
|
OutputPrintFcn(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void ratl_base::ProfilePrint(const char * format, ...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace str
|
||||||
|
{
|
||||||
|
void to_upper(char *dest)
|
||||||
|
{
|
||||||
|
for (int i=0; i<len(dest);i++)
|
||||||
|
{
|
||||||
|
dest[i] = (char)(toupper(dest[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void to_lower(char *dest)
|
||||||
|
{
|
||||||
|
for (int i=0; i<len(dest);i++)
|
||||||
|
{
|
||||||
|
dest[i] = (char)(tolower(dest[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void printf(char *dest,const char *formatS, ...)
|
||||||
|
{
|
||||||
|
va_list argptr;
|
||||||
|
va_start (argptr, formatS);
|
||||||
|
vsprintf (dest, formatS,argptr);
|
||||||
|
va_end (argptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,218 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD TEMPLATE LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Scheduler
|
||||||
|
// ---------
|
||||||
|
// The scheduler is a common piece of game functionality. To use it, simply add events
|
||||||
|
// at the given time, and call update() with the current time as frequently as you wish.
|
||||||
|
//
|
||||||
|
// Your event class MUST define a Fire() function which accepts a TCALLBACKPARAMS
|
||||||
|
// parameter.
|
||||||
|
//
|
||||||
|
// NOTES:
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_SCHEDULER_VS_INC)
|
||||||
|
#define RATL_SCHEDULER_VS_INC
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Includes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_COMMON_INC)
|
||||||
|
#include "ratl_common.h"
|
||||||
|
#endif
|
||||||
|
#if !defined(RATL_POOL_VS_INC)
|
||||||
|
#include "pool_vs.h"
|
||||||
|
#endif
|
||||||
|
#if !defined(RATL_HEAP_VS_INC)
|
||||||
|
#include "heap_vs.h"
|
||||||
|
#endif
|
||||||
|
namespace ratl
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Scheduler Class
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
template <class T>
|
||||||
|
class scheduler_base : public ratl_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename T TStorageTraits;
|
||||||
|
typedef typename T::TValue TTValue;
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Capacity Enum
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = T::CAPACITY
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Timed Event Class
|
||||||
|
//
|
||||||
|
// This class stores two numbers, a timer and an iterator to the events list. We
|
||||||
|
// don't store the event directly in the heap to make the swap operation in the
|
||||||
|
// heap faster. We define a less than operator so we can sort in the heap.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
struct timed_event
|
||||||
|
{
|
||||||
|
float mTime;
|
||||||
|
int mEvent;
|
||||||
|
|
||||||
|
timed_event() {}
|
||||||
|
timed_event(float time, int event) : mTime(time), mEvent(event) {}
|
||||||
|
bool operator< (const timed_event& t) const
|
||||||
|
{
|
||||||
|
return (mTime > t.mTime);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pool_base<TStorageTraits> mEvents;
|
||||||
|
heap_vs<timed_event, CAPACITY> mHeap;
|
||||||
|
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// How Many Objects Are In This List
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int size() const
|
||||||
|
{
|
||||||
|
// warning during a fire call, there will be one extra event
|
||||||
|
return mEvents.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Are There Any Objects In This List?
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return !size();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Is This List Filled?
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool full() const
|
||||||
|
{
|
||||||
|
return mEvents.full();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Clear All Elements
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
mEvents.clear();
|
||||||
|
mHeap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Add An Event
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void add(float time, const TTValue& e)
|
||||||
|
{
|
||||||
|
int nLoc = mEvents.alloc(e);
|
||||||
|
mHeap.push(timed_event(time, nLoc));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Add An Event
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TTValue & add(float time)
|
||||||
|
{
|
||||||
|
int nLoc = mEvents.alloc();
|
||||||
|
mHeap.push(timed_event(time, nLoc));
|
||||||
|
return mEvents[nLoc];
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Add A Raw Event for placement new
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TRatlNew * add_raw(float time)
|
||||||
|
{
|
||||||
|
TRatlNew *ret = mEvents.alloc_raw();
|
||||||
|
mHeap.push(timed_event(time, mEvents.pointer_to_index(ret)));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class TCALLBACKPARAMS>
|
||||||
|
void update(float time, TCALLBACKPARAMS& Params)
|
||||||
|
{
|
||||||
|
while (!mHeap.empty())
|
||||||
|
{
|
||||||
|
timed_event Next = mHeap.top();
|
||||||
|
if (Next.mTime>=time)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mHeap.pop();
|
||||||
|
mEvents[Next.mEvent].Fire(Params);
|
||||||
|
mEvents.free(Next.mEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void update(float time)
|
||||||
|
{
|
||||||
|
while (!mHeap.empty())
|
||||||
|
{
|
||||||
|
timed_event Next = mHeap.top();
|
||||||
|
if (Next.mTime>=time)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mHeap.pop();
|
||||||
|
mEvents[Next.mEvent].Fire();
|
||||||
|
mEvents.free(Next.mEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY>
|
||||||
|
class scheduler_vs : public scheduler_base<storage::value_semantics<T,ARG_CAPACITY> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::value_semantics<T,ARG_CAPACITY> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY
|
||||||
|
};
|
||||||
|
scheduler_vs() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY>
|
||||||
|
class scheduler_os : public scheduler_base<storage::object_semantics<T,ARG_CAPACITY> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::object_semantics<T,ARG_CAPACITY> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY
|
||||||
|
};
|
||||||
|
scheduler_os() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY, int ARG_MAX_CLASS_SIZE>
|
||||||
|
class scheduler_is : public scheduler_base<storage::virtual_semantics<T,ARG_CAPACITY,ARG_MAX_CLASS_SIZE> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::virtual_semantics<T,ARG_CAPACITY,ARG_MAX_CLASS_SIZE> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY,
|
||||||
|
MAX_CLASS_SIZE = ARG_MAX_CLASS_SIZE
|
||||||
|
};
|
||||||
|
scheduler_is() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,197 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD TEMPLATE LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Stack
|
||||||
|
// -----
|
||||||
|
// This is a very simple wrapper around a stack object.
|
||||||
|
//
|
||||||
|
// First In, Last Out
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// NOTES:
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_STACK_VS_INC)
|
||||||
|
#define RATL_STACK_VS_INC
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Includes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_COMMON_INC)
|
||||||
|
#include "ratl_common.h"
|
||||||
|
#endif
|
||||||
|
namespace ratl
|
||||||
|
{
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The stack Class
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
template <class T>
|
||||||
|
class stack_base : public ratl_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename T TStorageTraits;
|
||||||
|
typedef typename T::TValue TTValue;
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Capacity Enum
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = T::CAPACITY
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Data
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
array_base<TStorageTraits> mData; // The Memory
|
||||||
|
int mSize;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
stack_base() : mSize(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get The Size (The Difference Between The Push And Pop "Pointers")
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int size() const
|
||||||
|
{
|
||||||
|
return mSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Check To See If The Size Is Zero
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return !mSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Check To See If The Size Is Full
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool full() const
|
||||||
|
{
|
||||||
|
return mSize>=CAPACITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Empty Out The Entire stack
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
mSize = 0;
|
||||||
|
mData.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Add A Value, returns a reference to the value in place
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TTValue & push()
|
||||||
|
{
|
||||||
|
assert(!full());
|
||||||
|
mData.construct(mSize);
|
||||||
|
mSize++;
|
||||||
|
return mData[mSize-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Add A Value to the stack
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void push(const TTValue& v)
|
||||||
|
{
|
||||||
|
assert(!full());
|
||||||
|
mData.construct(mSize,v);
|
||||||
|
mSize++;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Add A Value to the stack, returning a void * to the memory
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TRatlNew *push_raw()
|
||||||
|
{
|
||||||
|
assert(!full());
|
||||||
|
mSize++;
|
||||||
|
return mData.alloc_raw(mSize-1);
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Remove A Value From The stack
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void pop()
|
||||||
|
{
|
||||||
|
assert(!empty());
|
||||||
|
mSize--;
|
||||||
|
mData.destruct(mSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
TTValue & top()
|
||||||
|
{
|
||||||
|
assert(!empty());
|
||||||
|
return mData[mSize-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
const TTValue & top() const
|
||||||
|
{
|
||||||
|
assert(!empty());
|
||||||
|
return mData[mSize-1];
|
||||||
|
}
|
||||||
|
template<class CAST_TO>
|
||||||
|
CAST_TO *verify_alloc(CAST_TO *p) const
|
||||||
|
{
|
||||||
|
return mData.verify_alloc(p);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY>
|
||||||
|
class stack_vs : public stack_base<storage::value_semantics<T,ARG_CAPACITY> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::value_semantics<T,ARG_CAPACITY> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY
|
||||||
|
};
|
||||||
|
stack_vs() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY>
|
||||||
|
class stack_os : public stack_base<storage::object_semantics<T,ARG_CAPACITY> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::object_semantics<T,ARG_CAPACITY> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY
|
||||||
|
};
|
||||||
|
stack_os() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY, int ARG_MAX_CLASS_SIZE>
|
||||||
|
class stack_is : public stack_base<storage::virtual_semantics<T,ARG_CAPACITY,ARG_MAX_CLASS_SIZE> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::virtual_semantics<T,ARG_CAPACITY,ARG_MAX_CLASS_SIZE> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY,
|
||||||
|
MAX_CLASS_SIZE = ARG_MAX_CLASS_SIZE
|
||||||
|
};
|
||||||
|
stack_is() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,366 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD TEMPLATE LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// String
|
||||||
|
// ------
|
||||||
|
// Simple wrapper around a char[SIZE] array.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// NOTES:
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_STRING_VS_INC)
|
||||||
|
#define RATL_STRING_VS_INC
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Includes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_COMMON_INC)
|
||||||
|
#include "ratl_common.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace ratl
|
||||||
|
{
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The String Class
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
template<int ARG_CAPACITY>
|
||||||
|
class string_vs : public ratl_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Capacity Enum
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY,
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Data
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#ifdef _DEBUG
|
||||||
|
char mData[CAPACITY+4];
|
||||||
|
#else
|
||||||
|
char mData[CAPACITY];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void FillTerminator()
|
||||||
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
|
mData[CAPACITY]='e';
|
||||||
|
mData[CAPACITY+1]='n';
|
||||||
|
mData[CAPACITY+2]='d';
|
||||||
|
mData[CAPACITY+3]=0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
string_vs()
|
||||||
|
{
|
||||||
|
mData[0]=0;
|
||||||
|
FillTerminator();
|
||||||
|
}
|
||||||
|
#ifdef _DEBUG
|
||||||
|
~string_vs()
|
||||||
|
{
|
||||||
|
//if you hit the below asserts, the end of the string was overwritten
|
||||||
|
assert(mData[CAPACITY]=='e');
|
||||||
|
assert(mData[CAPACITY+1]=='n');
|
||||||
|
assert(mData[CAPACITY+2]=='d');
|
||||||
|
assert(mData[CAPACITY+3]==0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copy Constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
string_vs(const string_vs<CAPACITY> &o)
|
||||||
|
{
|
||||||
|
assert(str::len(o.mData)<CAPACITY);
|
||||||
|
str::ncpy(mData, o.mData, CAPACITY); // Safe String Copy
|
||||||
|
mData[CAPACITY-1] = 0; // Make Sure We Have A Null Terminated Str
|
||||||
|
FillTerminator();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copy Constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
string_vs(const char *s)
|
||||||
|
{
|
||||||
|
assert(str::len(s)<CAPACITY);
|
||||||
|
str::ncpy(mData, s, CAPACITY); // Safe String Copy
|
||||||
|
mData[CAPACITY-1] = 0; // Make Sure We Have A Null Terminated Str
|
||||||
|
FillTerminator();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
string_vs& operator=(const char *s)
|
||||||
|
{
|
||||||
|
assert(str::len(s)<CAPACITY);
|
||||||
|
str::ncpy(mData, s, CAPACITY); // Safe String Copy
|
||||||
|
mData[CAPACITY-1] = 0; // Make Sure We Have A Null Terminated Str
|
||||||
|
FillTerminator();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Access To Raw Array
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
char* c_str()
|
||||||
|
{
|
||||||
|
return mData;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Access To Raw Array
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const char* c_str() const
|
||||||
|
{
|
||||||
|
return mData;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Access To Raw Array
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
operator const char *()
|
||||||
|
{
|
||||||
|
return mData;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Access To Raw Array
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const char* operator*()
|
||||||
|
{
|
||||||
|
return mData;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// How Many Characters Can This Hold
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int capacity() const
|
||||||
|
{
|
||||||
|
return CAPACITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Length
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int length() const
|
||||||
|
{
|
||||||
|
assert(str::len(mData)<CAPACITY-1);
|
||||||
|
return str::len(mData);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Character Bracket Operator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
char operator[](int index)
|
||||||
|
{
|
||||||
|
assert(index<CAPACITY);
|
||||||
|
return mData[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Equality Operator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool operator==(const string_vs &o) const
|
||||||
|
{
|
||||||
|
if (!stricmp(mData,o.mData))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// InEquality Operator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool operator!=(const string_vs &o) const
|
||||||
|
{
|
||||||
|
if (str::icmp(mData,o.mData)!=0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Compare Less Than
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool operator<(const string_vs &o) const
|
||||||
|
{
|
||||||
|
if (str::icmp(mData,o.mData)<0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Compare Greater Than
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool operator>(const string_vs &o) const
|
||||||
|
{
|
||||||
|
if (str::icmp(mData,o.mData)>0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void operator+=(const string_vs &o)
|
||||||
|
{
|
||||||
|
if ( (str::len(mData)+o.length())<CAPACITY ) // Only If It Is Safe
|
||||||
|
{
|
||||||
|
str::cat(mData, o.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(!"string_vs overflow\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void operator+=(const char *s)
|
||||||
|
{
|
||||||
|
if ( (str::len(mData)+str::len(s))<CAPACITY ) // Only If It Is Safe
|
||||||
|
{
|
||||||
|
str::cat(mData, s);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(!"string_vs overflow\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Tokenizer
|
||||||
|
//
|
||||||
|
// The string tokenizer class is similar to an iterator in that it essentially
|
||||||
|
// iterates over all the tokens in the string seperated by a common series of
|
||||||
|
// delinating sequences. For example: " ,\t\n" would seperate tokens on spaces
|
||||||
|
// commas, tabs and linefeeds.
|
||||||
|
//
|
||||||
|
// Iterating over string tokens is just like normal iteration:
|
||||||
|
//
|
||||||
|
// for (string_vs<CAPACITY>::tokenizer it=MyString.begin(" ,\t\n"); it!=MyString.end(); it++)
|
||||||
|
// {
|
||||||
|
// const char* token = *it;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// NOTE: This class is built upon the c library function strtok() which uses a
|
||||||
|
// static working area, so having multiple tokenizers in multiple threads or just
|
||||||
|
// plain at the same time is not safe.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
class tokenizer
|
||||||
|
{
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
TOKEN_GAP_LEN = 15,
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructors
|
||||||
|
//--------------
|
||||||
|
tokenizer() : mLoc(0)
|
||||||
|
{}
|
||||||
|
tokenizer(const char* t, const char* gap)
|
||||||
|
{
|
||||||
|
strncpy(mGap, gap, TOKEN_GAP_LEN); // Safe String Copy
|
||||||
|
mGap[TOKEN_GAP_LEN-1] = 0; // Make Sure We Have A Null Terminated Str
|
||||||
|
|
||||||
|
char* temp = (char*)t;
|
||||||
|
mLoc = str::tok(temp, mGap);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assignment Operator
|
||||||
|
//---------------------
|
||||||
|
void operator= (const tokenizer &t)
|
||||||
|
{
|
||||||
|
mLoc = t.mLoc;
|
||||||
|
str::cpy(mGap, t.mGap);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equality Operators
|
||||||
|
//--------------------
|
||||||
|
bool operator==(const tokenizer &t) {return (mLoc==t.mLoc);}
|
||||||
|
bool operator!=(const tokenizer &t) {return !(operator==(t));}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// DeReference Operator
|
||||||
|
//----------------------
|
||||||
|
const char* operator*()
|
||||||
|
{
|
||||||
|
assert(mLoc);
|
||||||
|
return mLoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inc & Dec Operators
|
||||||
|
//--------------------
|
||||||
|
void operator++(int)
|
||||||
|
{
|
||||||
|
assert(mLoc && mGap[0]);
|
||||||
|
mLoc = str::tok(NULL, mGap);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data
|
||||||
|
//------
|
||||||
|
private:
|
||||||
|
char* mLoc;
|
||||||
|
char mGap[TOKEN_GAP_LEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get An Iterator To The First Token Seperated By Gap
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
tokenizer begin(const char* gap)
|
||||||
|
{
|
||||||
|
return tokenizer(mData, gap);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Invalid Iterator, Use As A Stop Condition In Your For Loops
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
tokenizer end()
|
||||||
|
{
|
||||||
|
return tokenizer();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//fixme get rid of these
|
||||||
|
typedef ratl::string_vs<256> TString_vs;
|
||||||
|
typedef ratl::string_vs<128> TUIString_vs;
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,757 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD TEMPLATE LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Vector
|
||||||
|
// ------
|
||||||
|
// The vector class is a simple addition to the array. It supports some useful additions
|
||||||
|
// like sort and binary search, as well as keeping track of the number of objects
|
||||||
|
// contained within.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// NOTES:
|
||||||
|
//
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_VECTOR_VS_INC)
|
||||||
|
#define RATL_VECTOR_VS_INC
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Includes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RATL_COMMON_INC)
|
||||||
|
#include "ratl_common.h"
|
||||||
|
#endif
|
||||||
|
namespace ratl
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Vector Class
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
template<class T>
|
||||||
|
class vector_base : public ratl_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename T TStorageTraits;
|
||||||
|
typedef typename T::TValue TTValue;
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Capacity Enum
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = T::CAPACITY
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
array_base<TStorageTraits> mArray; // The Memory
|
||||||
|
int mSize;
|
||||||
|
public:
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
vector_base()
|
||||||
|
{
|
||||||
|
mSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copy Constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
vector_base(const vector_base &B)
|
||||||
|
{
|
||||||
|
for (int i=0; i<B.size(); i++)
|
||||||
|
{
|
||||||
|
mArray[i] = B.mArray[i];
|
||||||
|
}
|
||||||
|
mSize = val.mSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// How Many Objects Can Be Added?
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int capacity() const
|
||||||
|
{
|
||||||
|
assert(mSize>=0&&mSize<=CAPACITY);
|
||||||
|
return (CAPACITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// How Many Objects Have Been Added To This Vector?
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int size() const
|
||||||
|
{
|
||||||
|
assert(mSize>=0&&mSize<=CAPACITY);
|
||||||
|
return (mSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Have Any Objects Have Been Added To This Vector?
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
assert(mSize>=0&&mSize<=CAPACITY);
|
||||||
|
return (!mSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Have Any Objects Have Been Added To This Vector?
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool full() const
|
||||||
|
{
|
||||||
|
assert(mSize>=0&&mSize<=CAPACITY);
|
||||||
|
return (mSize==CAPACITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Clear Out Entire Array
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
mArray.clear();
|
||||||
|
mSize = 0;
|
||||||
|
}
|
||||||
|
// Constant Access Operator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const TTValue& operator[](int index) const
|
||||||
|
{
|
||||||
|
assert(index>=0&&index<mSize);
|
||||||
|
return mArray[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Access Operator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TTValue& operator[](int index)
|
||||||
|
{
|
||||||
|
assert(index>=0&&index<mSize);
|
||||||
|
return mArray[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Access To The Raw Array Pointer
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TTValue * raw_array()
|
||||||
|
{
|
||||||
|
// this (intentionally) won't compile for anything except value semantics
|
||||||
|
// could be done with object semantics, but I would want to assert that all objects are contructed
|
||||||
|
return T::raw_array(mArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Access To The Raw Array Pointer
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const TTValue* raw_array() const
|
||||||
|
{
|
||||||
|
// this (intentionally) won't compile for anything except value semantics
|
||||||
|
// could be done with object semantics, but I would want to assert that all objects are contructed
|
||||||
|
return T::raw_array(mArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Assignment Operator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
vector_base& operator=(const vector_base& val)
|
||||||
|
{
|
||||||
|
for (int i=0; i<val.size(); i++)
|
||||||
|
{
|
||||||
|
mArray[i] = val.mArray[i];
|
||||||
|
}
|
||||||
|
mSize = val.mSize;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Add
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TTValue & push_back()
|
||||||
|
{
|
||||||
|
assert(mSize>=0&&mSize<CAPACITY);
|
||||||
|
mArray.construct(mSize);
|
||||||
|
mSize++;
|
||||||
|
return (mArray[mSize-1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Add (And Set)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void push_back(const TTValue& value)
|
||||||
|
{
|
||||||
|
assert(mSize>=0&&mSize<CAPACITY);
|
||||||
|
mArray.construct(mSize,value);
|
||||||
|
mSize++;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Add raw
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TRatlNew * push_back_raw()
|
||||||
|
{
|
||||||
|
assert(mSize>=0&&mSize<CAPACITY);
|
||||||
|
mSize++;
|
||||||
|
return mArray.alloc_raw(mSize-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Remove
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void pop_back()
|
||||||
|
{
|
||||||
|
assert(mSize>0);
|
||||||
|
mSize--;
|
||||||
|
mArray.destruct(mSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Resizes The Array. If New Elements Are Needed, It Uses The (value) Param
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void resize(int nSize, const TTValue& value)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=(mSize-1); i>=nSize; i--)
|
||||||
|
{
|
||||||
|
mArray.destruct(i);
|
||||||
|
mSize--;
|
||||||
|
}
|
||||||
|
for (i=mSize; i<nSize; i++)
|
||||||
|
{
|
||||||
|
mArray.construct(i,value);
|
||||||
|
}
|
||||||
|
mSize = nSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Resizes The Array. If New Elements Are Needed, It Uses The (value) Param
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void resize(int nSize)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=mSize-1; i>=nSize; i--)
|
||||||
|
{
|
||||||
|
mArray.destruct(i);
|
||||||
|
mSize--;
|
||||||
|
}
|
||||||
|
for (i=mSize; i<nSize; i++)
|
||||||
|
{
|
||||||
|
mArray.construct(i);
|
||||||
|
}
|
||||||
|
mSize = nSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Swap the values at two locations
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void swap(int i,int j)
|
||||||
|
{
|
||||||
|
assert(i<mSize && j<mSize);
|
||||||
|
mArray.swap(i, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Erase An Iterator Location... NOTE: THIS DOES NOT PRESERVE ORDER IN THE VECTOR!!
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void erase_swap(int Index)
|
||||||
|
{
|
||||||
|
assert(Index>=0 && Index<mSize);
|
||||||
|
if (Index != mSize - 1)
|
||||||
|
{
|
||||||
|
mArray.swap(Index, mSize - 1);
|
||||||
|
}
|
||||||
|
pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Binary Search
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int find_index(const TTValue& value) const
|
||||||
|
{
|
||||||
|
int base = 0;
|
||||||
|
int head = mSize-1;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
int searchAt = (base+head)/2;
|
||||||
|
|
||||||
|
if (base == head && searchAt == head)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value < mArray[searchAt])
|
||||||
|
{
|
||||||
|
head = searchAt-1;
|
||||||
|
}
|
||||||
|
else if (mArray[searchAt] < value)
|
||||||
|
{
|
||||||
|
base = searchAt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return searchAt;
|
||||||
|
}
|
||||||
|
if (head < base)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mSize; //not found!
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Heap Sort
|
||||||
|
//
|
||||||
|
// This sort algorithm has all the advantages of merge sort in terms of guarenteeing
|
||||||
|
// O(n log n) worst case, as well as all the advantages of quick sort in that it is
|
||||||
|
// "in place" and requires no additional storage.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void sort()
|
||||||
|
{
|
||||||
|
// Temporary Data
|
||||||
|
//----------------
|
||||||
|
int HeapSize; // How Large The Heap Is (Grows In PHASE 1, Shrinks In PHASE 2)
|
||||||
|
int Pos; // The Location We Are AT During "re-heapify" Loops
|
||||||
|
int Compare; // The Location We Are Comparing AGAINST During "re-heapify" Loops
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// PHASE 1, CONSTRUCT THE HEAP O(n log n)
|
||||||
|
//===============================================================================
|
||||||
|
for (HeapSize=1; HeapSize<mSize; HeapSize++)
|
||||||
|
{
|
||||||
|
// We Now Have An Element At Heap Size Which Is Not In It's Correct Place
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
Pos = HeapSize;
|
||||||
|
Compare = parent(Pos);
|
||||||
|
while (mArray[Compare]<mArray[Pos])
|
||||||
|
{
|
||||||
|
// Swap The Compare Element With The Pos Element
|
||||||
|
//-----------------------------------------------
|
||||||
|
mArray.swap(Compare, Pos);
|
||||||
|
|
||||||
|
// Move Pos To The Current Compare, And Recalc Compare
|
||||||
|
//------------------------------------------------------
|
||||||
|
Pos = Compare;
|
||||||
|
Compare = parent(Pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// PHASE 2, POP OFF THE TOP OF THE HEAP ONE AT A TIME (AND FIX) O(n log n)
|
||||||
|
//===============================================================================
|
||||||
|
for (HeapSize=(mSize-1); HeapSize>0; HeapSize--)
|
||||||
|
{
|
||||||
|
// Swap The End And Front Of The "Heap" Half Of The Array
|
||||||
|
//--------------------------------------------------------
|
||||||
|
mArray.swap(0, HeapSize);
|
||||||
|
|
||||||
|
// We Now Have A Bogus Element At The Root, So Fix The Heap
|
||||||
|
//----------------------------------------------------------
|
||||||
|
Pos = 0;
|
||||||
|
Compare = largest_child(Pos, HeapSize);
|
||||||
|
while (mArray[Pos]<mArray[Compare])
|
||||||
|
{
|
||||||
|
// Swap The Compare Element With The Pos Element
|
||||||
|
//-----------------------------------------------
|
||||||
|
mArray.swap(Compare, Pos);
|
||||||
|
|
||||||
|
// Move Pos To The Current Compare, And Recalc Compare
|
||||||
|
//------------------------------------------------------
|
||||||
|
Pos = Compare;
|
||||||
|
Compare = largest_child(Pos, HeapSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// THIS IS A QUICK VALIDATION OF A SORTED LIST
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#ifdef _DEBUG
|
||||||
|
void sort_validate() const
|
||||||
|
{
|
||||||
|
for (int a=0; a<(mSize-1); a++)
|
||||||
|
{
|
||||||
|
assert(mArray[a] < mArray[a+1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// For Heap Sort
|
||||||
|
// Returns The Location Of Node (i)'s Parent Node (The Parent Node Of Zero Is Zero)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
static int parent(int i)
|
||||||
|
{
|
||||||
|
return ((i-1)/2);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// For Heap Sort
|
||||||
|
// Returns The Location Of Node (i)'s Left Child (The Child Of A Leaf Is The Leaf)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
static int left(int i)
|
||||||
|
{
|
||||||
|
return ((2*i)+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// For Heap Sort
|
||||||
|
// Returns The Location Of Node (i)'s Right Child (The Child Of A Leaf Is The Leaf)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
static int right(int i)
|
||||||
|
{
|
||||||
|
return ((2*i)+2);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// For Heap Sort
|
||||||
|
// Returns The Location Of Largest Child Of Node (i)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int largest_child(int i, int Size) const
|
||||||
|
{
|
||||||
|
if (left(i)<Size)
|
||||||
|
{
|
||||||
|
if (right(i)<Size)
|
||||||
|
{
|
||||||
|
return ( (mArray[right(i)] < mArray[left(i)]) ? (left(i)) : (right(i)) );
|
||||||
|
}
|
||||||
|
return left(i); // Node i only has a left child, so by default it is the biggest
|
||||||
|
}
|
||||||
|
return i; // Node i is a leaf, so just return it
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
class const_iterator;
|
||||||
|
class iterator
|
||||||
|
{
|
||||||
|
friend class vector_base<T>;
|
||||||
|
friend class const_iterator;
|
||||||
|
// Data
|
||||||
|
//------
|
||||||
|
int mLoc;
|
||||||
|
vector_base<T>* mOwner;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructors
|
||||||
|
//--------------
|
||||||
|
iterator() : mOwner(0), mLoc(0)
|
||||||
|
{}
|
||||||
|
iterator(vector_base<T>* p, int t) : mOwner(p), mLoc(t)
|
||||||
|
{}
|
||||||
|
|
||||||
|
iterator(const iterator &t) : mOwner(t.mOwner), mLoc(t.mLoc)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Assignment Operator
|
||||||
|
//---------------------
|
||||||
|
void operator= (const iterator &t)
|
||||||
|
{
|
||||||
|
mOwner = t.mOwner;
|
||||||
|
mLoc = t.mLoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Equality Operators
|
||||||
|
//--------------------
|
||||||
|
bool operator!=(const iterator &t) const
|
||||||
|
{
|
||||||
|
return (mLoc!=t.mLoc || mOwner!=t.mOwner);
|
||||||
|
}
|
||||||
|
bool operator==(const iterator &t) const
|
||||||
|
{
|
||||||
|
return (mLoc==t.mLoc && mOwner==t.mOwner);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeReference Operator
|
||||||
|
//----------------------
|
||||||
|
TTValue& operator* () const
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<mOwner->mSize);
|
||||||
|
return (mOwner->mArray[mLoc]);
|
||||||
|
}
|
||||||
|
// DeReference Operator
|
||||||
|
//----------------------
|
||||||
|
TTValue& value() const
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<mOwner->mSize);
|
||||||
|
return (mOwner->mArray[mLoc]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeReference Operator
|
||||||
|
//----------------------
|
||||||
|
TTValue* operator-> () const
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<mOwner->mSize);
|
||||||
|
return (&mOwner->mArray[mLoc]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inc Operator
|
||||||
|
//--------------
|
||||||
|
iterator operator++(int) //postfix
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<mOwner->mSize);
|
||||||
|
iterator old(*this);
|
||||||
|
mLoc ++;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inc Operator
|
||||||
|
//--------------
|
||||||
|
iterator operator++()
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<mOwner->mSize);
|
||||||
|
mLoc ++;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constant Iterator
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
class const_iterator
|
||||||
|
{
|
||||||
|
friend class vector_base<T>;
|
||||||
|
|
||||||
|
int mLoc;
|
||||||
|
const vector_base<T>* mOwner;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructors
|
||||||
|
//--------------
|
||||||
|
const_iterator() : mOwner(0), mLoc(0)
|
||||||
|
{}
|
||||||
|
const_iterator(const vector_base<T>* p, int t) : mOwner(p), mLoc(t)
|
||||||
|
{}
|
||||||
|
const_iterator(const const_iterator &t) : mOwner(t.mOwner), mLoc(t.mLoc)
|
||||||
|
{}
|
||||||
|
const_iterator(const iterator &t) : mOwner(t.mOwner), mLoc(t.mLoc)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Assignment Operator
|
||||||
|
//---------------------
|
||||||
|
void operator= (const const_iterator &t)
|
||||||
|
{
|
||||||
|
mOwner = t.mOwner;
|
||||||
|
mLoc = t.mLoc;
|
||||||
|
}
|
||||||
|
// Assignment Operator
|
||||||
|
//---------------------
|
||||||
|
void operator= (const iterator &t)
|
||||||
|
{
|
||||||
|
mOwner = t.mOwner;
|
||||||
|
mLoc = t.mLoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Equality Operators
|
||||||
|
//--------------------
|
||||||
|
bool operator!=(const iterator &t) const
|
||||||
|
{
|
||||||
|
return (mLoc!=t.mLoc || mOwner!=t.mOwner);
|
||||||
|
}
|
||||||
|
bool operator==(const iterator &t) const
|
||||||
|
{
|
||||||
|
return (mLoc==t.mLoc && mOwner==t.mOwner);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equality Operators
|
||||||
|
//--------------------
|
||||||
|
bool operator!=(const const_iterator &t) const
|
||||||
|
{
|
||||||
|
return (mLoc!=t.mLoc || mOwner!=t.mOwner);
|
||||||
|
}
|
||||||
|
bool operator==(const const_iterator &t) const
|
||||||
|
{
|
||||||
|
return (mLoc==t.mLoc && mOwner==t.mOwner);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeReference Operator
|
||||||
|
//----------------------
|
||||||
|
const TTValue& operator* () const
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<mOwner->mSize);
|
||||||
|
return (mOwner->mArray[mLoc]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeReference Operator
|
||||||
|
//----------------------
|
||||||
|
const TTValue& value() const
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<mOwner->mSize);
|
||||||
|
return (mOwner->mArray[mLoc]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeReference Operator
|
||||||
|
//----------------------
|
||||||
|
const TTValue* operator-> () const
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<mOwner->mSize);
|
||||||
|
return (&mOwner->mArray[mLoc]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inc Operator
|
||||||
|
//--------------
|
||||||
|
const_iterator operator++(int)
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<mOwner->mSize);
|
||||||
|
const_iterator old(*this);
|
||||||
|
mLoc ++;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inc Operator
|
||||||
|
//--------------
|
||||||
|
const_iterator operator++()
|
||||||
|
{
|
||||||
|
assert(mLoc>=0 && mLoc<mOwner->mSize);
|
||||||
|
mLoc ++;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
friend class iterator;
|
||||||
|
friend class const_iterator;
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator Begin (Starts At Address 0)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
iterator begin()
|
||||||
|
{
|
||||||
|
return iterator(this, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator End (Set To Address mSize)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
iterator end()
|
||||||
|
{
|
||||||
|
return iterator(this, mSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator Begin (Starts At Address 0)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const_iterator begin() const
|
||||||
|
{
|
||||||
|
return const_iterator(this, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator End (Set To Address mSize)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const_iterator end() const
|
||||||
|
{
|
||||||
|
return const_iterator(this, mSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator Find (If Fails To Find, Returns iterator end()
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
iterator find(const TTValue& value)
|
||||||
|
{
|
||||||
|
int index = find_index(value); // Call Find By Index
|
||||||
|
if (index<mSize)
|
||||||
|
{
|
||||||
|
return iterator(this, index); // Found It, Return An Iterator To Index
|
||||||
|
}
|
||||||
|
return end(); // Return "end" Iterator If Not Found
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Iterator Find (If Fails To Find, Returns iterator end()
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const_iterator find(const TTValue& value) const
|
||||||
|
{
|
||||||
|
int index = find_index(value); // Call Find By Index
|
||||||
|
if (index<mSize)
|
||||||
|
{
|
||||||
|
return const_iterator(this, index); // Found It, Return An Iterator To Index
|
||||||
|
}
|
||||||
|
return end(); // Return "end" Iterator If Not Found
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Erase An Iterator Location... NOTE: THIS DOES NOT PRESERVE ORDER IN THE VECTOR!!
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
iterator erase_swap(const iterator &it)
|
||||||
|
{
|
||||||
|
assert(it.mLoc>=0 && it.mLoc<it.mOwner->mSize);
|
||||||
|
if (it.mLoc != mSize - 1)
|
||||||
|
{
|
||||||
|
mArray.swap(it.mLoc, mSize - 1);
|
||||||
|
}
|
||||||
|
pop_back();
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
template<class CAST_TO>
|
||||||
|
CAST_TO *verify_alloc(CAST_TO *p) const
|
||||||
|
{
|
||||||
|
return mArray.verify_alloc(p);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY>
|
||||||
|
class vector_vs : public vector_base<storage::value_semantics<T,ARG_CAPACITY> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::value_semantics<T,ARG_CAPACITY> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY
|
||||||
|
};
|
||||||
|
vector_vs() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY>
|
||||||
|
class vector_os : public vector_base<storage::object_semantics<T,ARG_CAPACITY> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::object_semantics<T,ARG_CAPACITY> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY
|
||||||
|
};
|
||||||
|
vector_os() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, int ARG_CAPACITY, int ARG_MAX_CLASS_SIZE>
|
||||||
|
class vector_is : public vector_base<storage::virtual_semantics<T,ARG_CAPACITY,ARG_MAX_CLASS_SIZE> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename storage::virtual_semantics<T,ARG_CAPACITY,ARG_MAX_CLASS_SIZE> TStorageTraits;
|
||||||
|
typedef typename TStorageTraits::TValue TTValue;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CAPACITY = ARG_CAPACITY,
|
||||||
|
MAX_CLASS_SIZE = ARG_MAX_CLASS_SIZE
|
||||||
|
};
|
||||||
|
vector_is() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
Binary file not shown.
|
@ -0,0 +1,366 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD TEMPLATE LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Vector Library
|
||||||
|
// --------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// NOTES:
|
||||||
|
// 05/31/02 - CREATED
|
||||||
|
//
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#if !defined(ASSERT_H_INC)
|
||||||
|
#include <assert.h>
|
||||||
|
#define ASSERT_H_INC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <float.h>
|
||||||
|
#include "CBounds.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/*void CBBox::ThroughMatrix(const CBBox &from, const CMatrix4 &mat)
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
CVec3 bb,t;
|
||||||
|
int i;
|
||||||
|
const CVec3 &xmn=from.GetMin();
|
||||||
|
const CVec3 &xmx=from.GetMax();
|
||||||
|
for ( i = 0; i < 8; i++ )
|
||||||
|
{
|
||||||
|
if ( i & 1 )
|
||||||
|
bb[0] = xmn[0];
|
||||||
|
else
|
||||||
|
bb[0] = xmx[0];
|
||||||
|
if ( i & 2 )
|
||||||
|
bb[1] = xmn[1];
|
||||||
|
else
|
||||||
|
bb[1] = xmx[1];
|
||||||
|
if ( i & 4 )
|
||||||
|
bb[2] = xmn[2];
|
||||||
|
else
|
||||||
|
bb[2] = xmx[2];
|
||||||
|
mat.XFormPoint(t,bb);
|
||||||
|
AddPoint(t);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
float CBBox::LargestAxisSize() const
|
||||||
|
{
|
||||||
|
CVec3 Work(mMax);
|
||||||
|
Work-=mMin;
|
||||||
|
return Work.MaxElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
float CBBox::DistanceEstimate(const CVec3 &p) const
|
||||||
|
{
|
||||||
|
float ret=0.0f;
|
||||||
|
|
||||||
|
// X Axis
|
||||||
|
//--------
|
||||||
|
if (p[0]>mMax[0])
|
||||||
|
{
|
||||||
|
ret=p[0]-mMax[0];
|
||||||
|
}
|
||||||
|
else if (p[0]<mMin[0])
|
||||||
|
{
|
||||||
|
ret=mMax[0]-p[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Y Axis
|
||||||
|
//--------
|
||||||
|
if (p[1]>mMax[1])
|
||||||
|
{
|
||||||
|
ret+=p[1]-mMax[1];
|
||||||
|
}
|
||||||
|
else if (p[1]<mMin[1])
|
||||||
|
{
|
||||||
|
ret+=mMax[1]-p[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Z Axis
|
||||||
|
//--------
|
||||||
|
if (p[2]>mMax[2])
|
||||||
|
{
|
||||||
|
ret+=p[2]-mMax[2];
|
||||||
|
}
|
||||||
|
else if (p[2]<mMin[2])
|
||||||
|
{
|
||||||
|
ret+=mMax[2]-p[2];
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
float CBBox::AreaEstimate(const CVec3 &p) const
|
||||||
|
{
|
||||||
|
float Distance=DistanceEstimate(p);
|
||||||
|
if (Distance)
|
||||||
|
{
|
||||||
|
return LargestAxisSize()/Distance;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CBBox::Intersect(const CBBox &b2)
|
||||||
|
{
|
||||||
|
mMin.Max(b2.mMin);
|
||||||
|
mMax.Min(b2.mMax);
|
||||||
|
Validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CBBox::Union(const CBBox &b2)
|
||||||
|
{
|
||||||
|
mMin.Min(b2.mMin);
|
||||||
|
mMax.Max(b2.mMax);
|
||||||
|
Validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
ESide CBBox::InOutTest(const CVec3 &v) const
|
||||||
|
{
|
||||||
|
if (v>mMin && v<mMax)
|
||||||
|
{
|
||||||
|
return Side_In;
|
||||||
|
}
|
||||||
|
return Side_Out;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
ESide CBBox::InOutTest(const CVec3 &v,float tolout,float tolin) const
|
||||||
|
{
|
||||||
|
if (v[0]<mMin[0]-tolout||v[0]>mMax[0]+tolout||
|
||||||
|
v[1]<mMin[1]-tolout||v[1]>mMax[1]+tolout||
|
||||||
|
v[2]<mMin[2]-tolout||v[2]>mMax[2]+tolout)
|
||||||
|
{
|
||||||
|
return Side_Out;
|
||||||
|
}
|
||||||
|
if (v[0]>mMin[0]+tolin&&v[0]<mMax[0]-tolin&&
|
||||||
|
v[1]>mMin[1]+tolin&&v[1]<mMax[1]-tolin&&
|
||||||
|
v[2]>mMin[2]+tolin&&v[2]<mMax[2]-tolin)
|
||||||
|
{
|
||||||
|
return Side_In;
|
||||||
|
}
|
||||||
|
return Side_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CBBox::BoxTouchTest(const CBBox &b2,float tolout) const
|
||||||
|
{
|
||||||
|
if (mMin[0]-tolout>b2.mMax[0] ||
|
||||||
|
mMin[1]-tolout>b2.mMax[1] ||
|
||||||
|
mMin[2]-tolout>b2.mMax[2] ||
|
||||||
|
b2.mMin[0]-tolout>mMax[0] ||
|
||||||
|
b2.mMin[1]-tolout>mMax[1] ||
|
||||||
|
b2.mMin[2]-tolout>mMax[2])
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CBBox::SphereTouchTest(const CVec3 &v,float rad) const
|
||||||
|
{
|
||||||
|
if (v[0]<mMin[0]-rad||v[0]>mMax[0]+rad||
|
||||||
|
v[1]<mMin[1]-rad||v[1]>mMax[1]+rad||
|
||||||
|
v[2]<mMin[2]-rad||v[2]>mMax[2]+rad)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TPlanes CBBox::PlaneFlags(const CVec3 &p)
|
||||||
|
{
|
||||||
|
TPlanes ret=0;
|
||||||
|
if (p[0]<mMin[0])
|
||||||
|
{
|
||||||
|
ret|=1;
|
||||||
|
}
|
||||||
|
else if (p[0]>mMax[0])
|
||||||
|
{
|
||||||
|
ret|=2;
|
||||||
|
}
|
||||||
|
if (p[1]<mMin[1])
|
||||||
|
{
|
||||||
|
ret|=4;
|
||||||
|
}
|
||||||
|
else if (p[1]>mMax[1])
|
||||||
|
{
|
||||||
|
ret|=8;
|
||||||
|
}
|
||||||
|
if (p[2]<mMin[2])
|
||||||
|
{
|
||||||
|
ret|=16;
|
||||||
|
}
|
||||||
|
else if (p[2]>mMax[2])
|
||||||
|
{
|
||||||
|
ret|=32;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// return true if the segment intersect the box, in that case, return the first contact.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CBBox::HitTest(CBTrace& Tr) const
|
||||||
|
{
|
||||||
|
// Quick Box Cull
|
||||||
|
//----------------
|
||||||
|
CBBox tmp;
|
||||||
|
tmp.AddPoint(Tr.mStart);
|
||||||
|
tmp.AddPoint(Tr.mStop);
|
||||||
|
if (!BoxTouchTest(tmp))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Initialize Our Ranges
|
||||||
|
//-----------------------
|
||||||
|
Tr.mRange =-1E30f;
|
||||||
|
Tr.mRangeMax = 1E30f;
|
||||||
|
|
||||||
|
|
||||||
|
// For Each Non Zero Axis Of The Aim Vector
|
||||||
|
//------------------------------------------
|
||||||
|
float tmax,tmin,temp;
|
||||||
|
for (int axis=0; axis<3; axis++)
|
||||||
|
{
|
||||||
|
if (fabs(Tr.mAim[axis])>1E-6f)
|
||||||
|
{
|
||||||
|
// Find Mins And Maxs From The Start Along The Axis Of Aim
|
||||||
|
//---------------------------------------------------------
|
||||||
|
tmax = ((mMax[axis]-Tr.mStart[axis])/Tr.mAim[axis]);
|
||||||
|
tmin = ((mMin[axis]-Tr.mStart[axis])/Tr.mAim[axis]);
|
||||||
|
if (tmax<tmin)
|
||||||
|
{
|
||||||
|
temp = tmax;
|
||||||
|
tmax = tmin;
|
||||||
|
tmin = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust Range Max
|
||||||
|
//------------------
|
||||||
|
if (tmax<Tr.mRangeMax)
|
||||||
|
{
|
||||||
|
Tr.mRangeMax=tmax;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust Range Min
|
||||||
|
//------------------
|
||||||
|
if (tmin>Tr.mRange)
|
||||||
|
{
|
||||||
|
Tr.mRange=tmin;
|
||||||
|
Tr.mNormal.Clear();
|
||||||
|
Tr.mNormal[axis]=-1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Missed?
|
||||||
|
//---------
|
||||||
|
if (Tr.mRangeMax<Tr.mRange || Tr.mRangeMax<0.0f || Tr.mRange>Tr.mLength)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Start Solid Conditions
|
||||||
|
//------------------------
|
||||||
|
if (Tr.mRange<0.0f)
|
||||||
|
{
|
||||||
|
Tr.mRange = 0.0f;
|
||||||
|
Tr.mPoint = Tr.mStart;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Calculate The End Point
|
||||||
|
//-------------------------
|
||||||
|
Tr.mPoint = Tr.mAim;
|
||||||
|
Tr.mPoint *= Tr.mRange;
|
||||||
|
Tr.mPoint += Tr.mStart;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CBBox::FromStr(const char *s)
|
||||||
|
{
|
||||||
|
assert(s && s[0]);
|
||||||
|
|
||||||
|
char MinS[256];
|
||||||
|
char MaxS[266];
|
||||||
|
sscanf(s, "(%s|%s)", MinS, MaxS);
|
||||||
|
|
||||||
|
mMin.FromStr(MinS);
|
||||||
|
mMax.FromStr(MaxS);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CBBox::ToStr(char* s)
|
||||||
|
{
|
||||||
|
assert(s && s[0]);
|
||||||
|
|
||||||
|
char MinS[256];
|
||||||
|
char MaxS[266];
|
||||||
|
|
||||||
|
mMin.ToStr(MinS);
|
||||||
|
mMax.ToStr(MaxS);
|
||||||
|
sprintf(s, "(%s|%s)", MinS, MaxS);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CBBox::Validate()
|
||||||
|
{
|
||||||
|
assert(mMax>=mMin);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,188 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD TEMPLATE LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Vector Library
|
||||||
|
// --------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// NOTES:
|
||||||
|
// 05/31/02 - CREATED
|
||||||
|
//
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RAVL_BOUNDS_INC)
|
||||||
|
#define RAVL_BOUNDS_INC
|
||||||
|
//namespace ravl
|
||||||
|
//{
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Includes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#include "CVec.h"
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Defines
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#define RAVL_BB_EMPTY_MIN ( 1.234567E30f) // Empty Value
|
||||||
|
#define RAVL_BB_EMPTY_MAX (-1.234567E30f) // Empty Value
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Enums And Typedefs
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
typedef unsigned char TPlanes;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Bounds Trace
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
class CBTrace
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CBTrace(const CVec3& Start, const CVec3& Stop) :
|
||||||
|
mStart(Start),
|
||||||
|
mStop(Stop),
|
||||||
|
mAim(Stop),
|
||||||
|
mRange(0),
|
||||||
|
mRangeMax(0),
|
||||||
|
mPoint(Stop)
|
||||||
|
{
|
||||||
|
mAim-=Start;
|
||||||
|
mLength = mAim.Norm();
|
||||||
|
}
|
||||||
|
|
||||||
|
CBTrace& operator =(const CBTrace& T)
|
||||||
|
{
|
||||||
|
mStart = (T.mStart);
|
||||||
|
mStop = (T.mStop);
|
||||||
|
mAim = (T.mAim);
|
||||||
|
mRange = (T.mRange);
|
||||||
|
mRangeMax = (T.mRangeMax);
|
||||||
|
mPoint = (T.mPoint);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Setup Values, Do Not Change
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
public:
|
||||||
|
CVec3 mStart;
|
||||||
|
CVec3 mStop;
|
||||||
|
CVec3 mAim;
|
||||||
|
float mLength;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Results
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
public:
|
||||||
|
float mRange;
|
||||||
|
float mRangeMax;
|
||||||
|
CVec3 mPoint;
|
||||||
|
CVec3 mNormal;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Bounding Box Class
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
class CBBox
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructors
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
CBBox() {mMin.Set(RAVL_BB_EMPTY_MIN); mMax.Set(RAVL_BB_EMPTY_MAX);}
|
||||||
|
CBBox(float Radius) {mMin.Set(-Radius); mMax.Set(Radius);}
|
||||||
|
CBBox(const CVec3& t) {mMin=t; mMax=t;}
|
||||||
|
CBBox(const CVec3& min, const CVec3& max) {mMin=min; mMax=max;}
|
||||||
|
CBBox(const CBBox& t) {mMin=t.mMin; mMax=t.mMax;}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Initializers
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void Set(const CVec3& min, const CVec3& max) {mMin=min; mMax=max; Validate();}
|
||||||
|
void Clear() {mMin.Set(RAVL_BB_EMPTY_MIN); mMax.Set(RAVL_BB_EMPTY_MAX);}
|
||||||
|
void AddPoint(const CVec3 &p) {mMin.Min(p); mMax.Max(p); Validate();}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Accessors
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool IsEmpty() const {return (mMin[0]==RAVL_BB_EMPTY_MIN);}
|
||||||
|
CVec3 Center() const {return (mMin+mMax)*0.5;}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Translation, Rotation, Expansion
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void Translate(const CVec3 &f) {mMin+=f; mMax+=f;}
|
||||||
|
void Expand(float x) {mMin-=x; mMax+=x;}
|
||||||
|
void Expand(const CVec3 &f) {mMin-=f; mMax+=f;}
|
||||||
|
// void ThroughMatrix(const CBBox &from, const CMatrix4 &mat);
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Volumetric & Area Operations
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
float Volume() const {return (mMax[0]-mMin[0])*(mMax[1]-mMin[1])*(mMax[2]-mMin[2]);}
|
||||||
|
float AxisSize(int axis) const {return (mMax[axis]-mMin[axis]);}
|
||||||
|
float LargestAxisSize() const;
|
||||||
|
float DistanceEstimate(const CVec3 &p) const; // Manhattan Distance
|
||||||
|
float AreaEstimate(const CVec3 &p) const; // Manhattan Distance * LargestAxisSize()
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Set Operations
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void Intersect(const CBBox &b2);
|
||||||
|
void Union(const CBBox &b2);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Tests
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
ESide InOutTest(const CVec3 &p) const;
|
||||||
|
ESide InOutTest(const CVec3 &p, float tolout, float tolin) const;
|
||||||
|
bool BoxTouchTest(const CBBox &b2, float tolout=0.0f) const;
|
||||||
|
bool SphereTouchTest(const CVec3 &c, float rad) const;
|
||||||
|
TPlanes PlaneFlags(const CVec3 &p);
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Hit Tests
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool HitTest(CBTrace& Tr) const;
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// String Operations
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void FromStr(const char *s);
|
||||||
|
void ToStr(char* s);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Debug Operations
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void Validate();
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Data
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
public:
|
||||||
|
CVec3 mMin;
|
||||||
|
CVec3 mMax;
|
||||||
|
};
|
||||||
|
|
||||||
|
//};
|
||||||
|
#endif
|
|
@ -0,0 +1,165 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD TEMPLATE LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Matrix Library
|
||||||
|
// --------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// NOTES:
|
||||||
|
//
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RAVL_MATRIX_INC)
|
||||||
|
#define RAVL_MATRIX_INC
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Includes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if defined(RA_DEBUG_LINKING)
|
||||||
|
#pragma message("...including CMatrix.h")
|
||||||
|
#endif
|
||||||
|
#if !defined(RAVL_VEC_INC)
|
||||||
|
#include "CVec.h"
|
||||||
|
#endif
|
||||||
|
//namespace ravl
|
||||||
|
//{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Matrix
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
class CMatrix
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructors
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
CMatrix() {}
|
||||||
|
CMatrix(const CVec4& x,const CVec4& y,const CVec4& z, const CVec4& w) {v[0]=x; v[1]=y; v[2]=z; v[3]=w;}
|
||||||
|
CMatrix(const CMatrix& t) {v[0]=t.v[0]; v[1]=t.v[1]; v[2]=t.v[2]; v[3]=t.v[3];}
|
||||||
|
CMatrix(const float t[16]) {v[0]=t[0]; v[1]=t[4]; v[2]=t[8]; v[3]=t[12];}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Initializers
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void Set(const CVec4& x,const CVec4& y,const CVec4& z, const CVec4& w) {v[0]=x; v[1]=y; v[2]=z; v[3]=w;}
|
||||||
|
void Set(const CMatrix& t) {v[0]=t.v[0]; v[1]=t.v[1]; v[2]=t.v[2]; v[3]=t.v[3];}
|
||||||
|
void Set(const float t[16]) {v[0]=t[0]; v[1]=t[4]; v[2]=t[8]; v[3]=t[12];}
|
||||||
|
|
||||||
|
void Clear() {v[0].Set(0,0,0,0); v[1].Set(0,0,0,0); v[2].Set(0,0,0,0); v[3].Set(0,0,0,0);}
|
||||||
|
void Itentity() {v[0].Set(1,0,0,0); v[1].Set(0,1,0,0); v[2].Set(0,0,1,0); v[3].Set(0,0,0,1);}
|
||||||
|
void Translate(const float x, const float y, const float z) {v[0].Set(1,0,0,0); v[1].Set(0,1,0,0); v[2].Set(0,0,1,0); v[3].Set(x,y,z,1);}
|
||||||
|
void Scale(const float x, const float y, const float z) {v[0].Set(x,0,0,0); v[1].Set(0,y,0,0); v[2].Set(0,0,z,0); v[3].Set(0,0,0,1);}
|
||||||
|
void Rotate(int axis, const float s/*sin(angle)*/, const float c/*cos(angle)*/)
|
||||||
|
{
|
||||||
|
switch(axis)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
v[0].Set( 1, 0, 0, 0);
|
||||||
|
v[1].Set( 0, c,-s, 0);
|
||||||
|
v[2].Set( 0, s, c, 0);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
v[0].Set( c, 0, s, 0);
|
||||||
|
v[1].Set( 0, 1, 0, 0);
|
||||||
|
v[2].Set(-s, 0, c, 0);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
v[0].Set( c,-s, 0, 0);
|
||||||
|
v[1].Set( s, c, 0, 0);
|
||||||
|
v[2].Set( 0, 0, 1, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
v[3].Set( 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Member Accessors
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const CVec4& operator[](int i) const {return v[i];}
|
||||||
|
CVec4& operator[](int i) {return v[i];}
|
||||||
|
|
||||||
|
CVec4& up() {return v[0];}
|
||||||
|
CVec4& left() {return v[1];}
|
||||||
|
CVec4& fwd() {return v[2];}
|
||||||
|
CVec4& origin() {return v[3];}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Equality / Inequality Operators
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool operator== (const CMatrix& t) const {return (v[0]==t.v[0] && v[1]==t.v[1] && v[2]==t.v[2] && v[3]==t.v[3]);}
|
||||||
|
bool operator!= (const CMatrix& t) const {return !(v[0]==t.v[0] && v[1]==t.v[1] && v[2]==t.v[2] && v[3]==t.v[3]);}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Basic Arithimitic Operators
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const CMatrix &operator= (const CMatrix& t) {v[0]=t.v[0]; v[1]=t.v[1]; v[2]=t.v[2]; v[3]=t.v[3]; return *this;}
|
||||||
|
const CMatrix &operator+= (const CMatrix& t) {v[0]+=t.v[0]; v[1]+=t.v[1]; v[2]+=t.v[2]; v[3]+=t.v[3];return *this;}
|
||||||
|
const CMatrix &operator-= (const CMatrix& t) {v[0]-=t.v[0]; v[1]-=t.v[1]; v[2]-=t.v[2]; v[3]-=t.v[3];return *this;}
|
||||||
|
|
||||||
|
CMatrix operator+ (const CMatrix &t) const {return CMatrix(v[0]+t.v[0], v[1]+t.v[1], v[2]+t.v[2], v[3]+t.v[3]);}
|
||||||
|
CMatrix operator- (const CMatrix &t) const {return CMatrix(v[0]-t.v[0], v[1]-t.v[1], v[2]-t.v[2], v[3]-t.v[3]);}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Matrix Scale
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const CMatrix &operator*= (const float d) {v[0]*=d; v[1]*=d; v[2]*=d; v[3]*=d; return *this;}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Matrix To Matrix Multiply
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
CMatrix operator* (const CMatrix &t) const
|
||||||
|
{
|
||||||
|
// assert(this!=&t); // Don't Multiply With Self
|
||||||
|
|
||||||
|
CMatrix Result; // The Resulting Matrix
|
||||||
|
int i,j,k; // Counters
|
||||||
|
float Accumulator; // Current Value Of The Dot Product
|
||||||
|
for (i=0; i<4; i++)
|
||||||
|
{
|
||||||
|
for (j=0; j<4; j++)
|
||||||
|
{
|
||||||
|
Accumulator = 0.0f; // Reset The Accumulator
|
||||||
|
for(k=0; k<4; k++)
|
||||||
|
{
|
||||||
|
Accumulator += v[i][k]*t[k][j]; // Calculate Dot Product Of The Two Vectors
|
||||||
|
}
|
||||||
|
Result[i][j]=Accumulator; // Place In Result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Vector To Matrix Multiply
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
CVec4 operator* (const CVec4 &t) const
|
||||||
|
{
|
||||||
|
CVec4 Result;
|
||||||
|
|
||||||
|
Result[0] = v[0][0]*t[0] + v[1][0]*t[1] + v[2][0]*t[2] + v[3][0];
|
||||||
|
Result[1] = v[0][1]*t[0] + v[1][1]*t[1] + v[2][1]*t[2] + v[3][1];
|
||||||
|
Result[2] = v[0][2]*t[0] + v[1][2]*t[1] + v[2][2]*t[2] + v[3][2];
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
CVec4 v[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//}
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
@ -0,0 +1,378 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD USEFUL FUNCTION LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Handle File
|
||||||
|
// -----------
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Includes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#include "hfile.h"
|
||||||
|
#if !defined(RATL_HANDLE_POOL_VS_INC)
|
||||||
|
#include "..\Ratl\handle_pool_vs.h"
|
||||||
|
#endif
|
||||||
|
#if !defined(RATL_VECTOR_VS_INC)
|
||||||
|
#include "..\Ratl\vector_vs.h"
|
||||||
|
#endif
|
||||||
|
#if !defined(RUFL_HSTRING_INC)
|
||||||
|
#include "hstring.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extern bool HFILEopen_read(int& handle, const char* filepath);
|
||||||
|
extern bool HFILEopen_write(int& handle, const char* filepath);
|
||||||
|
extern bool HFILEread(int& handle, void* data, int size);
|
||||||
|
extern bool HFILEwrite(int& handle, const void* data, int size);
|
||||||
|
extern bool HFILEclose(int& handle);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Defines
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#define MAX_OPEN_FILES 20
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
struct SOpenFile
|
||||||
|
{
|
||||||
|
#ifdef _XBOX
|
||||||
|
dllNamespace::hstring mPath;
|
||||||
|
#else
|
||||||
|
hstring mPath;
|
||||||
|
#endif
|
||||||
|
bool mForRead;
|
||||||
|
int mHandle;
|
||||||
|
float mVersion;
|
||||||
|
int mChecksum;
|
||||||
|
};
|
||||||
|
typedef ratl::handle_pool_vs<SOpenFile, MAX_OPEN_FILES> TFilePool;
|
||||||
|
|
||||||
|
TFilePool& Pool()
|
||||||
|
{
|
||||||
|
static TFilePool TFP;
|
||||||
|
return TFP;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor
|
||||||
|
//
|
||||||
|
// Allocates a new OpenFile structure and initializes it. DOES NOT OPEN!
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
hfile::hfile(const char* file)
|
||||||
|
{
|
||||||
|
if (Pool().full())
|
||||||
|
{
|
||||||
|
mHandle = 0;
|
||||||
|
assert("HFILE: Too Many Files Open, Unable To Grab An Unused Handle"==0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mHandle = Pool().alloc();
|
||||||
|
|
||||||
|
SOpenFile& sfile = Pool()[mHandle];
|
||||||
|
|
||||||
|
sfile.mPath = file;
|
||||||
|
sfile.mHandle = 0;
|
||||||
|
sfile.mForRead = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Destructor
|
||||||
|
//
|
||||||
|
// Releases the open file structure for resue. Also closes the file if open.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
hfile::~hfile()
|
||||||
|
{
|
||||||
|
if (is_open())
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mHandle && Pool().is_used(mHandle))
|
||||||
|
{
|
||||||
|
Pool().free(mHandle);
|
||||||
|
}
|
||||||
|
mHandle = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool hfile::is_open(void) const
|
||||||
|
{
|
||||||
|
if (mHandle && Pool().is_used(mHandle))
|
||||||
|
{
|
||||||
|
return (Pool()[mHandle].mHandle!=0);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool hfile::is_open_for_read(void) const
|
||||||
|
{
|
||||||
|
if (mHandle && Pool().is_used(mHandle))
|
||||||
|
{
|
||||||
|
SOpenFile& sfile = Pool()[mHandle];
|
||||||
|
return (sfile.mHandle!=0 && sfile.mForRead);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool hfile::is_open_for_write(void) const
|
||||||
|
{
|
||||||
|
if (mHandle && Pool().is_used(mHandle))
|
||||||
|
{
|
||||||
|
SOpenFile& sfile = Pool()[mHandle];
|
||||||
|
return (sfile.mHandle!=0 && !sfile.mForRead);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool hfile::open(float version, int checksum, bool read)
|
||||||
|
{
|
||||||
|
// Make Sure This Is A Valid Handle
|
||||||
|
//----------------------------------
|
||||||
|
if (!mHandle || !Pool().is_used(mHandle))
|
||||||
|
{
|
||||||
|
assert("HFILE: Invalid Handle"==0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make Sure The File Is Not ALREADY Open
|
||||||
|
//----------------------------------------
|
||||||
|
SOpenFile& sfile = Pool()[mHandle];
|
||||||
|
if (sfile.mHandle!=0)
|
||||||
|
{
|
||||||
|
assert("HFILE: Attempt To Open An Already Open File"==0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sfile.mForRead = read;
|
||||||
|
if (read)
|
||||||
|
{
|
||||||
|
HFILEopen_read(sfile.mHandle, *sfile.mPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HFILEopen_write(sfile.mHandle, *sfile.mPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If The Open Failed, Report It And Free The SOpenFile
|
||||||
|
//------------------------------------------------------
|
||||||
|
if (sfile.mHandle==0)
|
||||||
|
{
|
||||||
|
if (!read)
|
||||||
|
{
|
||||||
|
assert("HFILE: Unable To Open File"==0);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Read The File's Header
|
||||||
|
//------------------------
|
||||||
|
if (read)
|
||||||
|
{
|
||||||
|
if (!HFILEread(sfile.mHandle, &sfile.mVersion, sizeof(sfile.mVersion)))
|
||||||
|
{
|
||||||
|
assert("HFILE: Unable To Read File Header"==0);
|
||||||
|
close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!HFILEread(sfile.mHandle, &sfile.mChecksum, sizeof(sfile.mChecksum)))
|
||||||
|
{
|
||||||
|
assert("HFILE: Unable To Read File Header"==0);
|
||||||
|
close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make Sure The Checksum & Version Match
|
||||||
|
//----------------------------------------
|
||||||
|
if (sfile.mVersion!=version || sfile.mChecksum!=checksum)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
return false; // Failed To Match Checksum Or Version Number -> Old Data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sfile.mVersion = version;
|
||||||
|
sfile.mChecksum = checksum;
|
||||||
|
|
||||||
|
if (!HFILEwrite(sfile.mHandle, &sfile.mVersion, sizeof(sfile.mVersion)))
|
||||||
|
{
|
||||||
|
assert("HFILE: Unable To Write File Header"==0);
|
||||||
|
close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!HFILEwrite(sfile.mHandle, &sfile.mChecksum, sizeof(sfile.mChecksum)))
|
||||||
|
{
|
||||||
|
assert("HFILE: Unable To Write File Header"==0);
|
||||||
|
close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool hfile::close()
|
||||||
|
{
|
||||||
|
if (!mHandle || !Pool().is_used(mHandle))
|
||||||
|
{
|
||||||
|
assert("HFILE: Invalid Handle"==0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SOpenFile& sfile = Pool()[mHandle];
|
||||||
|
if (sfile.mHandle==0)
|
||||||
|
{
|
||||||
|
assert("HFILE: Unable TO Close Unopened File"==0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!HFILEclose(sfile.mHandle))
|
||||||
|
{
|
||||||
|
sfile.mHandle = 0;
|
||||||
|
assert("HFILE: Unable To Close File"==0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sfile.mHandle = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Searches for the first block with the matching data size, and reads it in.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool hfile::load(void* data, int datasize)
|
||||||
|
{
|
||||||
|
// Go Ahead And Open The File For Reading
|
||||||
|
//----------------------------------------
|
||||||
|
bool auto_opened = false;
|
||||||
|
if (!is_open())
|
||||||
|
{
|
||||||
|
if (!open_read())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto_opened = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make Sure That The File Is Readable
|
||||||
|
//-------------------------------------
|
||||||
|
SOpenFile& sfile = Pool()[mHandle];
|
||||||
|
if (!sfile.mForRead)
|
||||||
|
{
|
||||||
|
assert("HFILE: Unable to load from a file that is opened for save"==0);
|
||||||
|
if (auto_opened)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Now Read It
|
||||||
|
//-------------
|
||||||
|
if (!HFILEread(sfile.mHandle, data, datasize))
|
||||||
|
{
|
||||||
|
assert("HFILE: Unable To Read Object"==0);
|
||||||
|
if (auto_opened)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success!
|
||||||
|
//----------
|
||||||
|
if (auto_opened)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool hfile::save(void* data, int datasize)
|
||||||
|
{
|
||||||
|
// Go Ahead And Open The File For Reading
|
||||||
|
//----------------------------------------
|
||||||
|
bool auto_opened = false;
|
||||||
|
if (!is_open())
|
||||||
|
{
|
||||||
|
if (!open_write())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto_opened = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make Sure That The File Is Readable
|
||||||
|
//-------------------------------------
|
||||||
|
SOpenFile& sfile = Pool()[mHandle];
|
||||||
|
if (sfile.mForRead)
|
||||||
|
{
|
||||||
|
assert("HFILE: Unable to save to a file that is opened for read"==0);
|
||||||
|
if (auto_opened)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Write The Actual Object
|
||||||
|
//-------------------------
|
||||||
|
if (!HFILEwrite(sfile.mHandle, data, datasize))
|
||||||
|
{
|
||||||
|
assert("HFILE: Unable To Write File Data"==0);
|
||||||
|
if (auto_opened)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto_opened)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD USEFUL FUNCTION LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Handle File
|
||||||
|
// -----------
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RUFL_HFILE_INC)
|
||||||
|
#define RUFL_HFILE_INC
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// HFile Bindings
|
||||||
|
//
|
||||||
|
// These are the standard C hfile bindings, copy these function wrappers to your .cpp
|
||||||
|
// before including hfile, and modify them if needed to support a different file
|
||||||
|
// system.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//bool HFILEopen_read(int& handle, const char* filepath) {handle=(int)fopen(filepath, "rb"); return (handle!=0);}
|
||||||
|
//bool HFILEopen_write(int& handle, const char* filepath) {handle=(int)fopen(filepath, "wb"); return (handle!=0);}
|
||||||
|
//bool HFILEread(int& handle, void* data, int size) {return (fread(data, size, 1, (FILE*)(handle))>0);}
|
||||||
|
//bool HFILEwrite(int& handle, const void* data, int size) {return (fwrite(data, size, 1, (FILE*)(handle))>0);}
|
||||||
|
//bool HFILEclose(int& handle) {return (fclose((FILE*)handle)==0);}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Handle String Class
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
class hfile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructors
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
hfile(const char *file);
|
||||||
|
~hfile();
|
||||||
|
|
||||||
|
bool load(void* data, int datasize);
|
||||||
|
bool save(void* data, int datasize);
|
||||||
|
|
||||||
|
bool is_open(void) const;
|
||||||
|
bool is_open_for_read(void) const;
|
||||||
|
bool is_open_for_write(void) const;
|
||||||
|
|
||||||
|
bool open_read(float version=1.0f, int checksum=0) {return open(version, checksum, true);}
|
||||||
|
bool open_write(float version=1.0f, int checksum=0) {return open(version, checksum, false);}
|
||||||
|
|
||||||
|
bool close();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool open(float version, int checksum, bool read);
|
||||||
|
|
||||||
|
|
||||||
|
int mHandle;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // hfile_H
|
|
@ -0,0 +1,185 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD USEFUL FUNCTION LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Handle String
|
||||||
|
// -------------
|
||||||
|
// Handle strings are allocated once in a static buffer (with a hash index), and are
|
||||||
|
// never cleared out. You should use these for very common string names which are
|
||||||
|
// redundant or intended to last a long time.
|
||||||
|
//
|
||||||
|
// Handle strings are also good for comparison and storage because they compare only
|
||||||
|
// the handles, which are simple unique integers.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Includes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#include "hstring.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include "..\Ratl\hash_pool_vs.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Defines
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#define MAX_HASH 16384 // How Many Hash
|
||||||
|
#define BLOCK_SIZE 65536 // Size of a string storage block in bytes.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Hash Pool
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
typedef ratl::hash_pool<BLOCK_SIZE, MAX_HASH> TStrPool;
|
||||||
|
|
||||||
|
|
||||||
|
TStrPool& Pool()
|
||||||
|
{
|
||||||
|
static TStrPool TSP;
|
||||||
|
return TSP;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _XBOX
|
||||||
|
namespace dllNamespace
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
hstring::hstring()
|
||||||
|
{
|
||||||
|
mHandle = 0;
|
||||||
|
#ifdef _DEBUG
|
||||||
|
mStr = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
hstring::hstring(const char *str)
|
||||||
|
{
|
||||||
|
init(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
hstring::hstring(const hstring &str)
|
||||||
|
{
|
||||||
|
mHandle = str.mHandle;
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
mStr = str.mStr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Assignment
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
hstring& hstring::operator= (const char *str)
|
||||||
|
{
|
||||||
|
init(str);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
hstring& hstring::operator= (const hstring &str)
|
||||||
|
{
|
||||||
|
mHandle = str.mHandle;
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
mStr = str.mStr;
|
||||||
|
#endif
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const char* hstring::c_str(void) const
|
||||||
|
{
|
||||||
|
if (!mHandle)
|
||||||
|
{
|
||||||
|
return("");
|
||||||
|
}
|
||||||
|
return ((const char*)Pool()[mHandle]);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const char* hstring::operator *(void) const
|
||||||
|
{
|
||||||
|
return c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int hstring::length() const
|
||||||
|
{
|
||||||
|
return strlen(c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int hstring::handle() const
|
||||||
|
{
|
||||||
|
return mHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void hstring::init(const char *str)
|
||||||
|
{
|
||||||
|
if (!str)
|
||||||
|
{
|
||||||
|
mHandle = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mHandle = Pool().get_handle(str, strlen(str)+1); // +1 for null character
|
||||||
|
}
|
||||||
|
#ifdef _DEBUG
|
||||||
|
mStr = (char*)Pool()[mHandle];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#ifdef _DEBUG
|
||||||
|
float hstring::ave_collisions() {return Pool().average_collisions();}
|
||||||
|
int hstring::total_strings() {return Pool().total_allocs();}
|
||||||
|
int hstring::total_bytes() {return Pool().size();}
|
||||||
|
int hstring::total_finds() {return Pool().total_finds();}
|
||||||
|
int hstring::total_collisions() {return Pool().total_collisions();}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _XBOX
|
||||||
|
} // dllNamespace
|
||||||
|
#endif
|
|
@ -0,0 +1,106 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAVEN STANDARD USEFUL FUNCTION LIBRARY
|
||||||
|
// (c) 2002 Activision
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Handle String
|
||||||
|
// -------------
|
||||||
|
// Handle strings are allocated once in a static buffer (with a hash index), and are
|
||||||
|
// never cleared out. You should use these for very common string names which are
|
||||||
|
// redundant or intended to last a long time.
|
||||||
|
//
|
||||||
|
// Handle strings are also good for comparison and storage because they compare only
|
||||||
|
// the handles, which are simple unique integers.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(RUFL_HSTRING_INC)
|
||||||
|
#define RUFL_HSTRING_INC
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _XBOX
|
||||||
|
namespace dllNamespace
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// The Handle String Class
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
class hstring
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructors
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
hstring();
|
||||||
|
hstring(const char *str);
|
||||||
|
hstring(const hstring &str);
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Assignment
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
hstring& operator= (const char *str);
|
||||||
|
hstring& operator= (const hstring &str);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Comparison
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool operator== (const hstring &str) const {return (mHandle==str.mHandle);}
|
||||||
|
bool operator< (const hstring &str) const {return (mHandle< str.mHandle);}
|
||||||
|
bool operator! () const {return (mHandle==0);}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Conversion
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const char* c_str(void) const;
|
||||||
|
const char* operator *(void) const;
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Access Functions
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int length(void) const;
|
||||||
|
int handle(void) const;
|
||||||
|
bool empty() const {return handle()==0;}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Debug Statistics Routines
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#ifdef _DEBUG
|
||||||
|
static float ave_collisions();
|
||||||
|
static int total_strings();
|
||||||
|
static int total_bytes();
|
||||||
|
static int total_finds();
|
||||||
|
static int total_collisions();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Helper Functions
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void init(const char *str);
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Data
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
int mHandle;
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
char* mStr;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef _XBOX
|
||||||
|
} // dllNamespace
|
||||||
|
using namespace dllNamespace;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // HSTRING_H
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
VersionUpdate -ss_ini \\Ravendata1\VSS\central_code\SRCSAFE.INI -ss_prj $/Jedi/Code -header win32/AutoVersion.h -email SW-Everyone -interactive
|
|
@ -0,0 +1,105 @@
|
||||||
|
// Bowcaster Weapon
|
||||||
|
|
||||||
|
// this line must stay at top so the whole PCH thing works...
|
||||||
|
#include "cg_headers.h"
|
||||||
|
|
||||||
|
//#include "cg_local.h"
|
||||||
|
#include "cg_media.h"
|
||||||
|
#include "FxScheduler.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_ATSTMainProjectileThink
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
void FX_ATSTMainProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||||
|
{
|
||||||
|
vec3_t forward;
|
||||||
|
|
||||||
|
if ( VectorNormalize2( cent->gent->s.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
forward[2] = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hack the scale of the forward vector if we were just fired or bounced...this will shorten up the tail for a split second so tails don't clip so harshly
|
||||||
|
int dif = cg.time - cent->gent->s.pos.trTime;
|
||||||
|
|
||||||
|
if ( dif < 30 )
|
||||||
|
{
|
||||||
|
if ( dif < 0 )
|
||||||
|
{
|
||||||
|
dif = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float scale = ( dif / 30.0f ) * 0.95f + 0.05f;
|
||||||
|
|
||||||
|
VectorScale( forward, scale, forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
theFxScheduler.PlayEffect( "atst/shot", cent->lerpOrigin, forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_ATSTMainHitWall
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
void FX_ATSTMainHitWall( vec3_t origin, vec3_t normal )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "atst/wall_impact", origin, normal );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_ATSTMainHitPlayer
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
void FX_ATSTMainHitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||||
|
{
|
||||||
|
if ( humanoid )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "atst/flesh_impact", origin, normal );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "atst/droid_impact", origin, normal );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_ATSTSideAltProjectileThink
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
void FX_ATSTSideAltProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||||
|
{
|
||||||
|
vec3_t forward;
|
||||||
|
|
||||||
|
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
forward[2] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
theFxScheduler.PlayEffect( "atst/side_alt_shot", cent->lerpOrigin, forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_ATSTSideMainProjectileThink
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
void FX_ATSTSideMainProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||||
|
{
|
||||||
|
vec3_t forward;
|
||||||
|
|
||||||
|
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
forward[2] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
theFxScheduler.PlayEffect( "atst/side_main_shot", cent->lerpOrigin, forward );
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
// Blaster Weapon
|
||||||
|
|
||||||
|
// this line must stay at top so the whole PCH thing works...
|
||||||
|
#include "cg_headers.h"
|
||||||
|
|
||||||
|
#include "cg_local.h"
|
||||||
|
#include "cg_media.h"
|
||||||
|
#include "FxScheduler.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------
|
||||||
|
FX_BlasterProjectileThink
|
||||||
|
-------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_BlasterProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||||
|
{
|
||||||
|
vec3_t forward;
|
||||||
|
|
||||||
|
if (cent->currentState.eFlags & EF_USE_ANGLEDELTA)
|
||||||
|
{
|
||||||
|
AngleVectors(cent->currentState.angles, forward, 0, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( VectorNormalize2( cent->gent->s.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
forward[2] = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hack the scale of the forward vector if we were just fired or bounced...this will shorten up the tail for a split second so tails don't clip so harshly
|
||||||
|
int dif = cg.time - cent->gent->s.pos.trTime;
|
||||||
|
|
||||||
|
if ( dif < 75 )
|
||||||
|
{
|
||||||
|
if ( dif < 0 )
|
||||||
|
{
|
||||||
|
dif = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float scale = ( dif / 75.0f ) * 0.95f + 0.05f;
|
||||||
|
|
||||||
|
VectorScale( forward, scale, forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( cent->gent && cent->gent->owner && cent->gent->owner->s.number > 0 )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "blaster/NPCshot", cent->lerpOrigin, forward );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( cgs.effects.blasterShotEffect, cent->lerpOrigin, forward );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------
|
||||||
|
FX_BlasterAltFireThink
|
||||||
|
-------------------------
|
||||||
|
*/
|
||||||
|
void FX_BlasterAltFireThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||||
|
{
|
||||||
|
FX_BlasterProjectileThink( cent, weapon );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------
|
||||||
|
FX_BlasterWeaponHitWall
|
||||||
|
-------------------------
|
||||||
|
*/
|
||||||
|
void FX_BlasterWeaponHitWall( vec3_t origin, vec3_t normal )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( cgs.effects.blasterWallImpactEffect, origin, normal );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------
|
||||||
|
FX_BlasterWeaponHitPlayer
|
||||||
|
-------------------------
|
||||||
|
*/
|
||||||
|
void FX_BlasterWeaponHitPlayer( gentity_t *hit, vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||||
|
{
|
||||||
|
//temporary? just testing out the damage skin stuff -rww
|
||||||
|
if ( hit && hit->client && hit->ghoul2.size() )
|
||||||
|
{
|
||||||
|
CG_AddGhoul2Mark(cgs.media.bdecal_burnmark1, flrand(3.5, 4.0), origin, normal, hit->s.number,
|
||||||
|
hit->client->ps.origin, hit->client->renderInfo.legsYaw, hit->ghoul2, hit->s.modelScale, Q_irand(10000, 13000));
|
||||||
|
}
|
||||||
|
|
||||||
|
theFxScheduler.PlayEffect( cgs.effects.blasterFleshImpactEffect, origin, normal );
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
// Bowcaster Weapon
|
||||||
|
|
||||||
|
// this line must stay at top so the whole PCH thing works...
|
||||||
|
#include "cg_headers.h"
|
||||||
|
|
||||||
|
//#include "cg_local.h"
|
||||||
|
#include "cg_media.h"
|
||||||
|
#include "FxScheduler.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_BowcasterProjectileThink
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_BowcasterProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||||
|
{
|
||||||
|
vec3_t forward;
|
||||||
|
|
||||||
|
if ( VectorNormalize2( cent->gent->s.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
forward[2] = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hack the scale of the forward vector if we were just fired or bounced...this will shorten up the tail for a split second so tails don't clip so harshly
|
||||||
|
int dif = cg.time - cent->gent->s.pos.trTime;
|
||||||
|
|
||||||
|
if ( dif < 75 )
|
||||||
|
{
|
||||||
|
if ( dif < 0 )
|
||||||
|
{
|
||||||
|
dif = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float scale = ( dif / 75.0f ) * 0.95f + 0.05f;
|
||||||
|
|
||||||
|
VectorScale( forward, scale, forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
theFxScheduler.PlayEffect( cgs.effects.bowcasterShotEffect, cent->lerpOrigin, forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_BowcasterHitWall
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_BowcasterHitWall( vec3_t origin, vec3_t normal )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( cgs.effects.bowcasterImpactEffect, origin, normal );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_BowcasterHitPlayer
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_BowcasterHitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( cgs.effects.bowcasterImpactEffect, origin, normal );
|
||||||
|
}
|
|
@ -0,0 +1,156 @@
|
||||||
|
// Bryar Pistol Weapon Effects
|
||||||
|
|
||||||
|
// this line must stay at top so the whole PCH thing works...
|
||||||
|
#include "cg_headers.h"
|
||||||
|
|
||||||
|
//#include "cg_local.h"
|
||||||
|
#include "cg_media.h"
|
||||||
|
#include "FxScheduler.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
MAIN FIRE
|
||||||
|
|
||||||
|
-------------------------
|
||||||
|
FX_BryarProjectileThink
|
||||||
|
-------------------------
|
||||||
|
*/
|
||||||
|
void FX_BryarProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||||
|
{
|
||||||
|
vec3_t forward;
|
||||||
|
|
||||||
|
if ( VectorNormalize2( cent->gent->s.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
forward[2] = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hack the scale of the forward vector if we were just fired or bounced...this will shorten up the tail for a split second so tails don't clip so harshly
|
||||||
|
int dif = cg.time - cent->gent->s.pos.trTime;
|
||||||
|
|
||||||
|
if ( dif < 75 )
|
||||||
|
{
|
||||||
|
if ( dif < 0 )
|
||||||
|
{
|
||||||
|
dif = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float scale = ( dif / 75.0f ) * 0.95f + 0.05f;
|
||||||
|
|
||||||
|
VectorScale( forward, scale, forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( cent->gent && cent->gent->owner && cent->gent->owner->s.number > 0 )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "bryar/NPCshot", cent->lerpOrigin, forward );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( cgs.effects.bryarShotEffect, cent->lerpOrigin, forward );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------
|
||||||
|
FX_BryarHitWall
|
||||||
|
-------------------------
|
||||||
|
*/
|
||||||
|
void FX_BryarHitWall( vec3_t origin, vec3_t normal )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( cgs.effects.bryarWallImpactEffect, origin, normal );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------
|
||||||
|
FX_BryarHitPlayer
|
||||||
|
-------------------------
|
||||||
|
*/
|
||||||
|
void FX_BryarHitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( cgs.effects.bryarFleshImpactEffect, origin, normal );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
ALT FIRE
|
||||||
|
|
||||||
|
-------------------------
|
||||||
|
FX_BryarAltProjectileThink
|
||||||
|
-------------------------
|
||||||
|
*/
|
||||||
|
void FX_BryarAltProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||||
|
{
|
||||||
|
vec3_t forward;
|
||||||
|
|
||||||
|
if ( VectorNormalize2( cent->gent->s.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
forward[2] = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hack the scale of the forward vector if we were just fired or bounced...this will shorten up the tail for a split second so tails don't clip so harshly
|
||||||
|
int dif = cg.time - cent->gent->s.pos.trTime;
|
||||||
|
|
||||||
|
if ( dif < 75 )
|
||||||
|
{
|
||||||
|
if ( dif < 0 )
|
||||||
|
{
|
||||||
|
dif = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float scale = ( dif / 75.0f ) * 0.95f + 0.05f;
|
||||||
|
|
||||||
|
VectorScale( forward, scale, forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
// see if we have some sort of extra charge going on
|
||||||
|
for ( int t = 1; t < cent->gent->count; t++ )
|
||||||
|
{
|
||||||
|
// just add ourselves over, and over, and over when we are charged
|
||||||
|
theFxScheduler.PlayEffect( cgs.effects.bryarPowerupShotEffect, cent->lerpOrigin, forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
theFxScheduler.PlayEffect( cgs.effects.bryarShotEffect, cent->lerpOrigin, forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------
|
||||||
|
FX_BryarAltHitWall
|
||||||
|
-------------------------
|
||||||
|
*/
|
||||||
|
void FX_BryarAltHitWall( vec3_t origin, vec3_t normal, int power )
|
||||||
|
{
|
||||||
|
switch( power )
|
||||||
|
{
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
theFxScheduler.PlayEffect( cgs.effects.bryarWallImpactEffect3, origin, normal );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
theFxScheduler.PlayEffect( cgs.effects.bryarWallImpactEffect2, origin, normal );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
theFxScheduler.PlayEffect( cgs.effects.bryarWallImpactEffect, origin, normal );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------
|
||||||
|
FX_BryarAltHitPlayer
|
||||||
|
-------------------------
|
||||||
|
*/
|
||||||
|
void FX_BryarAltHitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( cgs.effects.bryarFleshImpactEffect, origin, normal );
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
// Concussion Rifle Weapon
|
||||||
|
|
||||||
|
// this line must stay at top so the whole PCH thing works...
|
||||||
|
#include "cg_headers.h"
|
||||||
|
|
||||||
|
//#include "cg_local.h"
|
||||||
|
#include "cg_media.h"
|
||||||
|
#include "FxScheduler.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_ConcProjectileThink
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_ConcProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||||
|
{
|
||||||
|
vec3_t forward;
|
||||||
|
|
||||||
|
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
forward[2] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
theFxScheduler.PlayEffect( "concussion/shot", cent->lerpOrigin, forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_ConcHitWall
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_ConcHitWall( vec3_t origin, vec3_t normal )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "concussion/explosion", origin, normal );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_ConcHitPlayer
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_ConcHitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "concussion/explosion", origin, normal );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_ConcAltShot
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
static vec3_t WHITE ={1.0f,1.0f,1.0f};
|
||||||
|
|
||||||
|
void FX_ConcAltShot( vec3_t start, vec3_t end )
|
||||||
|
{
|
||||||
|
//"concussion/beam"
|
||||||
|
FX_AddLine( -1, start, end, 0.1f, 10.0f, 0.0f,
|
||||||
|
1.0f, 0.0f, 0.0f,
|
||||||
|
WHITE, WHITE, 0.0f,
|
||||||
|
175, cgi_R_RegisterShader( "gfx/effects/blueLine" ),
|
||||||
|
0, FX_SIZE_LINEAR | FX_ALPHA_LINEAR );
|
||||||
|
|
||||||
|
vec3_t BRIGHT={0.75f,0.5f,1.0f};
|
||||||
|
|
||||||
|
// add some beef
|
||||||
|
FX_AddLine( -1, start, end, 0.1f, 7.0f, 0.0f,
|
||||||
|
1.0f, 0.0f, 0.0f,
|
||||||
|
BRIGHT, BRIGHT, 0.0f,
|
||||||
|
150, cgi_R_RegisterShader( "gfx/misc/whiteline2" ),
|
||||||
|
0, FX_SIZE_LINEAR | FX_ALPHA_LINEAR );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_ConcAltMiss
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_ConcAltMiss( vec3_t origin, vec3_t normal )
|
||||||
|
{
|
||||||
|
vec3_t pos, c1, c2;
|
||||||
|
|
||||||
|
VectorMA( origin, 4.0f, normal, c1 );
|
||||||
|
VectorCopy( c1, c2 );
|
||||||
|
c1[2] += 4;
|
||||||
|
c2[2] += 12;
|
||||||
|
|
||||||
|
VectorAdd( origin, normal, pos );
|
||||||
|
pos[2] += 28;
|
||||||
|
|
||||||
|
FX_AddBezier( origin, pos, c1, vec3_origin, c2, vec3_origin, 6.0f, 6.0f, 0.0f, 0.0f, 0.2f, 0.5f, WHITE, WHITE, 0.0f, 4000, cgi_R_RegisterShader( "gfx/effects/smokeTrail" ), FX_ALPHA_WAVE );
|
||||||
|
|
||||||
|
theFxScheduler.PlayEffect( "concussion/alt_miss", origin, normal );
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
// DEMP2 Weapon
|
||||||
|
|
||||||
|
// this line must stay at top so the whole PCH thing works...
|
||||||
|
#include "cg_headers.h"
|
||||||
|
|
||||||
|
//#include "cg_local.h"
|
||||||
|
#include "cg_media.h"
|
||||||
|
#include "FxScheduler.h"
|
||||||
|
#include "FxUtil.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_DEMP2_ProjectileThink
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_DEMP2_ProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||||
|
{
|
||||||
|
vec3_t forward;
|
||||||
|
|
||||||
|
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
forward[2] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// theFxScheduler.PlayEffect( "demp2/shot", cent->lerpOrigin, forward );
|
||||||
|
// theFxScheduler.PlayEffect( "demp2/shot2", cent->lerpOrigin, forward );
|
||||||
|
theFxScheduler.PlayEffect( "demp2/projectile", cent->lerpOrigin, forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_DEMP2_HitWall
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_DEMP2_HitWall( vec3_t origin, vec3_t normal )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "demp2/wall_impact", origin, normal );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_DEMP2_HitPlayer
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_DEMP2_HitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "demp2/flesh_impact", origin, normal );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_DEMP2_AltProjectileThink
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_DEMP2_AltProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||||
|
{
|
||||||
|
vec3_t forward;
|
||||||
|
|
||||||
|
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
forward[2] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
theFxScheduler.PlayEffect( "demp2/projectile", cent->lerpOrigin, forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------
|
||||||
|
void FX_DEMP2_AltDetonate( vec3_t org, float size )
|
||||||
|
{
|
||||||
|
localEntity_t *ex;
|
||||||
|
|
||||||
|
ex = CG_AllocLocalEntity();
|
||||||
|
ex->leType = LE_FADE_SCALE_MODEL;
|
||||||
|
memset( &ex->refEntity, 0, sizeof( refEntity_t ));
|
||||||
|
|
||||||
|
ex->refEntity.renderfx |= RF_VOLUMETRIC;
|
||||||
|
|
||||||
|
ex->startTime = cg.time;
|
||||||
|
ex->endTime = ex->startTime + 1300;
|
||||||
|
|
||||||
|
ex->radius = size;
|
||||||
|
ex->refEntity.customShader = cgi_R_RegisterShader( "gfx/effects/demp2shell" );
|
||||||
|
|
||||||
|
ex->refEntity.hModel = cgi_R_RegisterModel( "models/items/sphere.md3" );
|
||||||
|
VectorCopy( org, ex->refEntity.origin );
|
||||||
|
|
||||||
|
ex->color[0] = ex->color[1] = ex->color[2] = 255.0f;
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
// Disruptor Weapon
|
||||||
|
|
||||||
|
// this line must stay at top so the whole PCH thing works...
|
||||||
|
#include "cg_headers.h"
|
||||||
|
|
||||||
|
//#include "cg_local.h"
|
||||||
|
#include "cg_media.h"
|
||||||
|
#include "FxScheduler.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_DisruptorMainShot
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
static vec3_t WHITE ={1.0f,1.0f,1.0f};
|
||||||
|
|
||||||
|
void FX_DisruptorMainShot( vec3_t start, vec3_t end )
|
||||||
|
{
|
||||||
|
FX_AddLine( -1, start, end, 0.1f, 4.0f, 0.0f,
|
||||||
|
1.0f, 0.0f, 0.0f,
|
||||||
|
WHITE, WHITE, 0.0f,
|
||||||
|
120, cgi_R_RegisterShader( "gfx/effects/redLine" ),
|
||||||
|
0, FX_SIZE_LINEAR | FX_ALPHA_LINEAR );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_DisruptorAltShot
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
void FX_DisruptorAltShot( vec3_t start, vec3_t end, qboolean fullCharge )
|
||||||
|
{
|
||||||
|
FX_AddLine( -1, start, end, 0.1f, 10.0f, 0.0f,
|
||||||
|
1.0f, 0.0f, 0.0f,
|
||||||
|
WHITE, WHITE, 0.0f,
|
||||||
|
175, cgi_R_RegisterShader( "gfx/effects/redLine" ),
|
||||||
|
0, FX_SIZE_LINEAR | FX_ALPHA_LINEAR );
|
||||||
|
|
||||||
|
if ( fullCharge )
|
||||||
|
{
|
||||||
|
vec3_t YELLER={0.8f,0.7f,0.0f};
|
||||||
|
|
||||||
|
// add some beef
|
||||||
|
FX_AddLine( -1, start, end, 0.1f, 7.0f, 0.0f,
|
||||||
|
1.0f, 0.0f, 0.0f,
|
||||||
|
YELLER, YELLER, 0.0f,
|
||||||
|
150, cgi_R_RegisterShader( "gfx/misc/whiteline2" ),
|
||||||
|
0, FX_SIZE_LINEAR | FX_ALPHA_LINEAR );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_DisruptorAltMiss
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_DisruptorAltMiss( vec3_t origin, vec3_t normal )
|
||||||
|
{
|
||||||
|
vec3_t pos, c1, c2;
|
||||||
|
|
||||||
|
VectorMA( origin, 4.0f, normal, c1 );
|
||||||
|
VectorCopy( c1, c2 );
|
||||||
|
c1[2] += 4;
|
||||||
|
c2[2] += 12;
|
||||||
|
|
||||||
|
VectorAdd( origin, normal, pos );
|
||||||
|
pos[2] += 28;
|
||||||
|
|
||||||
|
FX_AddBezier( origin, pos, c1, vec3_origin, c2, vec3_origin, 6.0f, 6.0f, 0.0f, 0.0f, 0.2f, 0.5f, WHITE, WHITE, 0.0f, 4000, cgi_R_RegisterShader( "gfx/effects/smokeTrail" ), FX_ALPHA_WAVE );
|
||||||
|
|
||||||
|
theFxScheduler.PlayEffect( "disruptor/alt_miss", origin, normal );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_KothosBeam
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
void FX_KothosBeam( vec3_t start, vec3_t end )
|
||||||
|
{
|
||||||
|
FX_AddLine( -1, start, end, 0.1f, 10.0f, 0.0f,
|
||||||
|
1.0f, 0.0f, 0.0f,
|
||||||
|
WHITE, WHITE, 0.0f,
|
||||||
|
175, cgi_R_RegisterShader( "gfx/misc/dr1" ),
|
||||||
|
0, FX_SIZE_LINEAR | FX_ALPHA_LINEAR );
|
||||||
|
|
||||||
|
vec3_t YELLER={0.8f,0.7f,0.0f};
|
||||||
|
|
||||||
|
// add some beef
|
||||||
|
FX_AddLine( -1, start, end, 0.1f, 7.0f, 0.0f,
|
||||||
|
1.0f, 0.0f, 0.0f,
|
||||||
|
YELLER, YELLER, 0.0f,
|
||||||
|
150, cgi_R_RegisterShader( "gfx/misc/whiteline2" ),
|
||||||
|
0, FX_SIZE_LINEAR | FX_ALPHA_LINEAR );
|
||||||
|
}
|
|
@ -0,0 +1,146 @@
|
||||||
|
// Emplaced Weapon
|
||||||
|
|
||||||
|
// this line must stay at top so the whole PCH thing works...
|
||||||
|
#include "cg_headers.h"
|
||||||
|
|
||||||
|
//#include "cg_local.h"
|
||||||
|
#include "cg_media.h"
|
||||||
|
#include "FxScheduler.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_EmplacedProjectileThink
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_EmplacedProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||||
|
{
|
||||||
|
vec3_t forward;
|
||||||
|
|
||||||
|
if ( VectorNormalize2( cent->gent->s.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
forward[2] = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hack the scale of the forward vector if we were just fired or bounced...this will shorten up the tail for a split second so tails don't clip so harshly
|
||||||
|
int dif = cg.time - cent->gent->s.pos.trTime;
|
||||||
|
|
||||||
|
if ( dif < 75 )
|
||||||
|
{
|
||||||
|
if ( dif < 0 )
|
||||||
|
{
|
||||||
|
dif = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float scale = ( dif / 75.0f ) * 0.95f + 0.05f;
|
||||||
|
|
||||||
|
VectorScale( forward, scale, forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
// If tie-fighter missle use green shot.
|
||||||
|
if ( cent->currentState.weapon == WP_TIE_FIGHTER )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "ships/imp_blastershot", cent->lerpOrigin, forward );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( cent->gent && cent->gent->owner && cent->gent->owner->activator && cent->gent->owner->activator->s.number > 0 )
|
||||||
|
{
|
||||||
|
// NPC's do short shot
|
||||||
|
if ( cent->gent->alt_fire )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "eweb/shotNPC", cent->lerpOrigin, forward );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "emplaced/shotNPC", cent->lerpOrigin, forward );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// players do long shot
|
||||||
|
if ( cent->gent && cent->gent->alt_fire )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "eweb/shotNPC", cent->lerpOrigin, forward );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "emplaced/shot", cent->lerpOrigin, forward );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_EmplacedHitWall
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_EmplacedHitWall( vec3_t origin, vec3_t normal, qboolean eweb )
|
||||||
|
{
|
||||||
|
if ( eweb )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "eweb/wall_impact", origin, normal );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "emplaced/wall_impact", origin, normal );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_EmplacedHitPlayer
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_EmplacedHitPlayer( vec3_t origin, vec3_t normal, qboolean eweb )
|
||||||
|
{
|
||||||
|
if ( eweb )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "eweb/flesh_impact", origin, normal );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "emplaced/wall_impact", origin, normal );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_TurretProjectileThink
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_TurretProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||||
|
{
|
||||||
|
vec3_t forward;
|
||||||
|
|
||||||
|
if ( VectorNormalize2( cent->gent->s.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
forward[2] = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hack the scale of the forward vector if we were just fired or bounced...this will shorten up the tail for a split second so tails don't clip so harshly
|
||||||
|
int dif = cg.time - cent->gent->s.pos.trTime;
|
||||||
|
|
||||||
|
if ( dif < 75 )
|
||||||
|
{
|
||||||
|
if ( dif < 0 )
|
||||||
|
{
|
||||||
|
dif = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float scale = ( dif / 75.0f ) * 0.95f + 0.05f;
|
||||||
|
|
||||||
|
VectorScale( forward, scale, forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
theFxScheduler.PlayEffect( "turret/shot", cent->lerpOrigin, forward );
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
// Golan Arms Flechette Weapon
|
||||||
|
|
||||||
|
// this line must stay at top so the whole PCH thing works...
|
||||||
|
#include "cg_headers.h"
|
||||||
|
|
||||||
|
//#include "cg_local.h"
|
||||||
|
#include "cg_media.h"
|
||||||
|
#include "FxScheduler.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------
|
||||||
|
FX_FlechetteProjectileThink
|
||||||
|
-------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_FlechetteProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||||
|
{
|
||||||
|
vec3_t forward;
|
||||||
|
|
||||||
|
EvaluateTrajectoryDelta( ¢->gent->s.pos, cg.time, forward );
|
||||||
|
|
||||||
|
if ( VectorNormalize( forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
forward[2] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
theFxScheduler.PlayEffect( cgs.effects.flechetteShotEffect, cent->lerpOrigin, forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------
|
||||||
|
FX_FlechetteWeaponHitWall
|
||||||
|
-------------------------
|
||||||
|
*/
|
||||||
|
void FX_FlechetteWeaponHitWall( vec3_t origin, vec3_t normal )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( cgs.effects.flechetteShotDeathEffect, origin, normal );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------
|
||||||
|
FX_BlasterWeaponHitPlayer
|
||||||
|
-------------------------
|
||||||
|
*/
|
||||||
|
void FX_FlechetteWeaponHitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||||
|
{
|
||||||
|
// if ( humanoid )
|
||||||
|
// {
|
||||||
|
theFxScheduler.PlayEffect( cgs.effects.flechetteFleshImpactEffect, origin, normal );
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// theFxScheduler.PlayEffect( "blaster/droid_impact", origin, normal );
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------
|
||||||
|
FX_FlechetteProjectileThink
|
||||||
|
-------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_FlechetteAltProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||||
|
{
|
||||||
|
vec3_t forward;
|
||||||
|
|
||||||
|
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
forward[2] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
theFxScheduler.PlayEffect( cgs.effects.flechetteAltShotEffect, cent->lerpOrigin, forward );
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
// Heavy Repeater Weapon
|
||||||
|
|
||||||
|
// this line must stay at top so the whole PCH thing works...
|
||||||
|
#include "cg_headers.h"
|
||||||
|
|
||||||
|
//#include "cg_local.h"
|
||||||
|
#include "cg_media.h"
|
||||||
|
#include "FxScheduler.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_RepeaterProjectileThink
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_RepeaterProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||||
|
{
|
||||||
|
vec3_t forward;
|
||||||
|
|
||||||
|
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
forward[2] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
theFxScheduler.PlayEffect( "repeater/projectile", cent->lerpOrigin, forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
------------------------
|
||||||
|
FX_RepeaterHitWall
|
||||||
|
------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_RepeaterHitWall( vec3_t origin, vec3_t normal )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "repeater/wall_impact", origin, normal );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
------------------------
|
||||||
|
FX_RepeaterHitPlayer
|
||||||
|
------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_RepeaterHitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "repeater/wall_impact", origin, normal );
|
||||||
|
// theFxScheduler.PlayEffect( "repeater/flesh_impact", origin, normal );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
------------------------------
|
||||||
|
FX_RepeaterAltProjectileThink
|
||||||
|
-----------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_RepeaterAltProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||||
|
{
|
||||||
|
vec3_t forward;
|
||||||
|
|
||||||
|
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
forward[2] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
theFxScheduler.PlayEffect( "repeater/alt_projectile", cent->lerpOrigin, forward );
|
||||||
|
// theFxScheduler.PlayEffect( "repeater/alt_projectile", cent->lerpOrigin, forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
------------------------
|
||||||
|
FX_RepeaterAltHitWall
|
||||||
|
------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_RepeaterAltHitWall( vec3_t origin, vec3_t normal )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "repeater/concussion", origin, normal );
|
||||||
|
// theFxScheduler.PlayEffect( "repeater/alt_wall_impact2", origin, normal );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
------------------------
|
||||||
|
FX_RepeaterAltHitPlayer
|
||||||
|
------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_RepeaterAltHitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "repeater/concussion", origin );
|
||||||
|
// theFxScheduler.PlayEffect( "repeater/alt_wall_impact2", origin, normal );
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
// Noghri Rifle
|
||||||
|
|
||||||
|
// this line must stay at top so the whole PCH thing works...
|
||||||
|
#include "cg_headers.h"
|
||||||
|
|
||||||
|
#include "cg_local.h"
|
||||||
|
#include "cg_media.h"
|
||||||
|
#include "FxScheduler.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------
|
||||||
|
FX_NoghriShotProjectileThink
|
||||||
|
-------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_NoghriShotProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||||
|
{
|
||||||
|
vec3_t forward;
|
||||||
|
|
||||||
|
if ( VectorNormalize2( cent->gent->s.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
forward[2] = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hack the scale of the forward vector if we were just fired or bounced...this will shorten up the tail for a split second so tails don't clip so harshly
|
||||||
|
int dif = cg.time - cent->gent->s.pos.trTime;
|
||||||
|
|
||||||
|
if ( dif < 75 )
|
||||||
|
{
|
||||||
|
if ( dif < 0 )
|
||||||
|
{
|
||||||
|
dif = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float scale = ( dif / 75.0f ) * 0.95f + 0.05f;
|
||||||
|
|
||||||
|
VectorScale( forward, scale, forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
theFxScheduler.PlayEffect( "noghri_stick/shot", cent->lerpOrigin, forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------
|
||||||
|
FX_NoghriShotWeaponHitWall
|
||||||
|
-------------------------
|
||||||
|
*/
|
||||||
|
void FX_NoghriShotWeaponHitWall( vec3_t origin, vec3_t normal )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "noghri_stick/flesh_impact", origin, normal );//no "noghri/wall_impact"?
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
-------------------------
|
||||||
|
FX_NoghriShotWeaponHitPlayer
|
||||||
|
-------------------------
|
||||||
|
*/
|
||||||
|
void FX_NoghriShotWeaponHitPlayer( gentity_t *hit, vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||||
|
{
|
||||||
|
//temporary? just testing out the damage skin stuff -rww
|
||||||
|
/*
|
||||||
|
if ( hit && hit->client && hit->ghoul2.size() )
|
||||||
|
{
|
||||||
|
CG_AddGhoul2Mark(cgs.media.bdecal_burnmark1, flrand(3.5, 4.0), origin, normal, hit->s.number,
|
||||||
|
hit->client->ps.origin, hit->client->renderInfo.legsYaw, hit->ghoul2, hit->s.modelScale, Q_irand(10000, 13000));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
theFxScheduler.PlayEffect( "noghri_stick/flesh_impact", origin, normal );
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
// Rocket Launcher Weapon
|
||||||
|
|
||||||
|
// this line must stay at top so the whole PCH thing works...
|
||||||
|
#include "cg_headers.h"
|
||||||
|
|
||||||
|
//#include "cg_local.h"
|
||||||
|
#include "cg_media.h"
|
||||||
|
#include "FxScheduler.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_RocketProjectileThink
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_RocketProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||||
|
{
|
||||||
|
vec3_t forward;
|
||||||
|
|
||||||
|
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
forward[2] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
theFxScheduler.PlayEffect( "rocket/shot", cent->lerpOrigin, forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_RocketHitWall
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_RocketHitWall( vec3_t origin, vec3_t normal )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "rocket/explosion", origin, normal );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_RocketHitPlayer
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_RocketHitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "rocket/explosion", origin, normal );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
---------------------------
|
||||||
|
FX_RocketAltProjectileThink
|
||||||
|
---------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_RocketAltProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||||
|
{
|
||||||
|
vec3_t forward;
|
||||||
|
|
||||||
|
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
forward[2] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
theFxScheduler.PlayEffect( "rocket/shot", cent->lerpOrigin, forward );
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
// Tusken Rifle
|
||||||
|
|
||||||
|
// this line must stay at top so the whole PCH thing works...
|
||||||
|
#include "cg_headers.h"
|
||||||
|
|
||||||
|
#include "cg_local.h"
|
||||||
|
#include "cg_media.h"
|
||||||
|
#include "FxScheduler.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------
|
||||||
|
FX_TuskenShotProjectileThink
|
||||||
|
-------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void FX_TuskenShotProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon )
|
||||||
|
{
|
||||||
|
vec3_t forward;
|
||||||
|
|
||||||
|
if ( VectorNormalize2( cent->gent->s.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
if ( VectorNormalize2( cent->currentState.pos.trDelta, forward ) == 0.0f )
|
||||||
|
{
|
||||||
|
forward[2] = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hack the scale of the forward vector if we were just fired or bounced...this will shorten up the tail for a split second so tails don't clip so harshly
|
||||||
|
int dif = cg.time - cent->gent->s.pos.trTime;
|
||||||
|
|
||||||
|
if ( dif < 75 )
|
||||||
|
{
|
||||||
|
if ( dif < 0 )
|
||||||
|
{
|
||||||
|
dif = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float scale = ( dif / 75.0f ) * 0.95f + 0.05f;
|
||||||
|
|
||||||
|
VectorScale( forward, scale, forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
theFxScheduler.PlayEffect( "tusken/shot", cent->lerpOrigin, forward );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------
|
||||||
|
FX_TuskenShotWeaponHitWall
|
||||||
|
-------------------------
|
||||||
|
*/
|
||||||
|
void FX_TuskenShotWeaponHitWall( vec3_t origin, vec3_t normal )
|
||||||
|
{
|
||||||
|
theFxScheduler.PlayEffect( "tusken/hitwall", origin, normal );
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
-------------------------
|
||||||
|
FX_TuskenShotWeaponHitPlayer
|
||||||
|
-------------------------
|
||||||
|
*/
|
||||||
|
void FX_TuskenShotWeaponHitPlayer( gentity_t *hit, vec3_t origin, vec3_t normal, qboolean humanoid )
|
||||||
|
{
|
||||||
|
//temporary? just testing out the damage skin stuff -rww
|
||||||
|
if ( hit && hit->client && hit->ghoul2.size() )
|
||||||
|
{
|
||||||
|
CG_AddGhoul2Mark(cgs.media.bdecal_burnmark1, flrand(3.5, 4.0), origin, normal, hit->s.number,
|
||||||
|
hit->client->ps.origin, hit->client->renderInfo.legsYaw, hit->ghoul2, hit->s.modelScale, Q_irand(10000, 13000));
|
||||||
|
}
|
||||||
|
|
||||||
|
theFxScheduler.PlayEffect( "tusken/hit", origin, normal );
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
// this include must remain at the top of every FXxxxx.CPP file
|
||||||
|
#include "common_headers.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
#pragma once
|
||||||
|
#if !defined(FX_PARSING_H_INC)
|
||||||
|
#define FX_PARSING_H_INC
|
||||||
|
|
||||||
|
|
||||||
|
#endif // FX_PARSING_H
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,572 @@
|
||||||
|
|
||||||
|
#if !defined(FX_SYSTEM_H_INC)
|
||||||
|
#include "FxSystem.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FX_PRIMITIVES_H_INC
|
||||||
|
#define FX_PRIMITIVES_H_INC
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_EFFECTS 1200
|
||||||
|
|
||||||
|
|
||||||
|
// Generic group flags, used by parser, then get converted to the appropriate specific flags
|
||||||
|
#define FX_PARM_MASK 0xC // use this to mask off any transition types that use a parm
|
||||||
|
#define FX_GENERIC_MASK 0xF
|
||||||
|
#define FX_LINEAR 0x1
|
||||||
|
#define FX_RAND 0x2
|
||||||
|
#define FX_NONLINEAR 0x4
|
||||||
|
#define FX_WAVE 0x8
|
||||||
|
#define FX_CLAMP 0xC
|
||||||
|
|
||||||
|
// Group flags
|
||||||
|
#define FX_ALPHA_SHIFT 0
|
||||||
|
#define FX_ALPHA_PARM_MASK 0x0000000C
|
||||||
|
#define FX_ALPHA_LINEAR 0x00000001
|
||||||
|
#define FX_ALPHA_RAND 0x00000002
|
||||||
|
#define FX_ALPHA_NONLINEAR 0x00000004
|
||||||
|
#define FX_ALPHA_WAVE 0x00000008
|
||||||
|
#define FX_ALPHA_CLAMP 0x0000000C
|
||||||
|
|
||||||
|
#define FX_RGB_SHIFT 4
|
||||||
|
#define FX_RGB_PARM_MASK 0x000000C0
|
||||||
|
#define FX_RGB_LINEAR 0x00000010
|
||||||
|
#define FX_RGB_RAND 0x00000020
|
||||||
|
#define FX_RGB_NONLINEAR 0x00000040
|
||||||
|
#define FX_RGB_WAVE 0x00000080
|
||||||
|
#define FX_RGB_CLAMP 0x000000C0
|
||||||
|
|
||||||
|
#define FX_SIZE_SHIFT 8
|
||||||
|
#define FX_SIZE_PARM_MASK 0x00000C00
|
||||||
|
#define FX_SIZE_LINEAR 0x00000100
|
||||||
|
#define FX_SIZE_RAND 0x00000200
|
||||||
|
#define FX_SIZE_NONLINEAR 0x00000400
|
||||||
|
#define FX_SIZE_WAVE 0x00000800
|
||||||
|
#define FX_SIZE_CLAMP 0x00000C00
|
||||||
|
|
||||||
|
#define FX_LENGTH_SHIFT 12
|
||||||
|
#define FX_LENGTH_PARM_MASK 0x0000C000
|
||||||
|
#define FX_LENGTH_LINEAR 0x00001000
|
||||||
|
#define FX_LENGTH_RAND 0x00002000
|
||||||
|
#define FX_LENGTH_NONLINEAR 0x00004000
|
||||||
|
#define FX_LENGTH_WAVE 0x00008000
|
||||||
|
#define FX_LENGTH_CLAMP 0x0000C000
|
||||||
|
|
||||||
|
#define FX_SIZE2_SHIFT 16
|
||||||
|
#define FX_SIZE2_PARM_MASK 0x000C0000
|
||||||
|
#define FX_SIZE2_LINEAR 0x00010000
|
||||||
|
#define FX_SIZE2_RAND 0x00020000
|
||||||
|
#define FX_SIZE2_NONLINEAR 0x00040000
|
||||||
|
#define FX_SIZE2_WAVE 0x00080000
|
||||||
|
#define FX_SIZE2_CLAMP 0x000C0000
|
||||||
|
|
||||||
|
// Feature flags
|
||||||
|
#define FX_DEPTH_HACK 0x00100000
|
||||||
|
#define FX_RELATIVE 0x00200000
|
||||||
|
#define FX_SET_SHADER_TIME 0x00400000 // by having the effects system set the shader time, we can make animating textures start at the correct time
|
||||||
|
#define FX_EXPENSIVE_PHYSICS 0x00800000
|
||||||
|
|
||||||
|
//rww - g2-related flags (these can slow things down significantly, use sparingly)
|
||||||
|
//These should be used only with particles/decals as they steal flags used by cylinders.
|
||||||
|
#define FX_GHOUL2_TRACE 0x00020000 //use in conjunction with particles - actually do full ghoul2 traces for physics collision against entities with a ghoul2 instance
|
||||||
|
//shared FX_SIZE2_RAND (used only with cylinders)
|
||||||
|
#define FX_GHOUL2_DECALS 0x00040000 //use in conjunction with decals - can project decal as a ghoul2 gore skin object onto ghoul2 models
|
||||||
|
//shared FX_SIZE2_NONLINEAR (used only with cylinders)
|
||||||
|
|
||||||
|
#define FX_ATTACHED_MODEL 0x01000000
|
||||||
|
|
||||||
|
#define FX_APPLY_PHYSICS 0x02000000
|
||||||
|
#define FX_USE_BBOX 0x04000000 // can make physics more accurate at the expense of speed
|
||||||
|
|
||||||
|
#define FX_USE_ALPHA 0x08000000 // the FX system actually uses RGB to do fades, but this will override that
|
||||||
|
// and cause it to fill in the alpha.
|
||||||
|
|
||||||
|
#define FX_EMIT_FX 0x10000000 // emitters technically don't have to emit stuff, but when they do
|
||||||
|
// this flag needs to be set
|
||||||
|
#define FX_DEATH_RUNS_FX 0x20000000 // Normal death triggers effect, but not kill_on_impact
|
||||||
|
#define FX_KILL_ON_IMPACT 0x40000000 // works just like it says, but only when physics are on.
|
||||||
|
#define FX_IMPACT_RUNS_FX 0x80000000 // an effect can call another effect when it hits something.
|
||||||
|
|
||||||
|
// Lightning flags, duplicates of existing flags, but lightning doesn't use those flags in that context...and nothing will ever use these in this context..so we are safe.
|
||||||
|
#define FX_TAPER 0x01000000 // tapers as it moves towards its endpoint
|
||||||
|
#define FX_BRANCH 0x02000000 // enables lightning branching
|
||||||
|
#define FX_GROW 0x04000000 // lightning grows from start point to end point over the course of its life
|
||||||
|
|
||||||
|
//------------------------------
|
||||||
|
class CEffect
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
vec3_t mOrigin1;
|
||||||
|
|
||||||
|
int mTimeStart;
|
||||||
|
int mTimeEnd;
|
||||||
|
|
||||||
|
unsigned int mFlags;
|
||||||
|
|
||||||
|
// Size of our object, useful for things that have physics
|
||||||
|
vec3_t mMin;
|
||||||
|
vec3_t mMax;
|
||||||
|
|
||||||
|
int mImpactFxID; // if we have an impact event, we may have to call an effect
|
||||||
|
int mDeathFxID; // if we have a death event, we may have to call an effect
|
||||||
|
|
||||||
|
refEntity_t mRefEnt;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CEffect() { memset( &mRefEnt, 0, sizeof( refEntity_t )); }
|
||||||
|
virtual ~CEffect() {}
|
||||||
|
virtual void Die() {}
|
||||||
|
|
||||||
|
virtual bool Update()
|
||||||
|
{ // Game pausing can cause dumb time things to happen, so kill the effect in this instance
|
||||||
|
if ( mTimeStart > theFxHelper.mTime ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SetSTScale(float s,float t) { mRefEnt.shaderTexCoord[0]=s;mRefEnt.shaderTexCoord[1]=t;}
|
||||||
|
|
||||||
|
inline void SetMin( const vec3_t min ) { if(min){VectorCopy(min,mMin);}else{VectorClear(mMin);} }
|
||||||
|
inline void SetMax( const vec3_t max ) { if(max){VectorCopy(max,mMax);}else{VectorClear(mMax);} }
|
||||||
|
inline void SetFlags( int flags ) { mFlags = flags; }
|
||||||
|
inline void AddFlags( int flags ) { mFlags |= flags; }
|
||||||
|
inline void ClearFlags( int flags ) { mFlags &= ~flags; }
|
||||||
|
inline void SetOrigin1( const vec3_t org ) { if(org){VectorCopy(org,mOrigin1);}else{VectorClear(mOrigin1);} }
|
||||||
|
inline void SetTimeStart( int time ) { mTimeStart = time; if (mFlags&FX_SET_SHADER_TIME) { mRefEnt.shaderTime = cg.time * 0.001f; }}
|
||||||
|
inline void SetTimeEnd( int time ) { mTimeEnd = time; }
|
||||||
|
inline void SetImpactFxID( int id ) { mImpactFxID = id; }
|
||||||
|
inline void SetDeathFxID( int id ) { mDeathFxID = id; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------
|
||||||
|
// This class is kind of an exception to the "rule".
|
||||||
|
// For now it exists only for allowing an easy way
|
||||||
|
// to get the saber slash trails rendered.
|
||||||
|
//---------------------------------------------------
|
||||||
|
class CTrail : public CEffect
|
||||||
|
{
|
||||||
|
// This is such a specific case thing, just grant public access to the goods.
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void Draw();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
vec3_t origin;
|
||||||
|
|
||||||
|
// very specifc case, we can modulate the color and the alpha
|
||||||
|
vec3_t rgb;
|
||||||
|
vec3_t destrgb;
|
||||||
|
vec3_t curRGB;
|
||||||
|
|
||||||
|
float alpha;
|
||||||
|
float destAlpha;
|
||||||
|
float curAlpha;
|
||||||
|
|
||||||
|
// this is a very specific case thing...allow interpolating the st coords so we can map the texture
|
||||||
|
// properly as this segement progresses through it's life
|
||||||
|
float ST[2];
|
||||||
|
float destST[2];
|
||||||
|
float curST[2];
|
||||||
|
|
||||||
|
} TVert;
|
||||||
|
|
||||||
|
TVert mVerts[4];
|
||||||
|
qhandle_t mShader;
|
||||||
|
|
||||||
|
|
||||||
|
CTrail() {};
|
||||||
|
virtual ~CTrail() {};
|
||||||
|
|
||||||
|
virtual bool Update();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------
|
||||||
|
class CLight : public CEffect
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
float mSizeStart;
|
||||||
|
float mSizeEnd;
|
||||||
|
float mSizeParm;
|
||||||
|
|
||||||
|
vec3_t mRGBStart;
|
||||||
|
vec3_t mRGBEnd;
|
||||||
|
float mRGBParm;
|
||||||
|
|
||||||
|
|
||||||
|
void UpdateSize();
|
||||||
|
void UpdateRGB();
|
||||||
|
|
||||||
|
void Draw()
|
||||||
|
{
|
||||||
|
theFxHelper.AddLightToScene( mOrigin1, mRefEnt.radius,
|
||||||
|
mRefEnt.lightingOrigin[0], mRefEnt.lightingOrigin[1], mRefEnt.lightingOrigin[2] );
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CLight() {}
|
||||||
|
virtual ~CLight() {}
|
||||||
|
virtual bool Update();
|
||||||
|
|
||||||
|
inline void SetSizeStart( float sz ) { mSizeStart = sz; }
|
||||||
|
inline void SetSizeEnd( float sz ) { mSizeEnd = sz; }
|
||||||
|
inline void SetSizeParm( float parm ) { mSizeParm = parm; }
|
||||||
|
|
||||||
|
inline void SetRGBStart( vec3_t rgb ) { if(rgb){VectorCopy(rgb,mRGBStart);}else{VectorClear(mRGBStart);} }
|
||||||
|
inline void SetRGBEnd( vec3_t rgb ) { if(rgb){VectorCopy(rgb,mRGBEnd);}else{VectorClear(mRGBEnd);} }
|
||||||
|
inline void SetRGBParm( float parm ) { mRGBParm = parm; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------
|
||||||
|
class CFlash : public CLight
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void Draw();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CFlash() {}
|
||||||
|
virtual ~CFlash() {}
|
||||||
|
|
||||||
|
virtual bool Update();
|
||||||
|
|
||||||
|
inline void SetShader( qhandle_t sh )
|
||||||
|
{ assert(sh);
|
||||||
|
mRefEnt.customShader = sh;
|
||||||
|
}
|
||||||
|
void Init( void );
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------
|
||||||
|
class CParticle : public CEffect
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
vec3_t mOrgOffset;
|
||||||
|
|
||||||
|
vec3_t mVel;
|
||||||
|
vec3_t mAccel;
|
||||||
|
float mGravity;
|
||||||
|
|
||||||
|
float mSizeStart;
|
||||||
|
float mSizeEnd;
|
||||||
|
float mSizeParm;
|
||||||
|
|
||||||
|
vec3_t mRGBStart;
|
||||||
|
vec3_t mRGBEnd;
|
||||||
|
float mRGBParm;
|
||||||
|
|
||||||
|
float mAlphaStart;
|
||||||
|
float mAlphaEnd;
|
||||||
|
float mAlphaParm;
|
||||||
|
|
||||||
|
float mRotationDelta;
|
||||||
|
float mElasticity;
|
||||||
|
|
||||||
|
short mClientID;
|
||||||
|
char mModelNum;
|
||||||
|
char mBoltNum;
|
||||||
|
|
||||||
|
bool UpdateOrigin();
|
||||||
|
void UpdateVelocity() {VectorMA( mVel, theFxHelper.mFloatFrameTime, mAccel, mVel ); }
|
||||||
|
|
||||||
|
void UpdateSize();
|
||||||
|
void UpdateRGB();
|
||||||
|
void UpdateAlpha();
|
||||||
|
void UpdateRotation() { mRefEnt.rotation += theFxHelper.mFrameTime * 0.01f * mRotationDelta; }
|
||||||
|
|
||||||
|
bool Cull();
|
||||||
|
void Draw();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
inline CParticle() { mRefEnt.reType = RT_SPRITE; mClientID = -1; mModelNum = -1; mBoltNum = -1; }
|
||||||
|
virtual ~CParticle() {}
|
||||||
|
|
||||||
|
virtual void Die();
|
||||||
|
virtual bool Update();
|
||||||
|
|
||||||
|
inline void SetShader( qhandle_t sh ) { mRefEnt.customShader = sh;}
|
||||||
|
|
||||||
|
inline void SetOrgOffset( const vec3_t o ) { if(o){VectorCopy(o,mOrgOffset);}else{VectorClear(mOrgOffset);}}
|
||||||
|
inline void SetVel( const vec3_t vel ) { if(vel){VectorCopy(vel,mVel);}else{VectorClear(mVel);} }
|
||||||
|
inline void SetAccel( const vec3_t ac ) { if(ac){VectorCopy(ac,mAccel);}else{VectorClear(mAccel);} }
|
||||||
|
inline void SetGravity( float grav ) { mGravity = grav; }
|
||||||
|
|
||||||
|
inline void SetSizeStart( float sz ) { mSizeStart = sz; }
|
||||||
|
inline void SetSizeEnd( float sz ) { mSizeEnd = sz; }
|
||||||
|
inline void SetSizeParm( float parm ) { mSizeParm = parm; }
|
||||||
|
|
||||||
|
inline void SetRGBStart( const vec3_t rgb ) { if(rgb){VectorCopy(rgb,mRGBStart);}else{VectorClear(mRGBStart);} }
|
||||||
|
inline void SetRGBEnd( const vec3_t rgb ) { if(rgb){VectorCopy(rgb,mRGBEnd);}else{VectorClear(mRGBEnd);} }
|
||||||
|
inline void SetRGBParm( float parm ) { mRGBParm = parm; }
|
||||||
|
|
||||||
|
inline void SetAlphaStart( float al ) { mAlphaStart = al; }
|
||||||
|
inline void SetAlphaEnd( float al ) { mAlphaEnd = al; }
|
||||||
|
inline void SetAlphaParm( float parm ) { mAlphaParm = parm; }
|
||||||
|
|
||||||
|
inline void SetRotation( float rot ) { mRefEnt.rotation = rot; }
|
||||||
|
inline void SetRotationDelta( float rot ) { mRotationDelta = rot; }
|
||||||
|
inline void SetElasticity( float el ) { mElasticity = el; }
|
||||||
|
|
||||||
|
inline void SetClient( int clientID, int modelNum = -1, int boltNum = -1 ) {mClientID = clientID; mModelNum = modelNum; mBoltNum = boltNum; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------
|
||||||
|
class CLine : public CParticle
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
vec3_t mOrigin2;
|
||||||
|
|
||||||
|
void Draw();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CLine() { mRefEnt.reType = RT_LINE;}
|
||||||
|
virtual ~CLine() {}
|
||||||
|
virtual void Die() {}
|
||||||
|
virtual bool Update();
|
||||||
|
|
||||||
|
|
||||||
|
inline void SetOrigin2( const vec3_t org2 ) { VectorCopy( org2, mOrigin2 ); }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------
|
||||||
|
class CBezier : public CLine
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
vec3_t mControl1;
|
||||||
|
vec3_t mControl1Vel;
|
||||||
|
|
||||||
|
vec3_t mControl2;
|
||||||
|
vec3_t mControl2Vel;
|
||||||
|
|
||||||
|
bool mInit;
|
||||||
|
|
||||||
|
void Draw();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CBezier(){ mInit = false; }
|
||||||
|
virtual ~CBezier() {}
|
||||||
|
virtual void Die() {}
|
||||||
|
|
||||||
|
virtual bool Update();
|
||||||
|
|
||||||
|
void DrawSegment( vec3_t start, vec3_t end, float texcoord1, float texcoord2 );
|
||||||
|
|
||||||
|
inline void SetControlPoints( const vec3_t ctrl1, const vec3_t ctrl2 ) { VectorCopy( ctrl1, mControl1 ); VectorCopy( ctrl2, mControl2 ); }
|
||||||
|
inline void SetControlVel( const vec3_t ctrl1v, const vec3_t ctrl2v ) { VectorCopy( ctrl1v, mControl1Vel ); VectorCopy( ctrl2v, mControl2Vel ); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------
|
||||||
|
class CElectricity : public CLine
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
float mChaos;
|
||||||
|
|
||||||
|
void Draw();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CElectricity() { mRefEnt.reType = RT_ELECTRICITY; }
|
||||||
|
virtual ~CElectricity() {}
|
||||||
|
virtual void Die() {}
|
||||||
|
|
||||||
|
virtual bool Update();
|
||||||
|
|
||||||
|
void Initialize();
|
||||||
|
|
||||||
|
inline void SetChaos( float chaos ) { mChaos = chaos; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Oriented quad
|
||||||
|
//------------------------------
|
||||||
|
class COrientedParticle : public CParticle
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
vec3_t mNormal;
|
||||||
|
vec3_t mNormalOffset;
|
||||||
|
|
||||||
|
bool Cull();
|
||||||
|
void Draw();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
COrientedParticle() { mRefEnt.reType = RT_ORIENTED_QUAD; }
|
||||||
|
virtual ~COrientedParticle() {}
|
||||||
|
|
||||||
|
virtual bool Update();
|
||||||
|
|
||||||
|
inline void SetNormal( const vec3_t norm ) { VectorCopy( norm, mNormal ); }
|
||||||
|
inline void SetNormalOffset( const vec3_t norm ) { VectorCopy( norm, mNormalOffset ); }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------
|
||||||
|
class CTail : public CParticle
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
vec3_t mOldOrigin;
|
||||||
|
|
||||||
|
float mLengthStart;
|
||||||
|
float mLengthEnd;
|
||||||
|
float mLengthParm;
|
||||||
|
|
||||||
|
float mLength;
|
||||||
|
|
||||||
|
void UpdateLength();
|
||||||
|
void CalcNewEndpoint();
|
||||||
|
|
||||||
|
void Draw();
|
||||||
|
bool Cull();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CTail() { mRefEnt.reType = RT_LINE; }
|
||||||
|
virtual ~CTail() {}
|
||||||
|
|
||||||
|
virtual bool Update();
|
||||||
|
|
||||||
|
inline void SetLengthStart( float len ) { mLengthStart = len; }
|
||||||
|
inline void SetLengthEnd( float len ) { mLengthEnd = len; }
|
||||||
|
inline void SetLengthParm( float len ) { mLengthParm = len; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------
|
||||||
|
class CCylinder : public CTail
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
float mSize2Start;
|
||||||
|
float mSize2End;
|
||||||
|
float mSize2Parm;
|
||||||
|
|
||||||
|
void UpdateSize2();
|
||||||
|
|
||||||
|
void Draw();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CCylinder() { mRefEnt.reType = RT_CYLINDER; }
|
||||||
|
virtual ~CCylinder() {}
|
||||||
|
|
||||||
|
virtual bool Update();
|
||||||
|
|
||||||
|
inline void SetSize2Start( float sz ) { mSize2Start = sz; }
|
||||||
|
inline void SetSize2End( float sz ) { mSize2End = sz; }
|
||||||
|
inline void SetSize2Parm( float parm ) { mSize2Parm = parm; }
|
||||||
|
|
||||||
|
inline void SetNormal( const vec3_t norm ) { VectorCopy( norm, mRefEnt.axis[0] ); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------
|
||||||
|
// Emitters are derived from particles because, although they don't draw, any effect called
|
||||||
|
// from them can borrow an initial or ending value from the emitters current alpha, rgb, etc..
|
||||||
|
class CEmitter : public CParticle
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
vec3_t mOldOrigin; // we use these to do some nice
|
||||||
|
vec3_t mLastOrigin; // tricks...
|
||||||
|
vec3_t mOldVelocity; //
|
||||||
|
int mOldTime;
|
||||||
|
|
||||||
|
vec3_t mAngles; // for a rotating thing, using a delta
|
||||||
|
vec3_t mAngleDelta; // as opposed to an end angle is probably much easier
|
||||||
|
|
||||||
|
int mEmitterFxID; // if we have emitter fx, this is our id
|
||||||
|
|
||||||
|
float mDensity; // controls how often emitter chucks an effect
|
||||||
|
float mVariance; // density sloppiness
|
||||||
|
|
||||||
|
void UpdateAngles();
|
||||||
|
|
||||||
|
void Draw();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CEmitter() {
|
||||||
|
// There may or may not be a model, but if there isn't one,
|
||||||
|
// we just won't bother adding the refEnt in our Draw func
|
||||||
|
mRefEnt.reType = RT_MODEL;
|
||||||
|
}
|
||||||
|
virtual ~CEmitter() {}
|
||||||
|
|
||||||
|
virtual bool Update();
|
||||||
|
|
||||||
|
inline void SetModel( qhandle_t model ) { mRefEnt.hModel = model; }
|
||||||
|
inline void SetAngles( const vec3_t ang ) { if(ang){VectorCopy(ang,mAngles);}else{VectorClear(mAngles);} }
|
||||||
|
inline void SetAngleDelta( const vec3_t ang){ if(ang){VectorCopy(ang,mAngleDelta);}else{VectorClear(mAngleDelta);} }
|
||||||
|
inline void SetEmitterFxID( int id ) { mEmitterFxID = id; }
|
||||||
|
inline void SetDensity( float density ) { mDensity = density; }
|
||||||
|
inline void SetVariance( float var ) { mVariance = var; }
|
||||||
|
inline void SetOldTime( int time ) { mOldTime = time; }
|
||||||
|
inline void SetLastOrg( const vec3_t org ) { if(org){VectorCopy(org,mLastOrigin);}else{VectorClear(mLastOrigin);} }
|
||||||
|
inline void SetLastVel( const vec3_t vel ) { if(vel){VectorCopy(vel,mOldVelocity);}else{VectorClear(mOldVelocity);}}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// We're getting pretty low level here, not the kind of thing to abuse considering how much overhead this
|
||||||
|
// adds to a SINGLE triangle or quad....
|
||||||
|
// The editor doesn't need to see or do anything with this
|
||||||
|
//------------------------------
|
||||||
|
#define MAX_CPOLY_VERTS 5
|
||||||
|
|
||||||
|
class CPoly : public CParticle
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
int mCount;
|
||||||
|
vec3_t mRotDelta;
|
||||||
|
int mTimeStamp;
|
||||||
|
|
||||||
|
bool Cull();
|
||||||
|
void Draw();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
vec3_t mOrg[MAX_CPOLY_VERTS];
|
||||||
|
vec2_t mST[MAX_CPOLY_VERTS];
|
||||||
|
|
||||||
|
float mRot[3][3];
|
||||||
|
int mLastFrameTime;
|
||||||
|
|
||||||
|
|
||||||
|
CPoly() {}
|
||||||
|
virtual ~CPoly() {}
|
||||||
|
|
||||||
|
virtual bool Update();
|
||||||
|
|
||||||
|
void PolyInit();
|
||||||
|
void CalcRotateMatrix();
|
||||||
|
void Rotate();
|
||||||
|
|
||||||
|
inline void SetNumVerts( int c ) { mCount = c; }
|
||||||
|
inline void SetRot( vec3_t r ) { if(r){VectorCopy(r,mRotDelta);}else{VectorClear(mRotDelta);}}
|
||||||
|
inline void SetMotionTimeStamp( int t ) { mTimeStamp = theFxHelper.mTime + t; }
|
||||||
|
inline int GetMotionTimeStamp() { return mTimeStamp; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //FX_PRIMITIVES_H_INC
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,497 @@
|
||||||
|
|
||||||
|
#if !defined(FX_UTIL_H_INC)
|
||||||
|
#include "FxUtil.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include "../qcommon/sstring.h"
|
||||||
|
typedef sstring_t fxString_t;
|
||||||
|
|
||||||
|
#if !defined(FX_PARSING_H_INC)
|
||||||
|
#include "FxParsing.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FX_SCHEDULER_H_INC
|
||||||
|
#define FX_SCHEDULER_H_INC
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
|
||||||
|
#define FX_FILE_PATH "effects"
|
||||||
|
|
||||||
|
#define FX_MAX_TRACE_DIST WORLD_SIZE
|
||||||
|
#define FX_MAX_EFFECTS 150 // how many effects the system can store
|
||||||
|
#define FX_MAX_EFFECT_COMPONENTS 24 // how many primitives an effect can hold, this should be plenty
|
||||||
|
#define FX_MAX_PRIM_NAME 32
|
||||||
|
|
||||||
|
//-----------------------------------------------
|
||||||
|
// These are spawn flags for primitiveTemplates
|
||||||
|
//-----------------------------------------------
|
||||||
|
|
||||||
|
#define FX_ORG_ON_SPHERE 0x00001 // Pretty dang expensive, calculates a point on a sphere/ellipsoid
|
||||||
|
#define FX_AXIS_FROM_SPHERE 0x00002 // Can be used in conjunction with org_on_sphere to cause particles to move out
|
||||||
|
// from the center of the sphere
|
||||||
|
#define FX_ORG_ON_CYLINDER 0x00004 // calculate point on cylinder/disk
|
||||||
|
|
||||||
|
#define FX_ORG2_FROM_TRACE 0x00010
|
||||||
|
#define FX_TRACE_IMPACT_FX 0x00020 // if trace impacts, we should play one of the specified impact fx files
|
||||||
|
#define FX_ORG2_IS_OFFSET 0x00040 // template specified org2 should be the offset from a trace endpos or
|
||||||
|
// passed in org2. You might use this to lend a random flair to the endpos.
|
||||||
|
// Note: this is done pre-trace, so you may have to specify large numbers for this
|
||||||
|
|
||||||
|
#define FX_CHEAP_ORG_CALC 0x00100 // Origin is calculated relative to passed in axis unless this is on.
|
||||||
|
#define FX_CHEAP_ORG2_CALC 0x00200 // Origin2 is calculated relative to passed in axis unless this is on.
|
||||||
|
#define FX_VEL_IS_ABSOLUTE 0x00400 // Velocity isn't relative to passed in axis with this flag on.
|
||||||
|
#define FX_ACCEL_IS_ABSOLUTE 0x00800 // Acceleration isn't relative to passed in axis with this flag on.
|
||||||
|
|
||||||
|
#define FX_RAND_ROT_AROUND_FWD 0x01000 // Randomly rotates up and right around forward vector
|
||||||
|
#define FX_EVEN_DISTRIBUTION 0x02000 // When you have a delay, it normally picks a random time to play. When
|
||||||
|
// this flag is on, it generates an even time distribution
|
||||||
|
#define FX_RGB_COMPONENT_INTERP 0x04000 // Picks a color on the line defined by RGB min & max, default is to pick color in cube defined by min & max
|
||||||
|
|
||||||
|
#define FX_AFFECTED_BY_WIND 0x10000 // we take into account our wind vector when we spawn in
|
||||||
|
|
||||||
|
#define FX_SND_LESS_ATTENUATION 0x20000 // attenuate sounds less
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// CMediaHandles
|
||||||
|
//
|
||||||
|
// Primitive templates might want to use a list of sounds, shaders
|
||||||
|
// or models to get a bit more variation in their effects.
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------
|
||||||
|
class CMediaHandles
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
vector<int> mMediaList;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void AddHandle( int item ) { mMediaList.push_back( item ); }
|
||||||
|
int GetHandle() { if (mMediaList.size()==0) {return 0;}
|
||||||
|
else {return mMediaList[irand(0,mMediaList.size()-1)];} }
|
||||||
|
|
||||||
|
void operator=(const CMediaHandles &that );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// CFxRange
|
||||||
|
//
|
||||||
|
// Primitive templates typically use this class to define each of
|
||||||
|
// its members. This is done to make it easier to create effects
|
||||||
|
// with a desired range of characteristics.
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------
|
||||||
|
class CFxRange
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
float mMin;
|
||||||
|
float mMax;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CFxRange() {mMin=0; mMax=0;}
|
||||||
|
|
||||||
|
inline void SetRange(float min,float max) {mMin=min; mMax=max;}
|
||||||
|
inline void SetMin(float min) {mMin=min;}
|
||||||
|
inline void SetMax(float max) {mMax=max;}
|
||||||
|
|
||||||
|
inline float GetMax() const {return mMax;}
|
||||||
|
inline float GetMin() const {return mMin;}
|
||||||
|
|
||||||
|
inline float GetVal(float percent) const {if(mMin == mMax){return mMin;}
|
||||||
|
return (mMin + (mMax - mMin) * percent);}
|
||||||
|
inline float GetVal() const {if(mMin == mMax){return mMin;}
|
||||||
|
return flrand(mMin, mMax);}
|
||||||
|
inline int GetRoundedVal() const {if(mMin == mMax){return mMin;}
|
||||||
|
return (int)(flrand(mMin, mMax) + 0.5f);}
|
||||||
|
|
||||||
|
inline void ForceRange(float min,float max) {if(mMin < min){mMin=min;} if(mMin > max){mMin=max;}
|
||||||
|
if(mMax < min){mMax=min;} if(mMax > max){mMax=max;}}
|
||||||
|
inline void Sort() {if(mMin > mMax){float temp = mMin; mMin=mMax;mMax=temp;}}
|
||||||
|
void operator=(const CFxRange &that) {mMin=that.mMin; mMax=that.mMax;}
|
||||||
|
|
||||||
|
bool operator==(const CFxRange &rhs) const { return ((mMin == rhs.mMin) &&
|
||||||
|
(mMax == rhs.mMax)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------
|
||||||
|
// Supported primitive types
|
||||||
|
//----------------------------
|
||||||
|
|
||||||
|
enum EPrimType
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Particle, // sprite
|
||||||
|
Line,
|
||||||
|
Tail, // comet-like tail thing
|
||||||
|
Cylinder,
|
||||||
|
Emitter, // emits effects as it moves, can also attach a chunk
|
||||||
|
Sound,
|
||||||
|
#ifdef _IMMERSION
|
||||||
|
Force,
|
||||||
|
#endif // _IMMERSION
|
||||||
|
Decal, // projected onto architecture
|
||||||
|
OrientedParticle,
|
||||||
|
Electricity,
|
||||||
|
FxRunner,
|
||||||
|
Light,
|
||||||
|
CameraShake,
|
||||||
|
ScreenFlash
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// CPrimitiveTemplate
|
||||||
|
//
|
||||||
|
// The primitive template is used to spawn 1 or more fx primitives
|
||||||
|
// with the range of characteristics defined by the template.
|
||||||
|
//
|
||||||
|
// As such, I just made this one huge shared class knowing that
|
||||||
|
// there won't be many of them in memory at once, and we won't
|
||||||
|
// be dynamically creating and deleting them mid-game. Also,
|
||||||
|
// note that not every primitive type will use all of these fields.
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------
|
||||||
|
class CPrimitiveTemplate
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// These kinds of things should not even be allowed to be accessed publicly
|
||||||
|
bool mCopy;
|
||||||
|
int mRefCount; // For a copy of a primitive...when we figure out how many items we want to spawn,
|
||||||
|
// we'll store that here and then decrement us for each we actually spawn. When we
|
||||||
|
// hit zero, we are no longer used and so we can just free ourselves
|
||||||
|
|
||||||
|
char mName[FX_MAX_PRIM_NAME];
|
||||||
|
|
||||||
|
EPrimType mType;
|
||||||
|
|
||||||
|
CFxRange mSpawnDelay;
|
||||||
|
CFxRange mSpawnCount;
|
||||||
|
CFxRange mLife;
|
||||||
|
int mCullRange;
|
||||||
|
|
||||||
|
CMediaHandles mMediaHandles;
|
||||||
|
CMediaHandles mImpactFxHandles;
|
||||||
|
CMediaHandles mDeathFxHandles;
|
||||||
|
CMediaHandles mEmitterFxHandles;
|
||||||
|
CMediaHandles mPlayFxHandles;
|
||||||
|
|
||||||
|
int mFlags; // These need to get passed on to the primitive
|
||||||
|
int mSpawnFlags; // These are only used to control spawning, but never get passed to prims.
|
||||||
|
|
||||||
|
vec3_t mMin;
|
||||||
|
vec3_t mMax;
|
||||||
|
|
||||||
|
CFxRange mOrigin1X;
|
||||||
|
CFxRange mOrigin1Y;
|
||||||
|
CFxRange mOrigin1Z;
|
||||||
|
|
||||||
|
CFxRange mOrigin2X;
|
||||||
|
CFxRange mOrigin2Y;
|
||||||
|
CFxRange mOrigin2Z;
|
||||||
|
|
||||||
|
CFxRange mRadius; // spawn on sphere/ellipse/disk stuff.
|
||||||
|
CFxRange mHeight;
|
||||||
|
|
||||||
|
CFxRange mRotation;
|
||||||
|
CFxRange mRotationDelta;
|
||||||
|
|
||||||
|
CFxRange mAngle1;
|
||||||
|
CFxRange mAngle2;
|
||||||
|
CFxRange mAngle3;
|
||||||
|
|
||||||
|
CFxRange mAngle1Delta;
|
||||||
|
CFxRange mAngle2Delta;
|
||||||
|
CFxRange mAngle3Delta;
|
||||||
|
|
||||||
|
CFxRange mVelX;
|
||||||
|
CFxRange mVelY;
|
||||||
|
CFxRange mVelZ;
|
||||||
|
|
||||||
|
CFxRange mAccelX;
|
||||||
|
CFxRange mAccelY;
|
||||||
|
CFxRange mAccelZ;
|
||||||
|
|
||||||
|
CFxRange mGravity;
|
||||||
|
|
||||||
|
CFxRange mDensity;
|
||||||
|
CFxRange mVariance;
|
||||||
|
|
||||||
|
CFxRange mRedStart;
|
||||||
|
CFxRange mGreenStart;
|
||||||
|
CFxRange mBlueStart;
|
||||||
|
|
||||||
|
CFxRange mRedEnd;
|
||||||
|
CFxRange mGreenEnd;
|
||||||
|
CFxRange mBlueEnd;
|
||||||
|
|
||||||
|
CFxRange mRGBParm;
|
||||||
|
|
||||||
|
CFxRange mAlphaStart;
|
||||||
|
CFxRange mAlphaEnd;
|
||||||
|
CFxRange mAlphaParm;
|
||||||
|
|
||||||
|
CFxRange mSizeStart;
|
||||||
|
CFxRange mSizeEnd;
|
||||||
|
CFxRange mSizeParm;
|
||||||
|
|
||||||
|
CFxRange mSize2Start;
|
||||||
|
CFxRange mSize2End;
|
||||||
|
CFxRange mSize2Parm;
|
||||||
|
|
||||||
|
CFxRange mLengthStart;
|
||||||
|
CFxRange mLengthEnd;
|
||||||
|
CFxRange mLengthParm;
|
||||||
|
|
||||||
|
CFxRange mTexCoordS;
|
||||||
|
CFxRange mTexCoordT;
|
||||||
|
|
||||||
|
CFxRange mElasticity;
|
||||||
|
|
||||||
|
|
||||||
|
// Lower level parsing utilities
|
||||||
|
bool ParseVector( const char *val, vec3_t min, vec3_t max );
|
||||||
|
bool ParseFloat( const char *val, float *min, float *max );
|
||||||
|
bool ParseGroupFlags( const char *val, int *flags );
|
||||||
|
|
||||||
|
// Base key processing
|
||||||
|
// Note that these all have their own parse functions in case it becomes important to do certain kinds
|
||||||
|
// of validation specific to that type.
|
||||||
|
bool ParseMin( const char *val );
|
||||||
|
bool ParseMax( const char *val );
|
||||||
|
bool ParseDelay( const char *val );
|
||||||
|
bool ParseCount( const char *val );
|
||||||
|
bool ParseLife( const char *val );
|
||||||
|
bool ParseElasticity( const char *val );
|
||||||
|
bool ParseFlags( const char *val );
|
||||||
|
bool ParseSpawnFlags( const char *val );
|
||||||
|
|
||||||
|
bool ParseOrigin1( const char *val );
|
||||||
|
bool ParseOrigin2( const char *val );
|
||||||
|
bool ParseRadius( const char *val );
|
||||||
|
bool ParseHeight( const char *val );
|
||||||
|
bool ParseRotation( const char *val );
|
||||||
|
bool ParseRotationDelta( const char *val );
|
||||||
|
bool ParseAngle( const char *val );
|
||||||
|
bool ParseAngleDelta( const char *val );
|
||||||
|
bool ParseVelocity( const char *val );
|
||||||
|
bool ParseAcceleration( const char *val );
|
||||||
|
bool ParseGravity( const char *val );
|
||||||
|
bool ParseDensity( const char *val );
|
||||||
|
bool ParseVariance( const char *val );
|
||||||
|
|
||||||
|
// Group type processing
|
||||||
|
bool ParseRGB( CGPGroup *grp );
|
||||||
|
bool ParseAlpha( CGPGroup *grp );
|
||||||
|
bool ParseSize( CGPGroup *grp );
|
||||||
|
bool ParseSize2( CGPGroup *grp );
|
||||||
|
bool ParseLength( CGPGroup *grp );
|
||||||
|
|
||||||
|
bool ParseModels( CGPValue *grp );
|
||||||
|
bool ParseShaders( CGPValue *grp );
|
||||||
|
bool ParseSounds( CGPValue *grp );
|
||||||
|
#ifdef _IMMERSION
|
||||||
|
bool ParseForces( CGPValue *grp );
|
||||||
|
#endif // _IMMERSION
|
||||||
|
|
||||||
|
bool ParseImpactFxStrings( CGPValue *grp );
|
||||||
|
bool ParseDeathFxStrings( CGPValue *grp );
|
||||||
|
bool ParseEmitterFxStrings( CGPValue *grp );
|
||||||
|
bool ParsePlayFxStrings( CGPValue *grp );
|
||||||
|
|
||||||
|
// Group keys
|
||||||
|
bool ParseRGBStart( const char *val );
|
||||||
|
bool ParseRGBEnd( const char *val );
|
||||||
|
bool ParseRGBParm( const char *val );
|
||||||
|
bool ParseRGBFlags( const char *val );
|
||||||
|
|
||||||
|
bool ParseAlphaStart( const char *val );
|
||||||
|
bool ParseAlphaEnd( const char *val );
|
||||||
|
bool ParseAlphaParm( const char *val );
|
||||||
|
bool ParseAlphaFlags( const char *val );
|
||||||
|
|
||||||
|
bool ParseSizeStart( const char *val );
|
||||||
|
bool ParseSizeEnd( const char *val );
|
||||||
|
bool ParseSizeParm( const char *val );
|
||||||
|
bool ParseSizeFlags( const char *val );
|
||||||
|
|
||||||
|
bool ParseSize2Start( const char *val );
|
||||||
|
bool ParseSize2End( const char *val );
|
||||||
|
bool ParseSize2Parm( const char *val );
|
||||||
|
bool ParseSize2Flags( const char *val );
|
||||||
|
|
||||||
|
bool ParseLengthStart( const char *val );
|
||||||
|
bool ParseLengthEnd( const char *val );
|
||||||
|
bool ParseLengthParm( const char *val );
|
||||||
|
bool ParseLengthFlags( const char *val );
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CPrimitiveTemplate();
|
||||||
|
~CPrimitiveTemplate() {};
|
||||||
|
|
||||||
|
bool ParsePrimitive( CGPGroup *grp );
|
||||||
|
|
||||||
|
void operator=(const CPrimitiveTemplate &that);
|
||||||
|
};
|
||||||
|
|
||||||
|
// forward declaration
|
||||||
|
struct SEffectTemplate;
|
||||||
|
|
||||||
|
// Effects are built of one or more primitives
|
||||||
|
struct SEffectTemplate
|
||||||
|
{
|
||||||
|
bool mInUse;
|
||||||
|
bool mCopy;
|
||||||
|
char mEffectName[MAX_QPATH]; // is this extraneous??
|
||||||
|
int mPrimitiveCount;
|
||||||
|
int mRepeatDelay;
|
||||||
|
CPrimitiveTemplate *mPrimitives[FX_MAX_EFFECT_COMPONENTS];
|
||||||
|
|
||||||
|
bool operator == (const char * name) const
|
||||||
|
{
|
||||||
|
return !stricmp( mEffectName, name );
|
||||||
|
}
|
||||||
|
void operator=(const SEffectTemplate &that);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// CFxScheduler
|
||||||
|
//
|
||||||
|
// The scheduler not only handles requests to play an effect, it
|
||||||
|
// tracks the request throughout its life if necessary, creating
|
||||||
|
// any of the delayed components as needed.
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------
|
||||||
|
// needs to be in global space now (loadsave stuff)
|
||||||
|
|
||||||
|
#define MAX_LOOPED_FX 32
|
||||||
|
// We hold a looped effect here
|
||||||
|
struct SLoopedEffect
|
||||||
|
{
|
||||||
|
int mId; // effect id
|
||||||
|
int mBoltInfo; // used to determine which bolt on the ghoul2 model we should be attaching this effect to
|
||||||
|
int mNextTime; //time to render again
|
||||||
|
int mLoopStopTime; //time to die
|
||||||
|
bool mPortalEffect; // rww - render this before skyportals, and not in the normal world view.
|
||||||
|
bool mIsRelative; // bolt this puppy on keep it updated
|
||||||
|
};
|
||||||
|
|
||||||
|
class CFxScheduler
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
// We hold a scheduled effect here
|
||||||
|
struct SScheduledEffect
|
||||||
|
{
|
||||||
|
CPrimitiveTemplate *mpTemplate; // primitive template
|
||||||
|
int mStartTime;
|
||||||
|
char mModelNum; // uset to determine which ghoul2 model we want to bolt this effect to
|
||||||
|
char mBoltNum; // used to determine which bolt on the ghoul2 model we should be attaching this effect to
|
||||||
|
short mEntNum; // used to determine which entity this ghoul model is attached to.
|
||||||
|
short mClientID; // FIXME: redundant. this is used for muzzle bolts, merge into normal bolting
|
||||||
|
bool mPortalEffect; // rww - render this before skyportals, and not in the normal world view.
|
||||||
|
bool mIsRelative; // bolt this puppy on keep it updated
|
||||||
|
vec3_t mOrigin;
|
||||||
|
vec3_t mAxis[3];
|
||||||
|
|
||||||
|
bool operator <= (const int time) const
|
||||||
|
{
|
||||||
|
return mStartTime <= time;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Looped Effects get stored and reschedule at mRepeatRate */
|
||||||
|
|
||||||
|
// must be in sync with gLoopedEffectArray[MAX_LOOPED_FX]!
|
||||||
|
//
|
||||||
|
SLoopedEffect mLoopedEffectArray[MAX_LOOPED_FX];
|
||||||
|
|
||||||
|
int ScheduleLoopedEffect( int id, int boltInfo, bool isPortal, int iLoopTime, bool isRelative );
|
||||||
|
void AddLoopedEffects( );
|
||||||
|
|
||||||
|
|
||||||
|
// this makes looking up the index based on the string name much easier
|
||||||
|
typedef map<fxString_t, int> TEffectID;
|
||||||
|
|
||||||
|
typedef list<SScheduledEffect*> TScheduledEffect;
|
||||||
|
|
||||||
|
// Effects
|
||||||
|
SEffectTemplate mEffectTemplates[FX_MAX_EFFECTS];
|
||||||
|
TEffectID mEffectIDs; // if you only have the unique effect name, you'll have to use this to get the ID.
|
||||||
|
|
||||||
|
// List of scheduled effects that will need to be created at the correct time.
|
||||||
|
TScheduledEffect mFxSchedule;
|
||||||
|
|
||||||
|
|
||||||
|
// Private function prototypes
|
||||||
|
SEffectTemplate *GetNewEffectTemplate( int *id, const char *file );
|
||||||
|
|
||||||
|
void AddPrimitiveToEffect( SEffectTemplate *fx, CPrimitiveTemplate *prim );
|
||||||
|
int ParseEffect( const char *file, CGPGroup *base );
|
||||||
|
|
||||||
|
void CreateEffect( CPrimitiveTemplate *fx, const vec3_t origin, vec3_t axis[3], int lateTime, int clientID = -1, int modelNum = -1, int boltNum = -1 );
|
||||||
|
void CreateEffect( CPrimitiveTemplate *fx, int clientID, int lateTime );
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CFxScheduler();
|
||||||
|
|
||||||
|
void LoadSave_Read();
|
||||||
|
void LoadSave_Write();
|
||||||
|
void FX_CopeWithAnyLoadedSaveGames();
|
||||||
|
|
||||||
|
int RegisterEffect( const char *file, bool bHasCorrectPath = false ); // handles pre-caching
|
||||||
|
|
||||||
|
|
||||||
|
// Nasty overloaded madness
|
||||||
|
void PlayEffect( int id, vec3_t org, bool isPortal = false ); // uses a default up axis
|
||||||
|
void PlayEffect( int id, vec3_t org, vec3_t fwd, bool isPortal = false ); // builds arbitrary perp. right vector, does a cross product to define up
|
||||||
|
void PlayEffect( int id, vec3_t origin, vec3_t axis[3], const int boltInfo=-1, const int entNum=-1, bool isPortal = false, int iLoopTime = false, bool isRelative = false );
|
||||||
|
void PlayEffect( const char *file, vec3_t org, bool isPortal = false ); // uses a default up axis
|
||||||
|
void PlayEffect( const char *file, vec3_t org, vec3_t fwd, bool isPortal = false ); // builds arbitrary perp. right vector, does a cross product to define up
|
||||||
|
void PlayEffect( const char *file, vec3_t origin, vec3_t axis[3], const int boltInfo, const int entNum, bool isPortal = false, int iLoopTime = false, bool isRelative = false );
|
||||||
|
|
||||||
|
//for muzzle
|
||||||
|
void PlayEffect( const char *file, int clientID, bool isPortal = false );
|
||||||
|
|
||||||
|
#ifdef _IMMERSION // for ff-system
|
||||||
|
void PlayEffect( int id, int clientNum, vec3_t org, vec3_t fwd, bool isPortal = false );
|
||||||
|
void PlayEffect( const char *file, int clientNum, vec3_t origin, vec3_t forward, bool isPortal = false );
|
||||||
|
#endif // _IMMERSION
|
||||||
|
|
||||||
|
void StopEffect( const char *file, const int boltInfo, bool isPortal = false ); //find a scheduled Looping effect with these parms and kill it
|
||||||
|
|
||||||
|
void AddScheduledEffects( bool portal ); // call once per CGame frame [rww ammendment - twice now actually, but first only renders portal effects]
|
||||||
|
|
||||||
|
int NumScheduledFx() { return mFxSchedule.size(); }
|
||||||
|
void Clean(bool bRemoveTemplates = true, int idToPreserve = 0); // clean out the system
|
||||||
|
|
||||||
|
// FX Override functions
|
||||||
|
SEffectTemplate *GetEffectCopy( int fxHandle, int *newHandle );
|
||||||
|
SEffectTemplate *GetEffectCopy( const char *file, int *newHandle );
|
||||||
|
|
||||||
|
CPrimitiveTemplate *GetPrimitiveCopy( SEffectTemplate *effectCopy, const char *componentName );
|
||||||
|
};
|
||||||
|
|
||||||
|
//-------------------
|
||||||
|
// The one and only
|
||||||
|
//-------------------
|
||||||
|
extern CFxScheduler theFxScheduler;
|
||||||
|
|
||||||
|
|
||||||
|
#endif // FX_SCHEDULER_H_INC
|
|
@ -0,0 +1,215 @@
|
||||||
|
// this include must remain at the top of every FXxxxx.CPP file
|
||||||
|
#include "common_headers.h"
|
||||||
|
|
||||||
|
#if !defined(FX_SCHEDULER_H_INC)
|
||||||
|
#include "FxScheduler.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "cg_media.h" //for cgs.model_draw for G2
|
||||||
|
|
||||||
|
extern vmCvar_t fx_debug;
|
||||||
|
extern vmCvar_t fx_freeze;
|
||||||
|
|
||||||
|
extern void CG_ExplosionEffects( vec3_t origin, float intensity, int radius, int time );
|
||||||
|
|
||||||
|
// Stuff for the FxHelper
|
||||||
|
//------------------------------------------------------
|
||||||
|
void SFxHelper::Init()
|
||||||
|
{
|
||||||
|
mTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
void SFxHelper::Print( const char *msg, ... )
|
||||||
|
{
|
||||||
|
#ifndef FINAL_BUILD
|
||||||
|
|
||||||
|
va_list argptr;
|
||||||
|
char text[1024];
|
||||||
|
|
||||||
|
va_start( argptr, msg );
|
||||||
|
vsprintf( text, msg, argptr );
|
||||||
|
va_end( argptr );
|
||||||
|
|
||||||
|
gi.Printf( text );
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
void SFxHelper::AdjustTime( int frameTime )
|
||||||
|
{
|
||||||
|
if ( fx_freeze.integer || ( frameTime <= 0 ))
|
||||||
|
{
|
||||||
|
// Allow no time progression when we are paused.
|
||||||
|
mFrameTime = 0;
|
||||||
|
mFloatFrameTime = 0.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( !cg_paused.integer )
|
||||||
|
{
|
||||||
|
if ( frameTime > 300 ) // hack for returning from paused and time bursts
|
||||||
|
{
|
||||||
|
frameTime = 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
mFrameTime = frameTime;
|
||||||
|
mFloatFrameTime = mFrameTime * 0.001f;
|
||||||
|
mTime += mFrameTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
int SFxHelper::OpenFile( const char *file, fileHandle_t *fh, int mode )
|
||||||
|
{
|
||||||
|
// char path[256];
|
||||||
|
|
||||||
|
// sprintf( path, "%s/%s", FX_FILE_PATH, file );
|
||||||
|
return cgi_FS_FOpenFile( file, fh, FS_READ );
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
int SFxHelper::ReadFile( void *data, int len, fileHandle_t fh )
|
||||||
|
{
|
||||||
|
return cgi_FS_Read( data, len, fh );
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
void SFxHelper::CloseFile( fileHandle_t fh )
|
||||||
|
{
|
||||||
|
cgi_FS_FCloseFile( fh );
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
void SFxHelper::PlaySound( const vec3_t org, int entityNum, int entchannel, int sfxHandle )
|
||||||
|
{
|
||||||
|
cgi_S_StartSound( org, entityNum, entchannel, sfxHandle );
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
void SFxHelper::PlayLocalSound( int sfxHandle, int channelNum )
|
||||||
|
{
|
||||||
|
cgi_S_StartLocalSound(sfxHandle, channelNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
void SFxHelper::Trace( trace_t *tr, vec3_t start, vec3_t min, vec3_t max,
|
||||||
|
vec3_t end, int skipEntNum, int flags )
|
||||||
|
{
|
||||||
|
CG_Trace( tr, start, min, max, end, skipEntNum, flags );
|
||||||
|
}
|
||||||
|
|
||||||
|
void SFxHelper::G2Trace( trace_t *tr, vec3_t start, vec3_t min, vec3_t max,
|
||||||
|
vec3_t end, int skipEntNum, int flags )
|
||||||
|
{
|
||||||
|
//CG_Trace( tr, start, min, max, end, skipEntNum, flags, G2_COLLIDE );
|
||||||
|
gi.trace(tr, start, NULL, NULL, end, skipEntNum, flags, G2_COLLIDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
void SFxHelper::AddFxToScene( refEntity_t *ent )
|
||||||
|
{
|
||||||
|
cgi_R_AddRefEntityToScene( ent );
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
int SFxHelper::RegisterShader( const char *shader )
|
||||||
|
{
|
||||||
|
return cgi_R_RegisterShader( shader );
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
int SFxHelper::RegisterSound( const char *sound )
|
||||||
|
{
|
||||||
|
return cgi_S_RegisterSound( sound );
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
int SFxHelper::RegisterModel( const char *model )
|
||||||
|
{
|
||||||
|
return cgi_R_RegisterModel( model );
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
void SFxHelper::AddLightToScene( vec3_t org, float radius, float red, float green, float blue )
|
||||||
|
{
|
||||||
|
cgi_R_AddLightToScene( org, radius, red, green, blue );
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
void SFxHelper::AddPolyToScene( int shader, int count, polyVert_t *verts )
|
||||||
|
{
|
||||||
|
cgi_R_AddPolyToScene( shader, count, verts );
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
void SFxHelper::CameraShake( vec3_t origin, float intensity, int radius, int time )
|
||||||
|
{
|
||||||
|
CG_ExplosionEffects( origin, intensity, radius, time );
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
int SFxHelper::GetOriginAxisFromBolt(const centity_t ¢, int modelNum, int boltNum, vec3_t /*out*/origin, vec3_t /*out*/axis[3])
|
||||||
|
{
|
||||||
|
if ((cg.time-cent.snapShotTime) > 200)
|
||||||
|
{ //you were added more than 200ms ago, so I say you are no longer valid/in our snapshot.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int doesBoltExist;
|
||||||
|
mdxaBone_t boltMatrix;
|
||||||
|
vec3_t G2Angles = {cent.lerpAngles[0] , cent.lerpAngles[1], cent.lerpAngles[2]};
|
||||||
|
if ( cent.currentState.eType == ET_PLAYER )
|
||||||
|
{//players use cent.renderAngles
|
||||||
|
VectorCopy( cent.renderAngles, G2Angles );
|
||||||
|
|
||||||
|
if ( cent.gent //has a game entity
|
||||||
|
&& cent.gent->s.m_iVehicleNum != 0 //in a vehicle
|
||||||
|
&& cent.gent->m_pVehicle //have a valid vehicle pointer
|
||||||
|
&& cent.gent->m_pVehicle->m_pVehicleInfo->type != VH_FIGHTER //it's not a fighter
|
||||||
|
&& cent.gent->m_pVehicle->m_pVehicleInfo->type != VH_SPEEDER //not a speeder
|
||||||
|
)
|
||||||
|
{
|
||||||
|
G2Angles[PITCH]=0;
|
||||||
|
G2Angles[ROLL] =0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// go away and get me the bolt position for this frame please
|
||||||
|
doesBoltExist = gi.G2API_GetBoltMatrix(cent.gent->ghoul2, modelNum,
|
||||||
|
boltNum, &boltMatrix, G2Angles,
|
||||||
|
cent.lerpOrigin, cg.time, cgs.model_draw,
|
||||||
|
cent.currentState.modelScale);
|
||||||
|
// set up the axis and origin we need for the actual effect spawning
|
||||||
|
origin[0] = boltMatrix.matrix[0][3];
|
||||||
|
origin[1] = boltMatrix.matrix[1][3];
|
||||||
|
origin[2] = boltMatrix.matrix[2][3];
|
||||||
|
|
||||||
|
axis[1][0] = boltMatrix.matrix[0][0];
|
||||||
|
axis[1][1] = boltMatrix.matrix[1][0];
|
||||||
|
axis[1][2] = boltMatrix.matrix[2][0];
|
||||||
|
|
||||||
|
axis[0][0] = boltMatrix.matrix[0][1];
|
||||||
|
axis[0][1] = boltMatrix.matrix[1][1];
|
||||||
|
axis[0][2] = boltMatrix.matrix[2][1];
|
||||||
|
|
||||||
|
axis[2][0] = boltMatrix.matrix[0][2];
|
||||||
|
axis[2][1] = boltMatrix.matrix[1][2];
|
||||||
|
axis[2][2] = boltMatrix.matrix[2][2];
|
||||||
|
return doesBoltExist;
|
||||||
|
}
|
||||||
|
#ifdef _IMMERSION
|
||||||
|
//------------------------------------------------------
|
||||||
|
ffHandle_t SFxHelper::RegisterForce( const char *force, int channel )
|
||||||
|
{
|
||||||
|
return cgi_FF_Register( force, channel );
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------
|
||||||
|
void SFxHelper::PlayForce( int entityNum, ffHandle_t ff )
|
||||||
|
{
|
||||||
|
cgi_FF_Start( ff, entityNum );
|
||||||
|
}
|
||||||
|
#endif // _IMMERSION
|
|
@ -0,0 +1,84 @@
|
||||||
|
|
||||||
|
#if !defined(CG_LOCAL_H_INC)
|
||||||
|
#include "cg_local.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FX_SYSTEM_H_INC
|
||||||
|
#define FX_SYSTEM_H_INC
|
||||||
|
|
||||||
|
|
||||||
|
#define irand Q_irand
|
||||||
|
#define flrand Q_flrand
|
||||||
|
|
||||||
|
extern vmCvar_t fx_debug;
|
||||||
|
extern vmCvar_t fx_freeze;
|
||||||
|
|
||||||
|
inline void Vector2Clear(vec2_t a)
|
||||||
|
{
|
||||||
|
a[0] = 0.0f;
|
||||||
|
a[1] = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Vector2Set(vec2_t a,float b,float c)
|
||||||
|
{
|
||||||
|
a[0] = b;
|
||||||
|
a[1] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Vector2Copy(vec2_t src,vec2_t dst)
|
||||||
|
{
|
||||||
|
dst[0] = src[0];
|
||||||
|
dst[1] = src[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern void CG_CalcEntityLerpPositions( centity_t * );
|
||||||
|
|
||||||
|
|
||||||
|
struct SFxHelper
|
||||||
|
{
|
||||||
|
int mTime;
|
||||||
|
int mFrameTime;
|
||||||
|
float mFloatFrameTime;
|
||||||
|
|
||||||
|
void Init();
|
||||||
|
void AdjustTime( int time );
|
||||||
|
|
||||||
|
// These functions are wrapped and used by the fx system in case it makes things a bit more portable
|
||||||
|
void Print( const char *msg, ... );
|
||||||
|
|
||||||
|
// File handling
|
||||||
|
int OpenFile( const char *path, fileHandle_t *fh, int mode );
|
||||||
|
int ReadFile( void *data, int len, fileHandle_t fh );
|
||||||
|
void CloseFile( fileHandle_t fh );
|
||||||
|
|
||||||
|
// Sound
|
||||||
|
void PlaySound( const vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx );
|
||||||
|
void PlayLocalSound( sfxHandle_t sfx, int channelNum );
|
||||||
|
int RegisterSound( const char *sound );
|
||||||
|
|
||||||
|
#ifdef _IMMERSION
|
||||||
|
void PlayForce( int entityNum, ffHandle_t ff );
|
||||||
|
ffHandle_t RegisterForce( const char *force, int channel );
|
||||||
|
#endif // _IMMERSION
|
||||||
|
//G2
|
||||||
|
int GetOriginAxisFromBolt(const centity_t ¢, int modelNum, int boltNum, vec3_t /*out*/origin, vec3_t /*out*/*axis);
|
||||||
|
|
||||||
|
// Physics/collision
|
||||||
|
void Trace( trace_t *tr, vec3_t start, vec3_t min, vec3_t max, vec3_t end, int skipEntNum, int flags );
|
||||||
|
void G2Trace( trace_t *tr, vec3_t start, vec3_t min, vec3_t max, vec3_t end, int skipEntNum, int flags );
|
||||||
|
|
||||||
|
void AddFxToScene( refEntity_t *ent );
|
||||||
|
void AddLightToScene( vec3_t org, float radius, float red, float green, float blue );
|
||||||
|
|
||||||
|
int RegisterShader( const char *shader );
|
||||||
|
int RegisterModel( const char *model );
|
||||||
|
|
||||||
|
void AddPolyToScene( int shader, int count, polyVert_t *verts );
|
||||||
|
|
||||||
|
void CameraShake( vec3_t origin, float intensity, int radius, int time );
|
||||||
|
};
|
||||||
|
|
||||||
|
extern SFxHelper theFxHelper;
|
||||||
|
|
||||||
|
#endif // FX_SYSTEM_H_INC
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,130 @@
|
||||||
|
|
||||||
|
#if !defined(FX_PRIMITIVES_H_INC)
|
||||||
|
#include "FxPrimitives.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FX_UTIL_H_INC
|
||||||
|
#define FX_UTIL_H_INC
|
||||||
|
|
||||||
|
|
||||||
|
bool FX_Free( void ); // ditches all active effects;
|
||||||
|
int FX_Init( void ); // called in CG_Init to purge the fx system.
|
||||||
|
void FX_Add( bool portal ); // called every cgame frame to add all fx into the scene.
|
||||||
|
void FX_Stop( void ); // ditches all active effects without touching the templates.
|
||||||
|
|
||||||
|
bool FX_ActiveFx(void); // returns whether there are any active or scheduled effects
|
||||||
|
|
||||||
|
|
||||||
|
CParticle *FX_AddParticle( int clientID, const vec3_t org, const vec3_t vel, const vec3_t accel, float gravity,
|
||||||
|
float size1, float size2, float sizeParm,
|
||||||
|
float alpha1, float alpha2, float alphaParm,
|
||||||
|
const vec3_t rgb1, const vec3_t rgb2, float rgbParm,
|
||||||
|
float rotation, float rotationDelta,
|
||||||
|
const vec3_t min, const vec3_t max, float elasticity,
|
||||||
|
int deathID, int impactID,
|
||||||
|
int killTime, qhandle_t shader, int flags, int modelNum = -1, int boltNum = -1 );
|
||||||
|
|
||||||
|
CLine *FX_AddLine( int clientID, vec3_t start, vec3_t end,
|
||||||
|
float size1, float size2, float sizeParm,
|
||||||
|
float alpha1, float alpha2, float alphaParm,
|
||||||
|
vec3_t rgb1, vec3_t rgb2, float rgbParm,
|
||||||
|
int killTime, qhandle_t shader, int impactFX_id, int flags, int modelNum = -1, int boltNum = -1 );
|
||||||
|
|
||||||
|
CElectricity *FX_AddElectricity( int clientID, vec3_t start, vec3_t end, float size1, float size2, float sizeParm,
|
||||||
|
float alpha1, float alpha2, float alphaParm,
|
||||||
|
vec3_t sRGB, vec3_t eRGB, float rgbParm,
|
||||||
|
float chaos, int killTime, qhandle_t shader, int flags, int modelNum = -1, int boltNum = -1 );
|
||||||
|
|
||||||
|
CTail *FX_AddTail( int clientID, vec3_t org, vec3_t vel, vec3_t accel,
|
||||||
|
float size1, float size2, float sizeParm,
|
||||||
|
float length1, float length2, float lengthParm,
|
||||||
|
float alpha1, float alpha2, float alphaParm,
|
||||||
|
vec3_t rgb1, vec3_t rgb2, float rgbParm,
|
||||||
|
vec3_t min, vec3_t max, float elasticity,
|
||||||
|
int deathID, int impactID,
|
||||||
|
int killTime, qhandle_t shader, int flags, int modelNum = -1, int boltNum = -1 );
|
||||||
|
|
||||||
|
CCylinder *FX_AddCylinder( int clientID, vec3_t start, vec3_t normal,
|
||||||
|
float size1s, float size1e, float size1Parm,
|
||||||
|
float size2s, float size2e, float size2Parm,
|
||||||
|
float length1, float length2, float lengthParm,
|
||||||
|
float alpha1, float alpha2, float alphaParm,
|
||||||
|
vec3_t rgb1, vec3_t rgb2, float rgbParm,
|
||||||
|
int killTime, qhandle_t shader, int flags, int modelNum = -1, int boltNum = -1 );
|
||||||
|
|
||||||
|
CEmitter *FX_AddEmitter( vec3_t org, vec3_t vel, vec3_t accel,
|
||||||
|
float size1, float size2, float sizeParm,
|
||||||
|
float alpha1, float alpha2, float alphaParm,
|
||||||
|
vec3_t rgb1, vec3_t rgb2, float rgbParm,
|
||||||
|
vec3_t angs, vec3_t deltaAngs,
|
||||||
|
vec3_t min, vec3_t max, float elasticity,
|
||||||
|
int deathID, int impactID, int emitterID,
|
||||||
|
float density, float variance,
|
||||||
|
int killTime, qhandle_t model, int flags );
|
||||||
|
|
||||||
|
CLight *FX_AddLight( vec3_t org, float size1, float size2, float sizeParm,
|
||||||
|
vec3_t rgb1, vec3_t rgb2, float rgbParm,
|
||||||
|
int killTime, int flags );
|
||||||
|
|
||||||
|
COrientedParticle *FX_AddOrientedParticle( int clientID, vec3_t org, vec3_t norm, vec3_t vel, vec3_t accel,
|
||||||
|
float size1, float size2, float sizeParm,
|
||||||
|
float alpha1, float alpha2, float alphaParm,
|
||||||
|
vec3_t rgb1, vec3_t rgb2, float rgbParm,
|
||||||
|
float rotation, float rotationDelta,
|
||||||
|
vec3_t min, vec3_t max, float bounce,
|
||||||
|
int deathID, int impactID,
|
||||||
|
int killTime, qhandle_t shader, int flags, int modelNum = -1, int boltNum = -1 );
|
||||||
|
|
||||||
|
CPoly *FX_AddPoly( vec3_t *verts, vec2_t *st, int numVerts,
|
||||||
|
vec3_t vel, vec3_t accel,
|
||||||
|
float alpha1, float alpha2, float alphaParm,
|
||||||
|
vec3_t rgb1, vec3_t rgb2, float rgbParm,
|
||||||
|
vec3_t rotationDelta, float bounce, int motionDelay,
|
||||||
|
int killTime, qhandle_t shader, int flags );
|
||||||
|
|
||||||
|
CFlash *FX_AddFlash( vec3_t origin, vec3_t sRGB, vec3_t eRGB, float rgbParm,
|
||||||
|
int life, qhandle_t shader, int flags );
|
||||||
|
|
||||||
|
|
||||||
|
// Included for backwards compatibility with CHC and for doing quick programmatic effects.
|
||||||
|
void FX_AddSprite( vec3_t origin, vec3_t vel, vec3_t accel,
|
||||||
|
float scale, float dscale,
|
||||||
|
float sAlpha, float eAlpha,
|
||||||
|
float rotation, float bounce,
|
||||||
|
int life, qhandle_t shader, int flags = 0 );
|
||||||
|
|
||||||
|
void FX_AddSprite( vec3_t origin, vec3_t vel, vec3_t accel,
|
||||||
|
float scale, float dscale,
|
||||||
|
float sAlpha, float eAlpha,
|
||||||
|
vec3_t sRGB, vec3_t eRGB,
|
||||||
|
float rotation, float bounce,
|
||||||
|
int life, qhandle_t shader, int flags = 0 );
|
||||||
|
|
||||||
|
void FX_AddLine( vec3_t start, vec3_t end, float stScale,
|
||||||
|
float width, float dwidth,
|
||||||
|
float sAlpha, float eAlpha,
|
||||||
|
int life, qhandle_t shader, int flags = 0 );
|
||||||
|
|
||||||
|
void FX_AddLine( vec3_t start, vec3_t end, float stScale,
|
||||||
|
float width, float dwidth,
|
||||||
|
float sAlpha, float eAlpha,
|
||||||
|
vec3_t sRGB, vec3_t eRGB,
|
||||||
|
int life, qhandle_t shader, int flags = 0 );
|
||||||
|
|
||||||
|
void FX_AddQuad( vec3_t origin, vec3_t normal,
|
||||||
|
vec3_t vel, vec3_t accel,
|
||||||
|
float sradius, float eradius,
|
||||||
|
float salpha, float ealpha,
|
||||||
|
vec3_t sRGB, vec3_t eRGB,
|
||||||
|
float rotation, int life, qhandle_t shader, int flags = 0 );
|
||||||
|
|
||||||
|
CBezier *FX_AddBezier( const vec3_t start, const vec3_t end,
|
||||||
|
const vec3_t control1, const vec3_t control1Vel,
|
||||||
|
const vec3_t control2, const vec3_t control2Vel,
|
||||||
|
float size1, float size2, float sizeParm,
|
||||||
|
float alpha1, float alpha2, float alphaParm,
|
||||||
|
const vec3_t sRGB, const vec3_t eRGB, const float rgbParm,
|
||||||
|
int killTime, qhandle_t shader, int flags = 0 );
|
||||||
|
|
||||||
|
|
||||||
|
#endif //FX_UTIL_H_INC
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue