You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
586 lines
21 KiB
586 lines
21 KiB
//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
// $NoKeywords: $
|
|
//=====================================================================================//
|
|
|
|
#include "cbase.h"
|
|
#include "StaticCollisionPolyhedronCache.h"
|
|
#include "engine/IEngineTrace.h"
|
|
#include "edict.h"
|
|
|
|
#include "tier0/memdbgon.h"
|
|
|
|
|
|
class CPolyhedron_LumpedMemory : public CPolyhedron //we'll be allocating one big chunk of memory for all our polyhedrons. No individual will own any memory.
|
|
{
|
|
public:
|
|
virtual void Release( void ) { Assert( false ); };
|
|
static CPolyhedron_LumpedMemory *AllocateAt( void *pMemory, int iVertices, int iLines, int iIndices, int iPolygons )
|
|
{
|
|
#include "tier0/memdbgoff.h" //the following placement new doesn't compile with memory debugging
|
|
CPolyhedron_LumpedMemory *pAllocated = new ( pMemory ) CPolyhedron_LumpedMemory;
|
|
#include "tier0/memdbgon.h"
|
|
|
|
pAllocated->iVertexCount = iVertices;
|
|
pAllocated->iLineCount = iLines;
|
|
pAllocated->iIndexCount = iIndices;
|
|
pAllocated->iPolygonCount = iPolygons;
|
|
pAllocated->pVertices = (Vector *)(pAllocated + 1); //start vertex memory at the end of the class
|
|
pAllocated->pLines = (Polyhedron_IndexedLine_t *)(pAllocated->pVertices + iVertices);
|
|
pAllocated->pIndices = (Polyhedron_IndexedLineReference_t *)(pAllocated->pLines + iLines);
|
|
pAllocated->pPolygons = (Polyhedron_IndexedPolygon_t *)(pAllocated->pIndices + iIndices);
|
|
|
|
return pAllocated;
|
|
}
|
|
};
|
|
|
|
static void *s_BrushPolyhedronMemory = NULL;
|
|
static void *s_StaticPropPolyhedronMemory = NULL;
|
|
|
|
CStaticCollisionPolyhedronCache g_StaticCollisionPolyhedronCache;
|
|
|
|
void sv_portal_staticcollisioncache_cache_ChangeFN( IConVar *var, const char *pOldValue, float flOldValue )
|
|
{
|
|
g_StaticCollisionPolyhedronCache.ForceRefreshOnMapLoad(); //force a reload on restart/mapchange
|
|
}
|
|
|
|
ConVar sv_portal_staticcollisioncache_cachebrushes( "sv_portal_staticcollisioncache_cachebrushes", IsPS3() ? "0" : "1", FCVAR_REPLICATED, "Cache all solid brushes as polyhedrons on level load", sv_portal_staticcollisioncache_cache_ChangeFN );
|
|
ConVar sv_portal_staticcollisioncache_cachestaticprops( "sv_portal_staticcollisioncache_cachestaticprops", IsPS3() ? "0" : "1", FCVAR_REPLICATED, "Cache all solid static props' vcollides as polyhedrons on level load", sv_portal_staticcollisioncache_cache_ChangeFN );
|
|
|
|
|
|
typedef vcollide_t *VCollidePtr; //needed for key comparison function syntax
|
|
static bool CollideablePtr_KeyCompareFunc( const VCollidePtr &a, const VCollidePtr &b )
|
|
{
|
|
return a < b;
|
|
};
|
|
|
|
CStaticCollisionPolyhedronCache::CStaticCollisionPolyhedronCache( void )
|
|
: m_CollideableIndicesMap( CollideablePtr_KeyCompareFunc )
|
|
{
|
|
|
|
}
|
|
|
|
CStaticCollisionPolyhedronCache::~CStaticCollisionPolyhedronCache( void )
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
void CStaticCollisionPolyhedronCache::LevelInitPreEntity( void )
|
|
{
|
|
//keep the cached data if the source hasn't changed.
|
|
if(
|
|
#if defined( GAME_DLL )
|
|
(gpGlobals->eLoadType != MapLoad_LoadGame) || //always reload on new game, only in case the map file contents changed (level designers using "restart")
|
|
#endif
|
|
(Q_stricmp( m_CachedMap, MapName() ) != 0) ) //different map than we have cached.
|
|
{
|
|
// New map or the last load was a transition, fully update the cache
|
|
m_CachedMap.Set( MapName() );
|
|
|
|
Update();
|
|
}
|
|
}
|
|
|
|
void CStaticCollisionPolyhedronCache::Shutdown( void )
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
|
|
void CStaticCollisionPolyhedronCache::Clear( void )
|
|
{
|
|
//The uses one big lump of memory to store polyhedrons. No need to Release() the polyhedrons.
|
|
|
|
//Brushes
|
|
{
|
|
m_BrushPolyhedrons.RemoveAll();
|
|
if( s_BrushPolyhedronMemory != NULL )
|
|
{
|
|
delete []s_BrushPolyhedronMemory;
|
|
s_BrushPolyhedronMemory = NULL;
|
|
}
|
|
}
|
|
|
|
//Static props
|
|
{
|
|
m_CollideableIndicesMap.RemoveAll();
|
|
m_StaticPropPolyhedrons.RemoveAll();
|
|
if( s_StaticPropPolyhedronMemory != NULL )
|
|
{
|
|
delete []s_StaticPropPolyhedronMemory;
|
|
s_StaticPropPolyhedronMemory = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
static CPolyhedron *ConvertBrushToPolyhedron( int iBrushNumber, int iContentsMask, bool bTempPolyhedron )
|
|
{
|
|
int iBrushContents = 0;
|
|
int iPlanesNeeded = -enginetrace->GetBrushInfo( iBrushNumber, iBrushContents, NULL, 0 );
|
|
if( (iPlanesNeeded == 0) || ((iContentsMask & iBrushContents) == 0) )
|
|
return NULL;
|
|
|
|
uint8 *pMemory;
|
|
void *pDeleteMemory;
|
|
float *fStackPlanes;
|
|
BrushSideInfo_t *brushSides;
|
|
size_t iMemoryNeeded = iPlanesNeeded * ((sizeof( float ) * 4) + sizeof( BrushSideInfo_t ));
|
|
|
|
if( iMemoryNeeded < (64 * 1024) )
|
|
{
|
|
//use stack memory
|
|
pMemory = (uint8 *)stackalloc( iMemoryNeeded );
|
|
pDeleteMemory = NULL;
|
|
}
|
|
else
|
|
{
|
|
pMemory = new uint8 [iMemoryNeeded];
|
|
pDeleteMemory = pMemory;
|
|
}
|
|
|
|
|
|
fStackPlanes = (float *)pMemory;
|
|
brushSides = (BrushSideInfo_t *)(pMemory + (iPlanesNeeded * (sizeof( float ) * 4)));
|
|
int iPlaneCount = enginetrace->GetBrushInfo( iBrushNumber, iBrushContents, brushSides, iPlanesNeeded );
|
|
|
|
CPolyhedron *pRetVal = NULL;
|
|
Assert( iPlaneCount == iPlanesNeeded );
|
|
if( iPlaneCount == iPlanesNeeded )
|
|
{
|
|
for( int i = 0; i != iPlaneCount; ++i )
|
|
{
|
|
fStackPlanes[(i * 4) + 0] = brushSides[i].plane.normal.x;
|
|
fStackPlanes[(i * 4) + 1] = brushSides[i].plane.normal.y;
|
|
fStackPlanes[(i * 4) + 2] = brushSides[i].plane.normal.z;
|
|
fStackPlanes[(i * 4) + 3] = brushSides[i].plane.dist;
|
|
}
|
|
|
|
pRetVal = GeneratePolyhedronFromPlanes( fStackPlanes, iPlaneCount, (1.0f/16.0f), bTempPolyhedron );
|
|
}
|
|
|
|
if( pDeleteMemory )
|
|
{
|
|
delete []pDeleteMemory;
|
|
}
|
|
|
|
return pRetVal;
|
|
}
|
|
|
|
void CStaticCollisionPolyhedronCache::Update( void )
|
|
{
|
|
Clear();
|
|
|
|
if( gpGlobals->IsClient() && (g_pGameRules->IsMultiplayer() == false) ) //not going to need this data on the client
|
|
return;
|
|
|
|
if( !sv_portal_staticcollisioncache_cachebrushes.GetBool() && !sv_portal_staticcollisioncache_cachestaticprops.GetBool() )
|
|
return;
|
|
|
|
//There's no efficient way to know exactly how much memory we'll need to cache off all these polyhedrons.
|
|
//So we're going to allocated temporary workspaces as we need them and consolidate into one allocation at the end.
|
|
const size_t workSpaceSize = 1024 * 1024; //1MB. Fairly arbitrary size for a workspace. Brushes usually use 1-3MB in the end. Static props usually use about half as much as brushes.
|
|
|
|
uint8 *workSpaceAllocations[256];
|
|
size_t usedSpaceInWorkspace[256];
|
|
unsigned int workSpacesAllocated = 0;
|
|
uint8 *pCurrentWorkSpace = new uint8 [workSpaceSize];
|
|
size_t roomLeftInWorkSpace = workSpaceSize;
|
|
workSpaceAllocations[workSpacesAllocated] = pCurrentWorkSpace;
|
|
usedSpaceInWorkspace[workSpacesAllocated] = 0;
|
|
++workSpacesAllocated;
|
|
|
|
|
|
//brushes
|
|
if( sv_portal_staticcollisioncache_cachebrushes.GetBool() )
|
|
{
|
|
int iBrush = 0;
|
|
int iBrushContents;
|
|
|
|
CPolyhedron *pTempPolyhedron = ConvertBrushToPolyhedron( iBrush, MASK_SOLID | CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP, true );
|
|
|
|
while( (pTempPolyhedron != NULL) || (enginetrace->GetBrushInfo( iBrush, iBrushContents, NULL, 0 ) != 0) )
|
|
{
|
|
if( pTempPolyhedron )
|
|
{
|
|
size_t memRequired = (sizeof( CPolyhedron_LumpedMemory )) +
|
|
(sizeof( Vector ) * pTempPolyhedron->iVertexCount) +
|
|
(sizeof( Polyhedron_IndexedLine_t ) * pTempPolyhedron->iLineCount) +
|
|
(sizeof( Polyhedron_IndexedLineReference_t ) * pTempPolyhedron->iIndexCount) +
|
|
(sizeof( Polyhedron_IndexedPolygon_t ) * pTempPolyhedron->iPolygonCount);
|
|
|
|
Assert( memRequired < workSpaceSize );
|
|
|
|
if( roomLeftInWorkSpace < memRequired )
|
|
{
|
|
usedSpaceInWorkspace[workSpacesAllocated - 1] = workSpaceSize - roomLeftInWorkSpace;
|
|
|
|
pCurrentWorkSpace = new uint8 [workSpaceSize];
|
|
roomLeftInWorkSpace = workSpaceSize;
|
|
workSpaceAllocations[workSpacesAllocated] = pCurrentWorkSpace;
|
|
usedSpaceInWorkspace[workSpacesAllocated] = 0;
|
|
++workSpacesAllocated;
|
|
}
|
|
|
|
CPolyhedron *pWorkSpacePolyhedron = CPolyhedron_LumpedMemory::AllocateAt( pCurrentWorkSpace,
|
|
pTempPolyhedron->iVertexCount,
|
|
pTempPolyhedron->iLineCount,
|
|
pTempPolyhedron->iIndexCount,
|
|
pTempPolyhedron->iPolygonCount );
|
|
|
|
pCurrentWorkSpace += memRequired;
|
|
roomLeftInWorkSpace -= memRequired;
|
|
|
|
memcpy( pWorkSpacePolyhedron->pVertices, pTempPolyhedron->pVertices, pTempPolyhedron->iVertexCount * sizeof( Vector ) );
|
|
memcpy( pWorkSpacePolyhedron->pLines, pTempPolyhedron->pLines, pTempPolyhedron->iLineCount * sizeof( Polyhedron_IndexedLine_t ) );
|
|
memcpy( pWorkSpacePolyhedron->pIndices, pTempPolyhedron->pIndices, pTempPolyhedron->iIndexCount * sizeof( Polyhedron_IndexedLineReference_t ) );
|
|
memcpy( pWorkSpacePolyhedron->pPolygons, pTempPolyhedron->pPolygons, pTempPolyhedron->iPolygonCount * sizeof( Polyhedron_IndexedPolygon_t ) );
|
|
|
|
m_BrushPolyhedrons.AddToTail( pWorkSpacePolyhedron );
|
|
|
|
pTempPolyhedron->Release();
|
|
}
|
|
else
|
|
{
|
|
m_BrushPolyhedrons.AddToTail( NULL );
|
|
}
|
|
|
|
++iBrush;
|
|
pTempPolyhedron = ConvertBrushToPolyhedron( iBrush, MASK_SOLID | CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP, true );
|
|
}
|
|
|
|
usedSpaceInWorkspace[workSpacesAllocated - 1] = workSpaceSize - roomLeftInWorkSpace;
|
|
|
|
if( usedSpaceInWorkspace[0] != 0 ) //At least a little bit of memory was used.
|
|
{
|
|
//consolidate workspaces into a single memory chunk
|
|
size_t totalMemoryNeeded = 0;
|
|
for( unsigned int i = 0; i != workSpacesAllocated; ++i )
|
|
{
|
|
totalMemoryNeeded += usedSpaceInWorkspace[i];
|
|
}
|
|
|
|
uint8 *pFinalDest = new uint8 [totalMemoryNeeded];
|
|
s_BrushPolyhedronMemory = pFinalDest;
|
|
|
|
DevMsg( 2, "CStaticCollisionPolyhedronCache: Used %.2f KB to cache %d brush polyhedrons.\n", ((float)totalMemoryNeeded) / 1024.0f, m_BrushPolyhedrons.Count() );
|
|
|
|
int iCount = m_BrushPolyhedrons.Count();
|
|
for( int i = 0; i != iCount; ++i )
|
|
{
|
|
CPolyhedron_LumpedMemory *pSource = (CPolyhedron_LumpedMemory *)m_BrushPolyhedrons[i];
|
|
|
|
if( pSource == NULL )
|
|
continue;
|
|
|
|
size_t memRequired = (sizeof( CPolyhedron_LumpedMemory )) +
|
|
(sizeof( Vector ) * pSource->iVertexCount) +
|
|
(sizeof( Polyhedron_IndexedLine_t ) * pSource->iLineCount) +
|
|
(sizeof( Polyhedron_IndexedLineReference_t ) * pSource->iIndexCount) +
|
|
(sizeof( Polyhedron_IndexedPolygon_t ) * pSource->iPolygonCount);
|
|
|
|
CPolyhedron_LumpedMemory *pDest = (CPolyhedron_LumpedMemory *)pFinalDest;
|
|
m_BrushPolyhedrons[i] = pDest;
|
|
pFinalDest += memRequired;
|
|
|
|
int memoryOffset = ((uint8 *)pDest) - ((uint8 *)pSource);
|
|
|
|
memcpy( pDest, pSource, memRequired );
|
|
//move all the pointers to their new location.
|
|
pDest->pVertices = (Vector *)(((uint8 *)(pDest->pVertices)) + memoryOffset);
|
|
pDest->pLines = (Polyhedron_IndexedLine_t *)(((uint8 *)(pDest->pLines)) + memoryOffset);
|
|
pDest->pIndices = (Polyhedron_IndexedLineReference_t *)(((uint8 *)(pDest->pIndices)) + memoryOffset);
|
|
pDest->pPolygons = (Polyhedron_IndexedPolygon_t *)(((uint8 *)(pDest->pPolygons)) + memoryOffset);
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned int iBrushWorkSpaces = workSpacesAllocated;
|
|
workSpacesAllocated = 1;
|
|
pCurrentWorkSpace = workSpaceAllocations[0];
|
|
usedSpaceInWorkspace[0] = 0;
|
|
roomLeftInWorkSpace = workSpaceSize;
|
|
|
|
//static props
|
|
if( sv_portal_staticcollisioncache_cachestaticprops.GetBool() )
|
|
{
|
|
CUtlVector<ICollideable *> StaticPropCollideables;
|
|
staticpropmgr->GetAllStaticProps( &StaticPropCollideables );
|
|
|
|
if( StaticPropCollideables.Count() != 0 )
|
|
{
|
|
ICollideable **pCollideables = StaticPropCollideables.Base();
|
|
ICollideable **pStop = pCollideables + StaticPropCollideables.Count();
|
|
|
|
int iStaticPropIndex = 0;
|
|
do
|
|
{
|
|
ICollideable *pProp = *pCollideables;
|
|
|
|
if( (pProp->GetCollisionModel() != NULL) && (pProp->GetSolid() != SOLID_NONE) && ((pProp->GetSolidFlags() & FSOLID_NOT_SOLID) == 0) )
|
|
{
|
|
vcollide_t *pCollide = modelinfo->GetVCollide( pProp->GetCollisionModel() );
|
|
if( (pCollide != NULL) && (m_CollideableIndicesMap.IsValidIndex( m_CollideableIndicesMap.Find( pCollide ) ) == false) )
|
|
{
|
|
StaticPropPolyhedronCacheInfo_t cacheInfo;
|
|
cacheInfo.iStartIndex = m_StaticPropPolyhedrons.Count();
|
|
for( int i = 0; i != pCollide->solidCount; ++i )
|
|
{
|
|
CPhysConvex *ConvexesArray[1024];
|
|
int iConvexes = physcollision->GetConvexesUsedInCollideable( pCollide->solids[i], ConvexesArray, 1024 );
|
|
|
|
for( int j = 0; j != iConvexes; ++j )
|
|
{
|
|
CPolyhedron *pTempPolyhedron = physcollision->PolyhedronFromConvex( ConvexesArray[j], true );
|
|
if( pTempPolyhedron )
|
|
{
|
|
size_t memRequired = (sizeof( CPolyhedron_LumpedMemory )) +
|
|
(sizeof( Vector ) * pTempPolyhedron->iVertexCount) +
|
|
(sizeof( Polyhedron_IndexedLine_t ) * pTempPolyhedron->iLineCount) +
|
|
(sizeof( Polyhedron_IndexedLineReference_t ) * pTempPolyhedron->iIndexCount) +
|
|
(sizeof( Polyhedron_IndexedPolygon_t ) * pTempPolyhedron->iPolygonCount);
|
|
|
|
Assert( memRequired < workSpaceSize );
|
|
|
|
if( roomLeftInWorkSpace < memRequired )
|
|
{
|
|
usedSpaceInWorkspace[workSpacesAllocated - 1] = workSpaceSize - roomLeftInWorkSpace;
|
|
|
|
if( workSpacesAllocated < iBrushWorkSpaces )
|
|
{
|
|
//re-use a workspace already allocated during brush polyhedron conversion
|
|
pCurrentWorkSpace = workSpaceAllocations[workSpacesAllocated];
|
|
usedSpaceInWorkspace[workSpacesAllocated] = 0;
|
|
}
|
|
else
|
|
{
|
|
//allocate a new workspace
|
|
pCurrentWorkSpace = new uint8 [workSpaceSize];
|
|
workSpaceAllocations[workSpacesAllocated] = pCurrentWorkSpace;
|
|
usedSpaceInWorkspace[workSpacesAllocated] = 0;
|
|
}
|
|
|
|
roomLeftInWorkSpace = workSpaceSize;
|
|
++workSpacesAllocated;
|
|
}
|
|
|
|
CPolyhedron *pWorkSpacePolyhedron = CPolyhedron_LumpedMemory::AllocateAt( pCurrentWorkSpace,
|
|
pTempPolyhedron->iVertexCount,
|
|
pTempPolyhedron->iLineCount,
|
|
pTempPolyhedron->iIndexCount,
|
|
pTempPolyhedron->iPolygonCount );
|
|
|
|
pCurrentWorkSpace += memRequired;
|
|
roomLeftInWorkSpace -= memRequired;
|
|
|
|
memcpy( pWorkSpacePolyhedron->pVertices, pTempPolyhedron->pVertices, pTempPolyhedron->iVertexCount * sizeof( Vector ) );
|
|
memcpy( pWorkSpacePolyhedron->pLines, pTempPolyhedron->pLines, pTempPolyhedron->iLineCount * sizeof( Polyhedron_IndexedLine_t ) );
|
|
memcpy( pWorkSpacePolyhedron->pIndices, pTempPolyhedron->pIndices, pTempPolyhedron->iIndexCount * sizeof( Polyhedron_IndexedLineReference_t ) );
|
|
memcpy( pWorkSpacePolyhedron->pPolygons, pTempPolyhedron->pPolygons, pTempPolyhedron->iPolygonCount * sizeof( Polyhedron_IndexedPolygon_t ) );
|
|
|
|
m_StaticPropPolyhedrons.AddToTail( pWorkSpacePolyhedron );
|
|
|
|
#if defined( DBGFLAG_ASSERT ) && 0
|
|
CPhysConvex *pConvex = physcollision->ConvexFromConvexPolyhedron( *pTempPolyhedron );
|
|
AssertMsg( pConvex != NULL, "Conversion from Convex to Polyhedron was irreversable" );
|
|
if( pConvex )
|
|
{
|
|
physcollision->ConvexFree( pConvex );
|
|
}
|
|
#endif
|
|
|
|
pTempPolyhedron->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
cacheInfo.iNumPolyhedrons = m_StaticPropPolyhedrons.Count() - cacheInfo.iStartIndex;
|
|
Assert( m_CollideableIndicesMap.IsValidIndex( m_CollideableIndicesMap.Find( pCollide ) ) == false );
|
|
m_CollideableIndicesMap.Insert( pCollide, cacheInfo );
|
|
}
|
|
}
|
|
|
|
++iStaticPropIndex;
|
|
++pCollideables;
|
|
} while( pCollideables != pStop );
|
|
|
|
|
|
usedSpaceInWorkspace[workSpacesAllocated - 1] = workSpaceSize - roomLeftInWorkSpace;
|
|
|
|
if( usedSpaceInWorkspace[0] != 0 ) //At least a little bit of memory was used.
|
|
{
|
|
//consolidate workspaces into a single memory chunk
|
|
size_t totalMemoryNeeded = 0;
|
|
for( unsigned int i = 0; i != workSpacesAllocated; ++i )
|
|
{
|
|
totalMemoryNeeded += usedSpaceInWorkspace[i];
|
|
}
|
|
|
|
uint8 *pFinalDest = new uint8 [totalMemoryNeeded];
|
|
s_StaticPropPolyhedronMemory = pFinalDest;
|
|
|
|
DevMsg( 2, "CStaticCollisionPolyhedronCache: Used %.2f KB to cache %d static prop polyhedrons.\n", ((float)totalMemoryNeeded) / 1024.0f, m_StaticPropPolyhedrons.Count() );
|
|
|
|
int iCount = m_StaticPropPolyhedrons.Count();
|
|
for( int i = 0; i != iCount; ++i )
|
|
{
|
|
CPolyhedron_LumpedMemory *pSource = (CPolyhedron_LumpedMemory *)m_StaticPropPolyhedrons[i];
|
|
|
|
size_t memRequired = (sizeof( CPolyhedron_LumpedMemory )) +
|
|
(sizeof( Vector ) * pSource->iVertexCount) +
|
|
(sizeof( Polyhedron_IndexedLine_t ) * pSource->iLineCount) +
|
|
(sizeof( Polyhedron_IndexedLineReference_t ) * pSource->iIndexCount) +
|
|
(sizeof( Polyhedron_IndexedPolygon_t ) * pSource->iPolygonCount);
|
|
|
|
CPolyhedron_LumpedMemory *pDest = (CPolyhedron_LumpedMemory *)pFinalDest;
|
|
m_StaticPropPolyhedrons[i] = pDest;
|
|
pFinalDest += memRequired;
|
|
|
|
int memoryOffset = ((uint8 *)pDest) - ((uint8 *)pSource);
|
|
|
|
memcpy( pDest, pSource, memRequired );
|
|
//move all the pointers to their new location.
|
|
pDest->pVertices = (Vector *)(((uint8 *)(pDest->pVertices)) + memoryOffset);
|
|
pDest->pLines = (Polyhedron_IndexedLine_t *)(((uint8 *)(pDest->pLines)) + memoryOffset);
|
|
pDest->pIndices = (Polyhedron_IndexedLineReference_t *)(((uint8 *)(pDest->pIndices)) + memoryOffset);
|
|
pDest->pPolygons = (Polyhedron_IndexedPolygon_t *)(((uint8 *)(pDest->pPolygons)) + memoryOffset);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( iBrushWorkSpaces > workSpacesAllocated )
|
|
workSpacesAllocated = iBrushWorkSpaces;
|
|
|
|
for( unsigned int i = 0; i != workSpacesAllocated; ++i )
|
|
{
|
|
delete []workSpaceAllocations[i];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const CPolyhedron *CStaticCollisionPolyhedronCache::GetBrushPolyhedron( int iBrushNumber )
|
|
{
|
|
Assert( (iBrushNumber < m_BrushPolyhedrons.Count()) || ((sv_portal_staticcollisioncache_cachebrushes.GetBool() == false) && (m_CachedMap.IsEmpty() == false)) );
|
|
|
|
if( iBrushNumber < 0 )
|
|
return NULL;
|
|
|
|
if( (iBrushNumber >= m_BrushPolyhedrons.Count()) || (m_BrushPolyhedrons[iBrushNumber] == NULL) )
|
|
{
|
|
return ConvertBrushToPolyhedron( iBrushNumber, MASK_ALL, false );
|
|
}
|
|
|
|
return m_BrushPolyhedrons[iBrushNumber];
|
|
}
|
|
|
|
void CStaticCollisionPolyhedronCache::ReleaseBrushPolyhedron( int iBrushNumber, const CPolyhedron *pPolyhedron )
|
|
{
|
|
//we only actually do any work here if there was a polyhedron and it's not in our cache.
|
|
if( pPolyhedron )
|
|
{
|
|
Assert( iBrushNumber >= 0 );
|
|
if( (iBrushNumber >= m_BrushPolyhedrons.Count()) || (pPolyhedron != m_BrushPolyhedrons[iBrushNumber]) )
|
|
{
|
|
//not a cached version. Must have generated it on the fly, release it
|
|
((CPolyhedron *)pPolyhedron)->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
int CStaticCollisionPolyhedronCache::GetStaticPropPolyhedrons( ICollideable *pStaticProp, const CPolyhedron **pOutputPolyhedronArray, int iOutputArraySize )
|
|
{
|
|
if( pStaticProp->GetCollisionModel() == NULL )
|
|
return 0;
|
|
|
|
vcollide_t *pCollide = modelinfo->GetVCollide( pStaticProp->GetCollisionModel() );
|
|
if( pCollide == NULL )
|
|
return 0;
|
|
|
|
unsigned short iPropIndex = m_CollideableIndicesMap.Find( pCollide );
|
|
|
|
int iWrotePolyhedrons = 0;
|
|
|
|
if( m_CollideableIndicesMap.IsValidIndex( iPropIndex ) )
|
|
{
|
|
StaticPropPolyhedronCacheInfo_t cacheInfo = m_CollideableIndicesMap.Element( iPropIndex );
|
|
|
|
if( cacheInfo.iNumPolyhedrons < iOutputArraySize )
|
|
{
|
|
iOutputArraySize = cacheInfo.iNumPolyhedrons;
|
|
}
|
|
|
|
for( int i = cacheInfo.iStartIndex; iWrotePolyhedrons != iOutputArraySize; ++i, ++iWrotePolyhedrons )
|
|
{
|
|
pOutputPolyhedronArray[iWrotePolyhedrons] = m_StaticPropPolyhedrons[i];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( (pStaticProp->GetSolid() == SOLID_NONE) || ((pStaticProp->GetSolidFlags() & FSOLID_NOT_SOLID) != 0) )
|
|
return 0;
|
|
|
|
for( int i = 0; i != pCollide->solidCount; ++i )
|
|
{
|
|
CPhysConvex *ConvexesArray[1024];
|
|
int iConvexes = physcollision->GetConvexesUsedInCollideable( pCollide->solids[i], ConvexesArray, 1024 );
|
|
|
|
if( iConvexes > iOutputArraySize )
|
|
{
|
|
iConvexes = iOutputArraySize;
|
|
}
|
|
|
|
for( int j = 0; j != iConvexes; ++j )
|
|
{
|
|
pOutputPolyhedronArray[iWrotePolyhedrons] = physcollision->PolyhedronFromConvex( ConvexesArray[j], false );
|
|
if( pOutputPolyhedronArray[iWrotePolyhedrons] != NULL )
|
|
{
|
|
++iWrotePolyhedrons;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return iWrotePolyhedrons;
|
|
}
|
|
|
|
void CStaticCollisionPolyhedronCache::ReleaseStaticPropPolyhedrons( ICollideable *pStaticProp, const CPolyhedron **pPolyhedrons, int iPolyhedronCount )
|
|
{
|
|
if( pStaticProp->GetCollisionModel() != NULL )
|
|
{
|
|
vcollide_t *pCollide = modelinfo->GetVCollide( pStaticProp->GetCollisionModel() );
|
|
if( pCollide != NULL )
|
|
{
|
|
if( m_CollideableIndicesMap.IsValidIndex( m_CollideableIndicesMap.Find( pCollide ) ) )
|
|
{
|
|
//these polyhedrons came from the cache, do nothing.
|
|
#if defined( DBGFLAG_ASSERT )
|
|
for( int i = 0; i < iPolyhedronCount; ++i )
|
|
{
|
|
Assert( m_StaticPropPolyhedrons.IsValidIndex( m_StaticPropPolyhedrons.Find((CPolyhedron *)pPolyhedrons[i]) ) );
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if defined( DBGFLAG_ASSERT )
|
|
for( int i = 0; i < iPolyhedronCount; ++i )
|
|
{
|
|
Assert( m_StaticPropPolyhedrons.IsValidIndex( m_StaticPropPolyhedrons.Find((CPolyhedron *)pPolyhedrons[i]) ) == false );
|
|
}
|
|
#endif
|
|
|
|
//if we're down here, the polyhedrons were not in the cache. Release them
|
|
for( int i = 0; i != iPolyhedronCount; ++i )
|
|
{
|
|
((CPolyhedron *)pPolyhedrons[i])->Release();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|