diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/shared/portal/StaticCollisionPolyhedronCache.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/shared/portal/StaticCollisionPolyhedronCache.cpp')
| -rw-r--r-- | game/shared/portal/StaticCollisionPolyhedronCache.cpp | 485 |
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; +} + + + + + + |