Counter Strike : Global Offensive Source Code
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

  1. //========= Copyright � 1996-2006, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=====================================================================================//
  7. #include "cbase.h"
  8. #include "StaticCollisionPolyhedronCache.h"
  9. #include "engine/IEngineTrace.h"
  10. #include "edict.h"
  11. #include "tier0/memdbgon.h"
  12. class CPolyhedron_LumpedMemory : public CPolyhedron //we'll be allocating one big chunk of memory for all our polyhedrons. No individual will own any memory.
  13. {
  14. public:
  15. virtual void Release( void ) { Assert( false ); };
  16. static CPolyhedron_LumpedMemory *AllocateAt( void *pMemory, int iVertices, int iLines, int iIndices, int iPolygons )
  17. {
  18. #include "tier0/memdbgoff.h" //the following placement new doesn't compile with memory debugging
  19. CPolyhedron_LumpedMemory *pAllocated = new ( pMemory ) CPolyhedron_LumpedMemory;
  20. #include "tier0/memdbgon.h"
  21. pAllocated->iVertexCount = iVertices;
  22. pAllocated->iLineCount = iLines;
  23. pAllocated->iIndexCount = iIndices;
  24. pAllocated->iPolygonCount = iPolygons;
  25. pAllocated->pVertices = (Vector *)(pAllocated + 1); //start vertex memory at the end of the class
  26. pAllocated->pLines = (Polyhedron_IndexedLine_t *)(pAllocated->pVertices + iVertices);
  27. pAllocated->pIndices = (Polyhedron_IndexedLineReference_t *)(pAllocated->pLines + iLines);
  28. pAllocated->pPolygons = (Polyhedron_IndexedPolygon_t *)(pAllocated->pIndices + iIndices);
  29. return pAllocated;
  30. }
  31. };
  32. static void *s_BrushPolyhedronMemory = NULL;
  33. static void *s_StaticPropPolyhedronMemory = NULL;
  34. CStaticCollisionPolyhedronCache g_StaticCollisionPolyhedronCache;
  35. void sv_portal_staticcollisioncache_cache_ChangeFN( IConVar *var, const char *pOldValue, float flOldValue )
  36. {
  37. g_StaticCollisionPolyhedronCache.ForceRefreshOnMapLoad(); //force a reload on restart/mapchange
  38. }
  39. 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 );
  40. 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 );
  41. typedef vcollide_t *VCollidePtr; //needed for key comparison function syntax
  42. static bool CollideablePtr_KeyCompareFunc( const VCollidePtr &a, const VCollidePtr &b )
  43. {
  44. return a < b;
  45. };
  46. CStaticCollisionPolyhedronCache::CStaticCollisionPolyhedronCache( void )
  47. : m_CollideableIndicesMap( CollideablePtr_KeyCompareFunc )
  48. {
  49. }
  50. CStaticCollisionPolyhedronCache::~CStaticCollisionPolyhedronCache( void )
  51. {
  52. Clear();
  53. }
  54. void CStaticCollisionPolyhedronCache::LevelInitPreEntity( void )
  55. {
  56. //keep the cached data if the source hasn't changed.
  57. if(
  58. #if defined( GAME_DLL )
  59. (gpGlobals->eLoadType != MapLoad_LoadGame) || //always reload on new game, only in case the map file contents changed (level designers using "restart")
  60. #endif
  61. (Q_stricmp( m_CachedMap, MapName() ) != 0) ) //different map than we have cached.
  62. {
  63. // New map or the last load was a transition, fully update the cache
  64. m_CachedMap.Set( MapName() );
  65. Update();
  66. }
  67. }
  68. void CStaticCollisionPolyhedronCache::Shutdown( void )
  69. {
  70. Clear();
  71. }
  72. void CStaticCollisionPolyhedronCache::Clear( void )
  73. {
  74. //The uses one big lump of memory to store polyhedrons. No need to Release() the polyhedrons.
  75. //Brushes
  76. {
  77. m_BrushPolyhedrons.RemoveAll();
  78. if( s_BrushPolyhedronMemory != NULL )
  79. {
  80. delete []s_BrushPolyhedronMemory;
  81. s_BrushPolyhedronMemory = NULL;
  82. }
  83. }
  84. //Static props
  85. {
  86. m_CollideableIndicesMap.RemoveAll();
  87. m_StaticPropPolyhedrons.RemoveAll();
  88. if( s_StaticPropPolyhedronMemory != NULL )
  89. {
  90. delete []s_StaticPropPolyhedronMemory;
  91. s_StaticPropPolyhedronMemory = NULL;
  92. }
  93. }
  94. }
  95. static CPolyhedron *ConvertBrushToPolyhedron( int iBrushNumber, int iContentsMask, bool bTempPolyhedron )
  96. {
  97. int iBrushContents = 0;
  98. int iPlanesNeeded = -enginetrace->GetBrushInfo( iBrushNumber, iBrushContents, NULL, 0 );
  99. if( (iPlanesNeeded == 0) || ((iContentsMask & iBrushContents) == 0) )
  100. return NULL;
  101. uint8 *pMemory;
  102. void *pDeleteMemory;
  103. float *fStackPlanes;
  104. BrushSideInfo_t *brushSides;
  105. size_t iMemoryNeeded = iPlanesNeeded * ((sizeof( float ) * 4) + sizeof( BrushSideInfo_t ));
  106. if( iMemoryNeeded < (64 * 1024) )
  107. {
  108. //use stack memory
  109. pMemory = (uint8 *)stackalloc( iMemoryNeeded );
  110. pDeleteMemory = NULL;
  111. }
  112. else
  113. {
  114. pMemory = new uint8 [iMemoryNeeded];
  115. pDeleteMemory = pMemory;
  116. }
  117. fStackPlanes = (float *)pMemory;
  118. brushSides = (BrushSideInfo_t *)(pMemory + (iPlanesNeeded * (sizeof( float ) * 4)));
  119. int iPlaneCount = enginetrace->GetBrushInfo( iBrushNumber, iBrushContents, brushSides, iPlanesNeeded );
  120. CPolyhedron *pRetVal = NULL;
  121. Assert( iPlaneCount == iPlanesNeeded );
  122. if( iPlaneCount == iPlanesNeeded )
  123. {
  124. for( int i = 0; i != iPlaneCount; ++i )
  125. {
  126. fStackPlanes[(i * 4) + 0] = brushSides[i].plane.normal.x;
  127. fStackPlanes[(i * 4) + 1] = brushSides[i].plane.normal.y;
  128. fStackPlanes[(i * 4) + 2] = brushSides[i].plane.normal.z;
  129. fStackPlanes[(i * 4) + 3] = brushSides[i].plane.dist;
  130. }
  131. pRetVal = GeneratePolyhedronFromPlanes( fStackPlanes, iPlaneCount, (1.0f/16.0f), bTempPolyhedron );
  132. }
  133. if( pDeleteMemory )
  134. {
  135. delete []pDeleteMemory;
  136. }
  137. return pRetVal;
  138. }
  139. void CStaticCollisionPolyhedronCache::Update( void )
  140. {
  141. Clear();
  142. if( gpGlobals->IsClient() && (g_pGameRules->IsMultiplayer() == false) ) //not going to need this data on the client
  143. return;
  144. if( !sv_portal_staticcollisioncache_cachebrushes.GetBool() && !sv_portal_staticcollisioncache_cachestaticprops.GetBool() )
  145. return;
  146. //There's no efficient way to know exactly how much memory we'll need to cache off all these polyhedrons.
  147. //So we're going to allocated temporary workspaces as we need them and consolidate into one allocation at the end.
  148. 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.
  149. uint8 *workSpaceAllocations[256];
  150. size_t usedSpaceInWorkspace[256];
  151. unsigned int workSpacesAllocated = 0;
  152. uint8 *pCurrentWorkSpace = new uint8 [workSpaceSize];
  153. size_t roomLeftInWorkSpace = workSpaceSize;
  154. workSpaceAllocations[workSpacesAllocated] = pCurrentWorkSpace;
  155. usedSpaceInWorkspace[workSpacesAllocated] = 0;
  156. ++workSpacesAllocated;
  157. //brushes
  158. if( sv_portal_staticcollisioncache_cachebrushes.GetBool() )
  159. {
  160. int iBrush = 0;
  161. int iBrushContents;
  162. CPolyhedron *pTempPolyhedron = ConvertBrushToPolyhedron( iBrush, MASK_SOLID | CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP, true );
  163. while( (pTempPolyhedron != NULL) || (enginetrace->GetBrushInfo( iBrush, iBrushContents, NULL, 0 ) != 0) )
  164. {
  165. if( pTempPolyhedron )
  166. {
  167. size_t memRequired = (sizeof( CPolyhedron_LumpedMemory )) +
  168. (sizeof( Vector ) * pTempPolyhedron->iVertexCount) +
  169. (sizeof( Polyhedron_IndexedLine_t ) * pTempPolyhedron->iLineCount) +
  170. (sizeof( Polyhedron_IndexedLineReference_t ) * pTempPolyhedron->iIndexCount) +
  171. (sizeof( Polyhedron_IndexedPolygon_t ) * pTempPolyhedron->iPolygonCount);
  172. Assert( memRequired < workSpaceSize );
  173. if( roomLeftInWorkSpace < memRequired )
  174. {
  175. usedSpaceInWorkspace[workSpacesAllocated - 1] = workSpaceSize - roomLeftInWorkSpace;
  176. pCurrentWorkSpace = new uint8 [workSpaceSize];
  177. roomLeftInWorkSpace = workSpaceSize;
  178. workSpaceAllocations[workSpacesAllocated] = pCurrentWorkSpace;
  179. usedSpaceInWorkspace[workSpacesAllocated] = 0;
  180. ++workSpacesAllocated;
  181. }
  182. CPolyhedron *pWorkSpacePolyhedron = CPolyhedron_LumpedMemory::AllocateAt( pCurrentWorkSpace,
  183. pTempPolyhedron->iVertexCount,
  184. pTempPolyhedron->iLineCount,
  185. pTempPolyhedron->iIndexCount,
  186. pTempPolyhedron->iPolygonCount );
  187. pCurrentWorkSpace += memRequired;
  188. roomLeftInWorkSpace -= memRequired;
  189. memcpy( pWorkSpacePolyhedron->pVertices, pTempPolyhedron->pVertices, pTempPolyhedron->iVertexCount * sizeof( Vector ) );
  190. memcpy( pWorkSpacePolyhedron->pLines, pTempPolyhedron->pLines, pTempPolyhedron->iLineCount * sizeof( Polyhedron_IndexedLine_t ) );
  191. memcpy( pWorkSpacePolyhedron->pIndices, pTempPolyhedron->pIndices, pTempPolyhedron->iIndexCount * sizeof( Polyhedron_IndexedLineReference_t ) );
  192. memcpy( pWorkSpacePolyhedron->pPolygons, pTempPolyhedron->pPolygons, pTempPolyhedron->iPolygonCount * sizeof( Polyhedron_IndexedPolygon_t ) );
  193. m_BrushPolyhedrons.AddToTail( pWorkSpacePolyhedron );
  194. pTempPolyhedron->Release();
  195. }
  196. else
  197. {
  198. m_BrushPolyhedrons.AddToTail( NULL );
  199. }
  200. ++iBrush;
  201. pTempPolyhedron = ConvertBrushToPolyhedron( iBrush, MASK_SOLID | CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP, true );
  202. }
  203. usedSpaceInWorkspace[workSpacesAllocated - 1] = workSpaceSize - roomLeftInWorkSpace;
  204. if( usedSpaceInWorkspace[0] != 0 ) //At least a little bit of memory was used.
  205. {
  206. //consolidate workspaces into a single memory chunk
  207. size_t totalMemoryNeeded = 0;
  208. for( unsigned int i = 0; i != workSpacesAllocated; ++i )
  209. {
  210. totalMemoryNeeded += usedSpaceInWorkspace[i];
  211. }
  212. uint8 *pFinalDest = new uint8 [totalMemoryNeeded];
  213. s_BrushPolyhedronMemory = pFinalDest;
  214. DevMsg( 2, "CStaticCollisionPolyhedronCache: Used %.2f KB to cache %d brush polyhedrons.\n", ((float)totalMemoryNeeded) / 1024.0f, m_BrushPolyhedrons.Count() );
  215. int iCount = m_BrushPolyhedrons.Count();
  216. for( int i = 0; i != iCount; ++i )
  217. {
  218. CPolyhedron_LumpedMemory *pSource = (CPolyhedron_LumpedMemory *)m_BrushPolyhedrons[i];
  219. if( pSource == NULL )
  220. continue;
  221. size_t memRequired = (sizeof( CPolyhedron_LumpedMemory )) +
  222. (sizeof( Vector ) * pSource->iVertexCount) +
  223. (sizeof( Polyhedron_IndexedLine_t ) * pSource->iLineCount) +
  224. (sizeof( Polyhedron_IndexedLineReference_t ) * pSource->iIndexCount) +
  225. (sizeof( Polyhedron_IndexedPolygon_t ) * pSource->iPolygonCount);
  226. CPolyhedron_LumpedMemory *pDest = (CPolyhedron_LumpedMemory *)pFinalDest;
  227. m_BrushPolyhedrons[i] = pDest;
  228. pFinalDest += memRequired;
  229. int memoryOffset = ((uint8 *)pDest) - ((uint8 *)pSource);
  230. memcpy( pDest, pSource, memRequired );
  231. //move all the pointers to their new location.
  232. pDest->pVertices = (Vector *)(((uint8 *)(pDest->pVertices)) + memoryOffset);
  233. pDest->pLines = (Polyhedron_IndexedLine_t *)(((uint8 *)(pDest->pLines)) + memoryOffset);
  234. pDest->pIndices = (Polyhedron_IndexedLineReference_t *)(((uint8 *)(pDest->pIndices)) + memoryOffset);
  235. pDest->pPolygons = (Polyhedron_IndexedPolygon_t *)(((uint8 *)(pDest->pPolygons)) + memoryOffset);
  236. }
  237. }
  238. }
  239. unsigned int iBrushWorkSpaces = workSpacesAllocated;
  240. workSpacesAllocated = 1;
  241. pCurrentWorkSpace = workSpaceAllocations[0];
  242. usedSpaceInWorkspace[0] = 0;
  243. roomLeftInWorkSpace = workSpaceSize;
  244. //static props
  245. if( sv_portal_staticcollisioncache_cachestaticprops.GetBool() )
  246. {
  247. CUtlVector<ICollideable *> StaticPropCollideables;
  248. staticpropmgr->GetAllStaticProps( &StaticPropCollideables );
  249. if( StaticPropCollideables.Count() != 0 )
  250. {
  251. ICollideable **pCollideables = StaticPropCollideables.Base();
  252. ICollideable **pStop = pCollideables + StaticPropCollideables.Count();
  253. int iStaticPropIndex = 0;
  254. do
  255. {
  256. ICollideable *pProp = *pCollideables;
  257. if( (pProp->GetCollisionModel() != NULL) && (pProp->GetSolid() != SOLID_NONE) && ((pProp->GetSolidFlags() & FSOLID_NOT_SOLID) == 0) )
  258. {
  259. vcollide_t *pCollide = modelinfo->GetVCollide( pProp->GetCollisionModel() );
  260. if( (pCollide != NULL) && (m_CollideableIndicesMap.IsValidIndex( m_CollideableIndicesMap.Find( pCollide ) ) == false) )
  261. {
  262. StaticPropPolyhedronCacheInfo_t cacheInfo;
  263. cacheInfo.iStartIndex = m_StaticPropPolyhedrons.Count();
  264. for( int i = 0; i != pCollide->solidCount; ++i )
  265. {
  266. CPhysConvex *ConvexesArray[1024];
  267. int iConvexes = physcollision->GetConvexesUsedInCollideable( pCollide->solids[i], ConvexesArray, 1024 );
  268. for( int j = 0; j != iConvexes; ++j )
  269. {
  270. CPolyhedron *pTempPolyhedron = physcollision->PolyhedronFromConvex( ConvexesArray[j], true );
  271. if( pTempPolyhedron )
  272. {
  273. size_t memRequired = (sizeof( CPolyhedron_LumpedMemory )) +
  274. (sizeof( Vector ) * pTempPolyhedron->iVertexCount) +
  275. (sizeof( Polyhedron_IndexedLine_t ) * pTempPolyhedron->iLineCount) +
  276. (sizeof( Polyhedron_IndexedLineReference_t ) * pTempPolyhedron->iIndexCount) +
  277. (sizeof( Polyhedron_IndexedPolygon_t ) * pTempPolyhedron->iPolygonCount);
  278. Assert( memRequired < workSpaceSize );
  279. if( roomLeftInWorkSpace < memRequired )
  280. {
  281. usedSpaceInWorkspace[workSpacesAllocated - 1] = workSpaceSize - roomLeftInWorkSpace;
  282. if( workSpacesAllocated < iBrushWorkSpaces )
  283. {
  284. //re-use a workspace already allocated during brush polyhedron conversion
  285. pCurrentWorkSpace = workSpaceAllocations[workSpacesAllocated];
  286. usedSpaceInWorkspace[workSpacesAllocated] = 0;
  287. }
  288. else
  289. {
  290. //allocate a new workspace
  291. pCurrentWorkSpace = new uint8 [workSpaceSize];
  292. workSpaceAllocations[workSpacesAllocated] = pCurrentWorkSpace;
  293. usedSpaceInWorkspace[workSpacesAllocated] = 0;
  294. }
  295. roomLeftInWorkSpace = workSpaceSize;
  296. ++workSpacesAllocated;
  297. }
  298. CPolyhedron *pWorkSpacePolyhedron = CPolyhedron_LumpedMemory::AllocateAt( pCurrentWorkSpace,
  299. pTempPolyhedron->iVertexCount,
  300. pTempPolyhedron->iLineCount,
  301. pTempPolyhedron->iIndexCount,
  302. pTempPolyhedron->iPolygonCount );
  303. pCurrentWorkSpace += memRequired;
  304. roomLeftInWorkSpace -= memRequired;
  305. memcpy( pWorkSpacePolyhedron->pVertices, pTempPolyhedron->pVertices, pTempPolyhedron->iVertexCount * sizeof( Vector ) );
  306. memcpy( pWorkSpacePolyhedron->pLines, pTempPolyhedron->pLines, pTempPolyhedron->iLineCount * sizeof( Polyhedron_IndexedLine_t ) );
  307. memcpy( pWorkSpacePolyhedron->pIndices, pTempPolyhedron->pIndices, pTempPolyhedron->iIndexCount * sizeof( Polyhedron_IndexedLineReference_t ) );
  308. memcpy( pWorkSpacePolyhedron->pPolygons, pTempPolyhedron->pPolygons, pTempPolyhedron->iPolygonCount * sizeof( Polyhedron_IndexedPolygon_t ) );
  309. m_StaticPropPolyhedrons.AddToTail( pWorkSpacePolyhedron );
  310. #if defined( DBGFLAG_ASSERT ) && 0
  311. CPhysConvex *pConvex = physcollision->ConvexFromConvexPolyhedron( *pTempPolyhedron );
  312. AssertMsg( pConvex != NULL, "Conversion from Convex to Polyhedron was irreversable" );
  313. if( pConvex )
  314. {
  315. physcollision->ConvexFree( pConvex );
  316. }
  317. #endif
  318. pTempPolyhedron->Release();
  319. }
  320. }
  321. }
  322. cacheInfo.iNumPolyhedrons = m_StaticPropPolyhedrons.Count() - cacheInfo.iStartIndex;
  323. Assert( m_CollideableIndicesMap.IsValidIndex( m_CollideableIndicesMap.Find( pCollide ) ) == false );
  324. m_CollideableIndicesMap.Insert( pCollide, cacheInfo );
  325. }
  326. }
  327. ++iStaticPropIndex;
  328. ++pCollideables;
  329. } while( pCollideables != pStop );
  330. usedSpaceInWorkspace[workSpacesAllocated - 1] = workSpaceSize - roomLeftInWorkSpace;
  331. if( usedSpaceInWorkspace[0] != 0 ) //At least a little bit of memory was used.
  332. {
  333. //consolidate workspaces into a single memory chunk
  334. size_t totalMemoryNeeded = 0;
  335. for( unsigned int i = 0; i != workSpacesAllocated; ++i )
  336. {
  337. totalMemoryNeeded += usedSpaceInWorkspace[i];
  338. }
  339. uint8 *pFinalDest = new uint8 [totalMemoryNeeded];
  340. s_StaticPropPolyhedronMemory = pFinalDest;
  341. DevMsg( 2, "CStaticCollisionPolyhedronCache: Used %.2f KB to cache %d static prop polyhedrons.\n", ((float)totalMemoryNeeded) / 1024.0f, m_StaticPropPolyhedrons.Count() );
  342. int iCount = m_StaticPropPolyhedrons.Count();
  343. for( int i = 0; i != iCount; ++i )
  344. {
  345. CPolyhedron_LumpedMemory *pSource = (CPolyhedron_LumpedMemory *)m_StaticPropPolyhedrons[i];
  346. size_t memRequired = (sizeof( CPolyhedron_LumpedMemory )) +
  347. (sizeof( Vector ) * pSource->iVertexCount) +
  348. (sizeof( Polyhedron_IndexedLine_t ) * pSource->iLineCount) +
  349. (sizeof( Polyhedron_IndexedLineReference_t ) * pSource->iIndexCount) +
  350. (sizeof( Polyhedron_IndexedPolygon_t ) * pSource->iPolygonCount);
  351. CPolyhedron_LumpedMemory *pDest = (CPolyhedron_LumpedMemory *)pFinalDest;
  352. m_StaticPropPolyhedrons[i] = pDest;
  353. pFinalDest += memRequired;
  354. int memoryOffset = ((uint8 *)pDest) - ((uint8 *)pSource);
  355. memcpy( pDest, pSource, memRequired );
  356. //move all the pointers to their new location.
  357. pDest->pVertices = (Vector *)(((uint8 *)(pDest->pVertices)) + memoryOffset);
  358. pDest->pLines = (Polyhedron_IndexedLine_t *)(((uint8 *)(pDest->pLines)) + memoryOffset);
  359. pDest->pIndices = (Polyhedron_IndexedLineReference_t *)(((uint8 *)(pDest->pIndices)) + memoryOffset);
  360. pDest->pPolygons = (Polyhedron_IndexedPolygon_t *)(((uint8 *)(pDest->pPolygons)) + memoryOffset);
  361. }
  362. }
  363. }
  364. }
  365. if( iBrushWorkSpaces > workSpacesAllocated )
  366. workSpacesAllocated = iBrushWorkSpaces;
  367. for( unsigned int i = 0; i != workSpacesAllocated; ++i )
  368. {
  369. delete []workSpaceAllocations[i];
  370. }
  371. }
  372. const CPolyhedron *CStaticCollisionPolyhedronCache::GetBrushPolyhedron( int iBrushNumber )
  373. {
  374. Assert( (iBrushNumber < m_BrushPolyhedrons.Count()) || ((sv_portal_staticcollisioncache_cachebrushes.GetBool() == false) && (m_CachedMap.IsEmpty() == false)) );
  375. if( iBrushNumber < 0 )
  376. return NULL;
  377. if( (iBrushNumber >= m_BrushPolyhedrons.Count()) || (m_BrushPolyhedrons[iBrushNumber] == NULL) )
  378. {
  379. return ConvertBrushToPolyhedron( iBrushNumber, MASK_ALL, false );
  380. }
  381. return m_BrushPolyhedrons[iBrushNumber];
  382. }
  383. void CStaticCollisionPolyhedronCache::ReleaseBrushPolyhedron( int iBrushNumber, const CPolyhedron *pPolyhedron )
  384. {
  385. //we only actually do any work here if there was a polyhedron and it's not in our cache.
  386. if( pPolyhedron )
  387. {
  388. Assert( iBrushNumber >= 0 );
  389. if( (iBrushNumber >= m_BrushPolyhedrons.Count()) || (pPolyhedron != m_BrushPolyhedrons[iBrushNumber]) )
  390. {
  391. //not a cached version. Must have generated it on the fly, release it
  392. ((CPolyhedron *)pPolyhedron)->Release();
  393. }
  394. }
  395. }
  396. int CStaticCollisionPolyhedronCache::GetStaticPropPolyhedrons( ICollideable *pStaticProp, const CPolyhedron **pOutputPolyhedronArray, int iOutputArraySize )
  397. {
  398. if( pStaticProp->GetCollisionModel() == NULL )
  399. return 0;
  400. vcollide_t *pCollide = modelinfo->GetVCollide( pStaticProp->GetCollisionModel() );
  401. if( pCollide == NULL )
  402. return 0;
  403. unsigned short iPropIndex = m_CollideableIndicesMap.Find( pCollide );
  404. int iWrotePolyhedrons = 0;
  405. if( m_CollideableIndicesMap.IsValidIndex( iPropIndex ) )
  406. {
  407. StaticPropPolyhedronCacheInfo_t cacheInfo = m_CollideableIndicesMap.Element( iPropIndex );
  408. if( cacheInfo.iNumPolyhedrons < iOutputArraySize )
  409. {
  410. iOutputArraySize = cacheInfo.iNumPolyhedrons;
  411. }
  412. for( int i = cacheInfo.iStartIndex; iWrotePolyhedrons != iOutputArraySize; ++i, ++iWrotePolyhedrons )
  413. {
  414. pOutputPolyhedronArray[iWrotePolyhedrons] = m_StaticPropPolyhedrons[i];
  415. }
  416. }
  417. else
  418. {
  419. if( (pStaticProp->GetSolid() == SOLID_NONE) || ((pStaticProp->GetSolidFlags() & FSOLID_NOT_SOLID) != 0) )
  420. return 0;
  421. for( int i = 0; i != pCollide->solidCount; ++i )
  422. {
  423. CPhysConvex *ConvexesArray[1024];
  424. int iConvexes = physcollision->GetConvexesUsedInCollideable( pCollide->solids[i], ConvexesArray, 1024 );
  425. if( iConvexes > iOutputArraySize )
  426. {
  427. iConvexes = iOutputArraySize;
  428. }
  429. for( int j = 0; j != iConvexes; ++j )
  430. {
  431. pOutputPolyhedronArray[iWrotePolyhedrons] = physcollision->PolyhedronFromConvex( ConvexesArray[j], false );
  432. if( pOutputPolyhedronArray[iWrotePolyhedrons] != NULL )
  433. {
  434. ++iWrotePolyhedrons;
  435. }
  436. }
  437. }
  438. }
  439. return iWrotePolyhedrons;
  440. }
  441. void CStaticCollisionPolyhedronCache::ReleaseStaticPropPolyhedrons( ICollideable *pStaticProp, const CPolyhedron **pPolyhedrons, int iPolyhedronCount )
  442. {
  443. if( pStaticProp->GetCollisionModel() != NULL )
  444. {
  445. vcollide_t *pCollide = modelinfo->GetVCollide( pStaticProp->GetCollisionModel() );
  446. if( pCollide != NULL )
  447. {
  448. if( m_CollideableIndicesMap.IsValidIndex( m_CollideableIndicesMap.Find( pCollide ) ) )
  449. {
  450. //these polyhedrons came from the cache, do nothing.
  451. #if defined( DBGFLAG_ASSERT )
  452. for( int i = 0; i < iPolyhedronCount; ++i )
  453. {
  454. Assert( m_StaticPropPolyhedrons.IsValidIndex( m_StaticPropPolyhedrons.Find((CPolyhedron *)pPolyhedrons[i]) ) );
  455. }
  456. #endif
  457. return;
  458. }
  459. }
  460. }
  461. #if defined( DBGFLAG_ASSERT )
  462. for( int i = 0; i < iPolyhedronCount; ++i )
  463. {
  464. Assert( m_StaticPropPolyhedrons.IsValidIndex( m_StaticPropPolyhedrons.Find((CPolyhedron *)pPolyhedrons[i]) ) == false );
  465. }
  466. #endif
  467. //if we're down here, the polyhedrons were not in the cache. Release them
  468. for( int i = 0; i != iPolyhedronCount; ++i )
  469. {
  470. ((CPolyhedron *)pPolyhedrons[i])->Release();
  471. }
  472. }