summaryrefslogtreecommitdiff
path: root/game/shared/portal/StaticCollisionPolyhedronCache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/shared/portal/StaticCollisionPolyhedronCache.cpp')
-rw-r--r--game/shared/portal/StaticCollisionPolyhedronCache.cpp485
1 files changed, 485 insertions, 0 deletions
diff --git a/game/shared/portal/StaticCollisionPolyhedronCache.cpp b/game/shared/portal/StaticCollisionPolyhedronCache.cpp
new file mode 100644
index 0000000..7f91060
--- /dev/null
+++ b/game/shared/portal/StaticCollisionPolyhedronCache.cpp
@@ -0,0 +1,485 @@
+//========= Copyright 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 ) { };
+ 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 uint8 *s_BrushPolyhedronMemory = NULL;
+static uint8 *s_StaticPropPolyhedronMemory = NULL;
+
+CStaticCollisionPolyhedronCache g_StaticCollisionPolyhedronCache;
+
+typedef ICollideable *ICollideablePtr; //needed for key comparison function syntax
+static bool CollideablePtr_KeyCompareFunc( const ICollideablePtr &a, const ICollideablePtr &b )
+{
+ return a < b;
+};
+
+CStaticCollisionPolyhedronCache::CStaticCollisionPolyhedronCache( void )
+: m_CollideableIndicesMap( CollideablePtr_KeyCompareFunc )
+{
+
+}
+
+CStaticCollisionPolyhedronCache::~CStaticCollisionPolyhedronCache( void )
+{
+ Clear();
+}
+
+void CStaticCollisionPolyhedronCache::LevelInitPreEntity( void )
+{
+
+ // FIXME: Fast updates would be nice but this method doesn't work with the recent changes to standard containers.
+ // For now we're going with the quick fix of always doing a full update. -Jeep
+
+// if( Q_stricmp( m_CachedMap, MapName() ) != 0 )
+// {
+// // New map or the last load was a transition, fully update the cache
+// m_CachedMap.Set( MapName() );
+
+ Update();
+// }
+// else
+// {
+// // No need for a full update, but we need to remap static prop ICollideable's in the old system to the new system
+// for( int i = m_CollideableIndicesMap.Count(); --i >= 0; )
+// {
+//#ifdef _DEBUG
+// StaticPropPolyhedronCacheInfo_t cacheInfo = m_CollideableIndicesMap.Element(i);
+//#endif
+// m_CollideableIndicesMap.Reinsert( staticpropmgr->GetStaticPropByIndex( m_CollideableIndicesMap.Element(i).iStaticPropIndex ), i );
+//
+// Assert( (m_CollideableIndicesMap.Element(i).iStartIndex == cacheInfo.iStartIndex) &&
+// (m_CollideableIndicesMap.Element(i).iNumPolyhedrons == cacheInfo.iNumPolyhedrons) &&
+// (m_CollideableIndicesMap.Element(i).iStaticPropIndex == cacheInfo.iStaticPropIndex) ); //I'm assuming this doesn't cause a reindex of the unordered list, if it does then this needs to be rewritten
+// }
+// }
+}
+
+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;
+ }
+ }
+}
+
+void CStaticCollisionPolyhedronCache::Update( void )
+{
+ Clear();
+
+ //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
+ {
+ int iBrush = 0;
+ CUtlVector<Vector4D> Planes;
+
+ float fStackPlanes[4 * 400]; //400 is a crapload of planes in my opinion
+
+ while( enginetrace->GetBrushInfo( iBrush, &Planes, NULL ) )
+ {
+ int iPlaneCount = Planes.Count();
+ AssertMsg( iPlaneCount != 0, "A brush with no planes???????" );
+
+ const Vector4D *pReturnedPlanes = Planes.Base();
+
+ CPolyhedron *pTempPolyhedron;
+
+ if( iPlaneCount > 400 )
+ {
+ // o_O, we'll have to get more memory to transform this brush
+ float *pNonstackPlanes = new float [4 * iPlaneCount];
+
+ for( int i = 0; i != iPlaneCount; ++i )
+ {
+ pNonstackPlanes[(i * 4) + 0] = pReturnedPlanes[i].x;
+ pNonstackPlanes[(i * 4) + 1] = pReturnedPlanes[i].y;
+ pNonstackPlanes[(i * 4) + 2] = pReturnedPlanes[i].z;
+ pNonstackPlanes[(i * 4) + 3] = pReturnedPlanes[i].w;
+ }
+
+ pTempPolyhedron = GeneratePolyhedronFromPlanes( pNonstackPlanes, iPlaneCount, 0.01f, true );
+
+ delete []pNonstackPlanes;
+ }
+ else
+ {
+ for( int i = 0; i != iPlaneCount; ++i )
+ {
+ fStackPlanes[(i * 4) + 0] = pReturnedPlanes[i].x;
+ fStackPlanes[(i * 4) + 1] = pReturnedPlanes[i].y;
+ fStackPlanes[(i * 4) + 2] = pReturnedPlanes[i].z;
+ fStackPlanes[(i * 4) + 3] = pReturnedPlanes[i].w;
+ }
+
+ pTempPolyhedron = GeneratePolyhedronFromPlanes( fStackPlanes, iPlaneCount, 0.01f, 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;
+
+ 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;
+ }
+
+ 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
+ {
+ 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;
+ vcollide_t *pCollide = modelinfo->GetVCollide( pProp->GetCollisionModel() );
+ StaticPropPolyhedronCacheInfo_t cacheInfo;
+ cacheInfo.iStartIndex = m_StaticPropPolyhedrons.Count();
+
+ if( pCollide != NULL )
+ {
+ VMatrix matToWorldPosition = pProp->CollisionToWorldTransform();
+
+ 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 )
+ {
+ for( int iPointCounter = 0; iPointCounter != pTempPolyhedron->iVertexCount; ++iPointCounter )
+ pTempPolyhedron->pVertices[iPointCounter] = matToWorldPosition * pTempPolyhedron->pVertices[iPointCounter];
+
+ for( int iPolyCounter = 0; iPolyCounter != pTempPolyhedron->iPolygonCount; ++iPolyCounter )
+ pTempPolyhedron->pPolygons[iPolyCounter].polyNormal = matToWorldPosition.ApplyRotation( pTempPolyhedron->pPolygons[iPolyCounter].polyNormal );
+
+
+ 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 );
+
+#ifdef _DEBUG
+ CPhysConvex *pConvex = physcollision->ConvexFromConvexPolyhedron( *pTempPolyhedron );
+ AssertMsg( pConvex != NULL, "Conversion from Convex to Polyhedron was unreversable" );
+ if( pConvex )
+ {
+ physcollision->ConvexFree( pConvex );
+ }
+#endif
+
+ pTempPolyhedron->Release();
+ }
+ }
+ }
+
+ cacheInfo.iNumPolyhedrons = m_StaticPropPolyhedrons.Count() - cacheInfo.iStartIndex;
+ cacheInfo.iStaticPropIndex = iStaticPropIndex;
+ Assert( staticpropmgr->GetStaticPropByIndex( iStaticPropIndex ) == pProp );
+
+ m_CollideableIndicesMap.InsertOrReplace( pProp, 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() );
+
+ if( (iBrushNumber < 0) || (iBrushNumber >= m_BrushPolyhedrons.Count()) )
+ return NULL;
+
+ return m_BrushPolyhedrons[iBrushNumber];
+}
+
+int CStaticCollisionPolyhedronCache::GetStaticPropPolyhedrons( ICollideable *pStaticProp, CPolyhedron **pOutputPolyhedronArray, int iOutputArraySize )
+{
+ unsigned short iPropIndex = m_CollideableIndicesMap.Find( pStaticProp );
+ if( !m_CollideableIndicesMap.IsValidIndex( iPropIndex ) ) //static prop never made it into the cache for some reason (specifically no collision data when this workaround was written)
+ return 0;
+
+ StaticPropPolyhedronCacheInfo_t cacheInfo = m_CollideableIndicesMap.Element( iPropIndex );
+
+ if( cacheInfo.iNumPolyhedrons < iOutputArraySize )
+ iOutputArraySize = cacheInfo.iNumPolyhedrons;
+
+ for( int i = cacheInfo.iStartIndex, iWriteIndex = 0; iWriteIndex != iOutputArraySize; ++i, ++iWriteIndex )
+ {
+ pOutputPolyhedronArray[iWriteIndex] = m_StaticPropPolyhedrons[i];
+ }
+
+ return iOutputArraySize;
+}
+
+
+
+
+
+