Jedi Academy Release

This commit is contained in:
James Monroe 2013-04-04 17:35:38 -05:00
commit 684d1bcb3b
1520 changed files with 1152378 additions and 0 deletions

View File

@ -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.

BIN
code/ALut.lib Normal file

Binary file not shown.

BIN
code/EaxMan.dll Normal file

Binary file not shown.

BIN
code/IFC22.dll Normal file

Binary file not shown.

88
code/JediAcademy.sln Normal file
View File

@ -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

10
code/JediAcademy.vssscc Normal file
View File

@ -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"
}

BIN
code/OpenAL32.dll Normal file

Binary file not shown.

BIN
code/OpenAL32.lib Normal file

Binary file not shown.

480
code/RMG/RM_Area.cpp Normal file
View File

@ -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

99
code/RMG/RM_Area.h Normal file
View File

@ -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

71
code/RMG/RM_Headers.h Normal file
View File

@ -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

191
code/RMG/RM_Instance.cpp Normal file
View File

@ -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);
}
*/
}

122
code/RMG/RM_Instance.h Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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 );
}
}

View File

@ -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

View File

@ -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 );
}

View File

@ -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

View File

@ -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 );
}

View File

@ -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

402
code/RMG/RM_Manager.cpp Normal file
View File

@ -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;
}

55
code/RMG/RM_Manager.h Normal file
View File

@ -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

1930
code/RMG/RM_Mission.cpp Normal file

File diff suppressed because it is too large Load Diff

129
code/RMG/RM_Mission.h Normal file
View File

@ -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

134
code/RMG/RM_Objective.cpp Normal file
View File

@ -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;
}

65
code/RMG/RM_Objective.h Normal file
View File

@ -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

721
code/RMG/RM_Path.cpp Normal file
View File

@ -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);
}

223
code/RMG/RM_Path.h Normal file
View File

@ -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

533
code/RMG/RM_Terrain.cpp Normal file
View File

@ -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)

97
code/RMG/RM_Terrain.h Normal file
View File

@ -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

BIN
code/RMG/vssver.scc Normal file

Binary file not shown.

419
code/Ragl/graph_region.h Normal file
View File

@ -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

View File

@ -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

1776
code/Ragl/graph_vs.h Normal file

File diff suppressed because it is too large Load Diff

458
code/Ragl/kdtree_vs.h Normal file
View File

@ -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

232
code/Ragl/ragl_common.h Normal file
View File

@ -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

BIN
code/Ragl/vssver.scc Normal file

Binary file not shown.

73
code/Ratl/array_vs.h Normal file
View File

@ -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

218
code/Ratl/bits_vs.h Normal file
View File

@ -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

526
code/Ratl/grid_vs.h Normal file
View File

@ -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

291
code/Ratl/handle_pool_vs.h Normal file
View File

@ -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

200
code/Ratl/hash_pool_vs.h Normal file
View File

@ -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

324
code/Ratl/heap_vs.h Normal file
View File

@ -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

751
code/Ratl/list_vs.h Normal file
View File

@ -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

1629
code/Ratl/map_vs.h Normal file

File diff suppressed because it is too large Load Diff

570
code/Ratl/pool_vs.h Normal file
View File

@ -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

231
code/Ratl/queue_vs.h Normal file
View File

@ -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

130
code/Ratl/ratl.cpp Normal file
View File

@ -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);
}
}
}

1180
code/Ratl/ratl_common.h Normal file

File diff suppressed because it is too large Load Diff

218
code/Ratl/scheduler_vs.h Normal file
View File

@ -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

197
code/Ratl/stack_vs.h Normal file
View File

@ -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

366
code/Ratl/string_vs.h Normal file
View File

@ -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

757
code/Ratl/vector_vs.h Normal file
View File

@ -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

BIN
code/Ratl/vssver.scc Normal file

Binary file not shown.

366
code/Ravl/CBounds.cpp Normal file
View File

@ -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);
}

188
code/Ravl/CBounds.h Normal file
View File

@ -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

165
code/Ravl/CMatrix.h Normal file
View File

@ -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

1154
code/Ravl/CVec.cpp Normal file

File diff suppressed because it is too large Load Diff

1002
code/Ravl/CVec.h Normal file

File diff suppressed because it is too large Load Diff

BIN
code/Ravl/vssver.scc Normal file

Binary file not shown.

378
code/Rufl/hfile.cpp Normal file
View File

@ -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;
}

61
code/Rufl/hfile.h Normal file
View File

@ -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

185
code/Rufl/hstring.cpp Normal file
View File

@ -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

106
code/Rufl/hstring.h Normal file
View File

@ -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

0
code/Rufl/random.cpp Normal file
View File

0
code/Rufl/random.h Normal file
View File

BIN
code/Rufl/vssver.scc Normal file

Binary file not shown.

BIN
code/SHDebug/HA312W32.DLL Normal file

Binary file not shown.

BIN
code/SHDebug/SHW32.DLL Normal file

Binary file not shown.

BIN
code/SHDebug/vssver.scc Normal file

Binary file not shown.

1
code/VU.bat Normal file
View File

@ -0,0 +1 @@
VersionUpdate -ss_ini \\Ravendata1\VSS\central_code\SRCSAFE.INI -ss_prj $/Jedi/Code -header win32/AutoVersion.h -email SW-Everyone -interactive

105
code/cgame/FX_ATSTMain.cpp Normal file
View File

@ -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 );
}

95
code/cgame/FX_Blaster.cpp Normal file
View File

@ -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 );
}

View File

@ -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 );
}

View File

@ -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 );
}

View File

@ -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 );
}

92
code/cgame/FX_DEMP2.cpp Normal file
View File

@ -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;
}

View File

@ -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 );
}

146
code/cgame/FX_Emplaced.cpp Normal file
View File

@ -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 );
}

View File

@ -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( &cent->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 );
}

View File

@ -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 );
}

View File

@ -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 );
}

View File

@ -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 );
}

View File

@ -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 );
}

5
code/cgame/FxParsing.cpp Normal file
View File

@ -0,0 +1,5 @@
// this include must remain at the top of every FXxxxx.CPP file
#include "common_headers.h"

6
code/cgame/FxParsing.h Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#if !defined(FX_PARSING_H_INC)
#define FX_PARSING_H_INC
#endif // FX_PARSING_H

2289
code/cgame/FxPrimitives.cpp Normal file

File diff suppressed because it is too large Load Diff

572
code/cgame/FxPrimitives.h Normal file
View File

@ -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

2049
code/cgame/FxScheduler.cpp Normal file

File diff suppressed because it is too large Load Diff

497
code/cgame/FxScheduler.h Normal file
View File

@ -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

215
code/cgame/FxSystem.cpp Normal file
View File

@ -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 &cent, 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

84
code/cgame/FxSystem.h Normal file
View File

@ -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 &cent, 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

2370
code/cgame/FxTemplate.cpp Normal file

File diff suppressed because it is too large Load Diff

1400
code/cgame/FxUtil.cpp Normal file

File diff suppressed because it is too large Load Diff

130
code/cgame/FxUtil.h Normal file
View File

@ -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

1792
code/cgame/animtable.h Normal file

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