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.

3219 lines
106 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. // @TODO: The features and implementation of these class classes require overly
  8. // broad mutexing. Needs to be addressed. (toml 3-20-06)
  9. //
  10. //===========================================================================//
  11. #include "mathlib/vector.h"
  12. #include "utlhash.h"
  13. #include "utllinkedlist.h"
  14. #include "utllinkedlist.h"
  15. #include "ispatialpartitioninternal.h"
  16. #include "bsptreedata.h"
  17. #include "worldsize.h"
  18. #include "cmodel.h"
  19. #include "sys_dll.h"
  20. #include "collisionutils.h"
  21. #include "debugoverlay.h"
  22. #include "tier0/vprof.h"
  23. #include "tier1/utlbuffer.h"
  24. #include "filesystem_engine.h"
  25. #include "filesystem.h"
  26. #include "tier1/convar.h"
  27. #include "tier1/memstack.h"
  28. #include "enginethreads.h"
  29. #include "datacache/imdlcache.h"
  30. #include "tier2/renderutils.h"
  31. #include "bitvec.h"
  32. #include "host.h"
  33. #include "tier1/mempool.h"
  34. #ifdef _PS3
  35. #include "tls_ps3.h"
  36. #endif
  37. // memdbgon must be the last include file in a .cpp file!!!
  38. #include "tier0/memdbgon.h"
  39. class CVoxelTree;
  40. class CIntersectSweptBox;
  41. #define SPHASH_LEVEL_SKIP 2
  42. #define SPHASH_VOXEL_SIZE 256 // must power of 2
  43. #define SPHASH_VOXEL_SHIFT 8 // shift for voxel size
  44. #define SPHASH_VOXEL_LARGE 65536.0f
  45. #define SPHASH_HANDLELIST_BLOCK 256
  46. #define SPHASH_LEAFLIST_BLOCK 512
  47. #define SPHASH_ENTITYLIST_BLOCK 256
  48. #define SPHASH_BUCKET_COUNT 512
  49. #define SPHASH_EPS 0.03125f
  50. enum PartitionTrees_t
  51. {
  52. CLIENT_TREE,
  53. SERVER_TREE,
  54. NUM_TREES,
  55. };
  56. class CPartitionVisitor;
  57. #if defined( _X360 )
  58. #pragma bitfield_order( push, lsb_to_msb )
  59. #elif defined( _PS3 )
  60. #pragma ms_struct on
  61. #pragma reverse_bitfields on
  62. #endif
  63. union Voxel_t
  64. {
  65. struct
  66. {
  67. unsigned int x:11;
  68. unsigned int y:11;
  69. unsigned int z:10;
  70. } bitsVoxel;
  71. unsigned int uiVoxel;
  72. };
  73. #if defined( _X360 )
  74. #pragma bitfield_order( pop )
  75. #elif defined( _PS3 )
  76. #pragma ms_struct off
  77. #pragma reverse_bitfields off
  78. #endif
  79. enum EntityInfoFlags_t
  80. {
  81. ENTITY_HIDDEN = ( 1 << 0 ),
  82. IN_CLIENT_TREE = ( 1 << 1 ),
  83. IN_SERVER_TREE = ( 1 << 2 ),
  84. };
  85. struct EntityInfo_t
  86. {
  87. Vector m_vecMin; // Min/Max of entity
  88. Voxel_t m_voxelMin;
  89. Vector m_vecMax;
  90. Voxel_t m_voxelMax;
  91. IHandleEntity * m_pHandleEntity; // Entity handle.
  92. unsigned short m_fList; // Which lists is it in?
  93. uint8 m_flags;
  94. char m_nLevel[NUM_TREES]; // Which level voxel tree is it in?
  95. unsigned short m_nVisitBit[NUM_TREES];
  96. intp m_iLeafList[NUM_TREES]; // Index into the leaf pool - leaf list for entity (m_aLeafList).
  97. };
  98. struct LeafListData_t
  99. {
  100. UtlHashFixedHandle_t m_hVoxel; // Voxel handle the entity is in.
  101. intp m_iEntity; // Entity list index for voxel
  102. };
  103. typedef CUtlFixedLinkedList<LeafListData_t> CLeafList;
  104. typedef CVarBitVec CPartitionVisits;
  105. //-----------------------------------------------------------------------------
  106. // Used when rendering the various levels of the voxel hash
  107. //-----------------------------------------------------------------------------
  108. static Color s_pVoxelColor[9] =
  109. {
  110. Color( 255, 0, 0, 255 ),
  111. Color( 0, 255, 0, 255 ),
  112. Color( 0, 0, 255, 255 ),
  113. Color( 255, 0, 255, 255 ),
  114. Color( 255, 255, 0, 255 ),
  115. Color( 0, 255, 255, 255 ),
  116. Color( 255, 255, 255, 255 ),
  117. Color( 192, 192, 0, 255 ),
  118. Color( 128, 128, 128, 255 ),
  119. };
  120. // bounds of the spatial partition
  121. static Vector s_PartitionMin( MIN_COORD_FLOAT, MIN_COORD_FLOAT, MIN_COORD_FLOAT );
  122. static Vector s_PartitionMax( MAX_COORD_FLOAT, MAX_COORD_FLOAT, MAX_COORD_FLOAT );
  123. //-----------------------------------------------------------------------------
  124. // Divide voxel coordinates by 2
  125. //-----------------------------------------------------------------------------
  126. inline Voxel_t ConvertToNextLevel( Voxel_t v )
  127. {
  128. // Just need to divide by 2 and eliminate the low bits of y and z that shifted
  129. // into the x and y fields
  130. Voxel_t res;
  131. res.uiVoxel = ( ( v.uiVoxel >> SPHASH_LEVEL_SKIP ) & 0xFFCFF9FF );
  132. return res;
  133. }
  134. class CSpatialEntry
  135. {
  136. public:
  137. SpatialPartitionHandle_t m_handle;
  138. uint16 m_nListMask;
  139. };
  140. //-----------------------------------------------------------------------------
  141. // A single voxel hash
  142. //-----------------------------------------------------------------------------
  143. class CVoxelHash
  144. {
  145. public:
  146. // Constructor, destructor
  147. CVoxelHash();
  148. ~CVoxelHash();
  149. // Call this to clear out the spatial partition and to re-initialize it given a particular world size (ISpatialPartitionInternal)
  150. void Init( CVoxelTree *pPartition, const Vector& worldmin, const Vector& worldmax, int nLevel );
  151. void Shutdown();
  152. // Gets all entities in a particular volume...
  153. // returns false if the enumerator broke early
  154. bool EnumerateElementsInBox( SpatialPartitionListMask_t listMask, Voxel_t vmin, Voxel_t vmax, const Vector& mins, const Vector& maxs, IPartitionEnumerator* pIterator );
  155. bool EnumerateElementsAlongRay( SpatialPartitionListMask_t listMask, const Ray_t& ray, const Vector &vecInvDelta, const Vector &vecEnd, IPartitionEnumerator* pIterator );
  156. bool EnumerateElementsAtPoint( SpatialPartitionListMask_t listMask, Voxel_t v, const Vector& pt, IPartitionEnumerator* pIterator );
  157. // Inserts/Removes a handle from the tree.
  158. void InsertIntoTree( SpatialPartitionHandle_t hPartition, Voxel_t voxelMin, Voxel_t voxelMax );
  159. void RemoveFromTree( SpatialPartitionHandle_t hPartition );
  160. void UpdateListMask( SpatialPartitionHandle_t hPartition );
  161. // Debug!
  162. void RenderAllObjectsInTree( float flTime );
  163. void RenderObjectsInPlayerLeafs( const Vector &vecPlayerMin, const Vector &vecPlayerMax, float flTime );
  164. void RenderVoxel( Voxel_t voxel, float flTime );
  165. void RenderObjectInVoxel( SpatialPartitionHandle_t hPartition, CPartitionVisitor *pVisitor, float flTime );
  166. void RenderObjectsInVoxel( Voxel_t voxel, CPartitionVisitor *pVisitor, bool bRenderVoxel, float flTime );
  167. // Computes the voxel count in 1 dimension at a particular level of the tree
  168. static int ComputeVoxelCountAtLevel( int nLevel );
  169. // Gets the voxel size for this hash
  170. int VoxelSize( ) const;
  171. inline float VoxelSizeF( ) const { return m_flVoxelSize; }
  172. int EntityCount();
  173. // Rendering methods
  174. void RenderGrid();
  175. // Converts point into voxel index
  176. inline Voxel_t VoxelIndexFromPoint( const Vector &vecWorldPoint );
  177. inline void VoxelIndexFromPoint( const Vector &vecWorldPoint, int pPoint[3] );
  178. #if defined(_X360) || defined(_PS3)
  179. inline Voxel_t VoxelIndexFromPoint( const fltx4 &vecWorldPoint );
  180. inline void VoxelIndexFromPoint( const fltx4 &vecWorldPoint, int pPoint[3] );
  181. #endif
  182. // Setup ray for iteration
  183. void LeafListRaySetup( const Ray_t &ray, const Vector &vecEnd, const Vector &vecInvDelta, Voxel_t voxel, int *pStep, float *pMax, float *pDelta );
  184. void LeafListExtrudedRaySetup( const Ray_t &ray, const Vector &vecInvDelta, const Vector &vecMin, const Vector &vecMax, int iVoxelMin[3], int iVoxelMax[3], int *pStep, float *pMin, float *pMax, float *pDelta );
  185. // Main enumeration method
  186. template <class T> bool EnumerateElementsInVoxel( Voxel_t voxel, const T &intersectTest, SpatialPartitionListMask_t listMask, IPartitionEnumerator* pIterator );
  187. // Enumeration method when only 1 voxel is ever visited
  188. template <class T> bool EnumerateElementsInSingleVoxel( Voxel_t voxel, const T &intersectTest, SpatialPartitionListMask_t listMask, IPartitionEnumerator* pIterator );
  189. bool EnumerateElementsAlongRay_ExtrudedRaySlice( SpatialPartitionListMask_t listMask, IPartitionEnumerator *pIterator, const CIntersectSweptBox &intersectSweptBox, int voxelMin[3], int voxelMax[3], int iAxis, int *pStep );
  190. private:
  191. bool EnumerateElementsAlongRay_Ray( SpatialPartitionListMask_t listMask, const Ray_t &ray, const Vector &vecInvDelta, const Vector &vecEnd, IPartitionEnumerator* pIterator );
  192. bool EnumerateElementsAlongRay_ExtrudedRay( SpatialPartitionListMask_t listMask, const Ray_t &ray, const Vector &vecInvDelta, const Vector &vecEnd, IPartitionEnumerator* pIterator );
  193. inline void PackVoxel( int iX, int iY, int iZ, Voxel_t &voxel );
  194. typedef CUtlHashFixed<intp, SPHASH_BUCKET_COUNT, CUtlHashFixedGenericHash<SPHASH_BUCKET_COUNT> > CHashTable;
  195. Vector m_vecVoxelOrigin; // Voxel space (hash) origin.
  196. CHashTable m_aVoxelHash; // Voxel tree (hash) - data = entity list head handle (m_aEntityList)
  197. int m_nVoxelDelta[3]; // Voxel world - width(Dx), height(Dy), depth(Dz)
  198. CUtlFixedLinkedList<CSpatialEntry> m_aEntityList; // Pool - Linked list(multilist) of entities per leaf.
  199. CVoxelTree *m_pTree;
  200. int m_nLevel;
  201. float m_flVoxelSize;
  202. uint m_nLevelShift;
  203. };
  204. class CSpatialPartition;
  205. //-----------------------------------------------------------------------------
  206. //
  207. //-----------------------------------------------------------------------------
  208. class CVoxelTree
  209. {
  210. public:
  211. // constructor, destructor
  212. CVoxelTree();
  213. virtual ~CVoxelTree();
  214. // Inherited from ISpatialPartition
  215. virtual void Init( CSpatialPartition *pOwner, int iTree, const Vector& worldmin, const Vector& worldmax );
  216. virtual void ElementMoved( SpatialPartitionHandle_t handle, const Vector& mins, const Vector& maxs );
  217. virtual void EnumerateElementsInBox( SpatialPartitionListMask_t listMask, const Vector& mins, const Vector& maxs, bool coarseTest, IPartitionEnumerator* pIterator );
  218. virtual void EnumerateElementsInSphere( SpatialPartitionListMask_t listMask, const Vector& origin, float radius, bool coarseTest, IPartitionEnumerator* pIterator );
  219. virtual void EnumerateElementsAlongRay( SpatialPartitionListMask_t listMask, const Ray_t& ray, bool coarseTest, IPartitionEnumerator* pIterator );
  220. virtual void EnumerateElementsAtPoint( SpatialPartitionListMask_t listMask, const Vector& pt, bool coarseTest, IPartitionEnumerator* pIterator );
  221. virtual void RenderAllObjectsInTree( float flTime );
  222. virtual void RenderObjectsInPlayerLeafs( const Vector &vecPlayerMin, const Vector &vecPlayerMax, float flTime );
  223. virtual void ReportStats( const char *pFileName );
  224. virtual void DrawDebugOverlays();
  225. EntityInfo_t &EntityInfo( SpatialPartitionHandle_t hPartition );
  226. CLeafList &LeafList();
  227. int GetTreeId() const;
  228. CPartitionVisits *BeginVisit();
  229. CPartitionVisits *GetVisits();
  230. void EndVisit( CPartitionVisits * );
  231. // Shut down the allocated memory
  232. void Shutdown( void );
  233. // Insert into the appropriate tree
  234. void InsertIntoTree( SpatialPartitionHandle_t hPartition, const Vector& mins, const Vector& maxs, bool bReinsert );
  235. // Remove from appropriate tree
  236. void RemoveFromTree( SpatialPartitionHandle_t hPartition );
  237. void UpdateListMask( SpatialPartitionHandle_t hPartition );
  238. void LockForWrite() { m_lock.LockForWrite(); }
  239. void UnlockWrite() { m_lock.UnlockWrite(); }
  240. void LockForRead() { m_lock.LockForRead(); }
  241. void UnlockRead() { m_lock.UnlockRead(); }
  242. // Ray casting
  243. bool EnumerateElementsAlongRay_Ray( SpatialPartitionListMask_t listMask, const Ray_t &ray, const Vector &vecInvDelta, const Vector &vecEnd, IPartitionEnumerator *pIterator );
  244. bool EnumerateElementsAlongRay_ExtrudedRay( SpatialPartitionListMask_t listMask,
  245. const Ray_t &ray, const Vector &vecInvDelta, const Vector &vecEnd, IPartitionEnumerator *pIterator );
  246. bool EnumerateRayStartVoxels( SpatialPartitionListMask_t listMask, IPartitionEnumerator *pIterator, CIntersectSweptBox &intersectSweptBox, int voxelBounds[4][2][3] );
  247. // Purpose:
  248. void ComputeSweptRayBounds( const Ray_t &ray, const Vector &vecStartMin, const Vector &vecStartMax, Vector *pVecMin, Vector *pVecMax );
  249. private:
  250. int m_nLevelCount;
  251. CVoxelHash* m_pVoxelHash;
  252. CLeafList m_aLeafList; // Pool - Linked list(multilist) of leaves per entity.
  253. int m_TreeId;
  254. CPartitionVisits * m_pVisits[MAX_THREADS_SUPPORTED];
  255. CSpatialPartition * m_pOwner;
  256. CUtlVector<unsigned short> m_AvailableVisitBits;
  257. unsigned short m_nNextVisitBit;
  258. CTSPool<CPartitionVisits> m_FreeVisits;
  259. CThreadSpinRWLock m_lock;
  260. };
  261. //-----------------------------------------------------------------------------
  262. // The spatial partition
  263. //-----------------------------------------------------------------------------
  264. class CSpatialPartition : public ISpatialPartitionInternal
  265. {
  266. public:
  267. CSpatialPartition();
  268. ~CSpatialPartition();
  269. enum
  270. {
  271. MAX_QUERY_CALLBACK = 3
  272. };
  273. // Inherited from ISpatialPartition
  274. virtual void Init( const Vector& worldmin, const Vector& worldmax );
  275. void Shutdown( void );
  276. virtual SpatialPartitionHandle_t CreateHandle( IHandleEntity *pHandleEntity );
  277. virtual SpatialPartitionHandle_t CreateHandle( IHandleEntity *pHandleEntity, SpatialPartitionListMask_t listMask, const Vector& mins, const Vector& maxs );
  278. virtual void DestroyHandle( SpatialPartitionHandle_t handle );
  279. virtual void Insert( SpatialPartitionListMask_t listMask, SpatialPartitionHandle_t handle );
  280. virtual void Remove( SpatialPartitionListMask_t listMask, SpatialPartitionHandle_t handle );
  281. virtual void RemoveAndInsert( SpatialPartitionListMask_t removeMask, SpatialPartitionListMask_t insertMask, SpatialPartitionHandle_t handle );
  282. virtual void Remove( SpatialPartitionHandle_t handle );
  283. virtual SpatialTempHandle_t HideElement( SpatialPartitionHandle_t handle );
  284. virtual void UnhideElement( SpatialPartitionHandle_t handle, SpatialTempHandle_t tempHandle );
  285. virtual void InstallQueryCallback( IPartitionQueryCallback *pCallback );
  286. virtual void RemoveQueryCallback( IPartitionQueryCallback *pCallback );
  287. virtual void SuppressLists( SpatialPartitionListMask_t nListMask, bool bSuppress );
  288. virtual SpatialPartitionListMask_t GetSuppressedLists( void );
  289. virtual void RenderLeafsForRayTraceStart( float flTime ) { }
  290. virtual void RenderLeafsForRayTraceEnd( void ) { }
  291. virtual void RenderLeafsForHullTraceStart( float flTime ) { }
  292. virtual void RenderLeafsForHullTraceEnd( void ) { }
  293. virtual void RenderLeafsForBoxStart( float flTime ) { }
  294. virtual void RenderLeafsForBoxEnd( void ) { }
  295. virtual void RenderLeafsForSphereStart( float flTime ) { }
  296. virtual void RenderLeafsForSphereEnd( void ) { }
  297. virtual void RenderObjectsInBox( const Vector &vecMin, const Vector &vecMax, float flTime );
  298. virtual void RenderObjectsInSphere( const Vector &vecCenter, float flRadius, float flTime );
  299. virtual void RenderObjectsAlongRay( const Ray_t& ray, float flTime );
  300. virtual void ElementMoved( SpatialPartitionHandle_t handle, const Vector& mins, const Vector& maxs );
  301. virtual void EnumerateElementsInBox( SpatialPartitionListMask_t listMask, const Vector& mins, const Vector& maxs, bool coarseTest, IPartitionEnumerator* pIterator );
  302. virtual void EnumerateElementsInSphere( SpatialPartitionListMask_t listMask, const Vector& origin, float radius, bool coarseTest, IPartitionEnumerator* pIterator );
  303. virtual void EnumerateElementsAlongRay( SpatialPartitionListMask_t listMask, const Ray_t& ray, bool coarseTest, IPartitionEnumerator* pIterator );
  304. virtual void EnumerateElementsAtPoint( SpatialPartitionListMask_t listMask, const Vector& pt, bool coarseTest, IPartitionEnumerator* pIterator );
  305. virtual void RenderAllObjectsInTree( float flTime );
  306. virtual void RenderObjectsInPlayerLeafs( const Vector &vecPlayerMin, const Vector &vecPlayerMax, float flTime );
  307. virtual void ReportStats( const char *pFileName );
  308. virtual void DrawDebugOverlays();
  309. // Gets entity info (for enumerations).
  310. EntityInfo_t &EntityInfo( SpatialPartitionHandle_t hPartition );
  311. virtual void InsertIntoTree( SpatialPartitionHandle_t hPartition, const Vector& mins, const Vector& maxs );
  312. virtual void RemoveFromTree( SpatialPartitionHandle_t hPartition );
  313. CVoxelTree * VoxelTree( SpatialPartitionListMask_t listMask );
  314. CVoxelTree * VoxelTreeForHandle( SpatialPartitionHandle_t handle );
  315. protected:
  316. void UpdateListMask( SpatialPartitionHandle_t hPartition, uint16 nListMask );
  317. // Invokes the pre-query callbacks.
  318. void InvokeQueryCallbacks( SpatialPartitionListMask_t listMask, bool = false );
  319. typedef CUtlLinkedList<EntityInfo_t, SpatialPartitionHandle_t, false, SpatialPartitionHandle_t, CUtlMemoryStack<UtlLinkedListElem_t< EntityInfo_t, SpatialPartitionHandle_t >, SpatialPartitionHandle_t, 0xffff, 1024> > CHandleList;
  320. private:
  321. CHandleList m_aHandles; // Stores all unique elements (1 per entity in tree).
  322. CThreadFastMutex m_HandlesMutex;
  323. CVoxelTree m_VoxelTrees[NUM_TREES];
  324. IPartitionQueryCallback *m_pQueryCallback[MAX_QUERY_CALLBACK]; // Query callbacks.
  325. int m_nQueryCallbackCount; // Number of query callbacks.
  326. // Debug!
  327. SpatialPartitionListMask_t m_nSuppressedListMask;
  328. };
  329. //-----------------------------------------------------------------------------
  330. // Spatial partition inline methods
  331. //-----------------------------------------------------------------------------
  332. // Gets entity info (for enumerations).
  333. inline EntityInfo_t &CSpatialPartition::EntityInfo( SpatialPartitionHandle_t hPartition )
  334. {
  335. return m_aHandles[hPartition];
  336. }
  337. inline EntityInfo_t &CVoxelTree::EntityInfo( SpatialPartitionHandle_t hPartition )
  338. {
  339. return m_pOwner->EntityInfo( hPartition );
  340. }
  341. inline CLeafList &CVoxelTree::LeafList()
  342. {
  343. return m_aLeafList;
  344. }
  345. inline int CVoxelTree::GetTreeId() const
  346. {
  347. return m_TreeId;
  348. }
  349. inline CPartitionVisits *CVoxelTree::GetVisits()
  350. {
  351. int nThread = g_nThreadID;
  352. return m_pVisits[nThread];
  353. }
  354. inline CPartitionVisits *CVoxelTree::BeginVisit()
  355. {
  356. int nThread = g_nThreadID;
  357. CPartitionVisits *pPrev = m_pVisits[nThread];
  358. CPartitionVisits *pVisits = m_FreeVisits.GetObject();
  359. if ( pVisits->GetNumBits() < m_nNextVisitBit )
  360. {
  361. pVisits->Resize( m_nNextVisitBit, true );
  362. }
  363. else
  364. {
  365. pVisits->ClearAll();
  366. }
  367. m_pVisits[g_nThreadID] = pVisits;
  368. return pPrev;
  369. }
  370. inline void CVoxelTree::EndVisit( CPartitionVisits *pPrev )
  371. {
  372. int nThread = g_nThreadID;
  373. m_FreeVisits.PutObject( m_pVisits[nThread] );
  374. m_pVisits[nThread] = pPrev;
  375. }
  376. inline CVoxelTree *CSpatialPartition::VoxelTree( SpatialPartitionListMask_t listMask )
  377. {
  378. int iTree = ( ( listMask & PARTITION_ALL_CLIENT_EDICTS ) == 0 ) ? SERVER_TREE : CLIENT_TREE;
  379. return &m_VoxelTrees[iTree];
  380. }
  381. inline CVoxelTree *CSpatialPartition::VoxelTreeForHandle( SpatialPartitionHandle_t handle )
  382. {
  383. return VoxelTree( m_aHandles[handle].m_fList );
  384. }
  385. //-----------------------------------------------------------------------------
  386. // Constructor, destructor
  387. //-----------------------------------------------------------------------------
  388. CVoxelHash::CVoxelHash( )
  389. {
  390. }
  391. CVoxelHash::~CVoxelHash()
  392. {
  393. Shutdown();
  394. }
  395. //-----------------------------------------------------------------------------
  396. // Purpose: Create a voxel index from a world point - is the hash key.
  397. // Input: vecWorldPoint - world point to get voxel index for
  398. // Output: voxel index
  399. //-----------------------------------------------------------------------------
  400. inline void CVoxelHash::PackVoxel( int iX, int iY, int iZ, Voxel_t &voxel )
  401. {
  402. Assert( ( iX >= -( 1 << 10 ) ) && ( iX <= ( 1 << 10 ) ) );
  403. Assert( ( iY >= -( 1 << 10 ) ) && ( iY <= ( 1 << 10 ) ) );
  404. Assert( ( iZ >= -( 1 << 9 ) ) && ( iZ <= ( 1 << 9 ) ) );
  405. voxel.bitsVoxel.x = iX;
  406. voxel.bitsVoxel.y = iY;
  407. voxel.bitsVoxel.z = iZ;
  408. }
  409. #if defined(_X360) || defined(_PS3)
  410. // NOTE: This isn't supportable on SSE but it isn't necessary either
  411. inline double FloatConvertToIntegerFormat( double flVal )
  412. {
  413. #if defined( _PS3 )
  414. return __builtin_fctiwz( flVal );
  415. #else
  416. return __fctiwz( flVal );
  417. #endif
  418. }
  419. inline fltx4 ConvertToSignedIntegerSIMD( fltx4 fl4Data )
  420. {
  421. #if defined(_X360)
  422. return __vctsxs( fl4Data, 0 ); // NOTE: 0 is power of 2 to scale by
  423. #else
  424. return (fltx4)vec_cts( fl4Data, 0 );
  425. #endif
  426. }
  427. inline fltx4 ShiftRightSIMD( const fltx4 &fl4Data, const fltx4 &fl4Shift )
  428. {
  429. #if defined(_X360)
  430. return __vsrw( fl4Data, fl4Shift );
  431. #else
  432. return (fltx4)vec_sr( (u32x4)fl4Data, (u32x4)fl4Shift );
  433. #endif
  434. }
  435. union doublecnv_t
  436. {
  437. double m_flConverted;
  438. int32 m_nConverted[2];
  439. };
  440. // SIMD Versions - need more code changes to fully support this but there are enough benefits to use it on some of the code
  441. inline void CVoxelHash::VoxelIndexFromPoint( const fltx4 &fl4WorldPoint, int pPoint[3] )
  442. {
  443. fltx4 fl4Shift = (fltx4)ReplicateIX4( m_nLevelShift );
  444. fltx4 fl4VoxelOrigin = LoadUnaligned3SIMD( m_vecVoxelOrigin.Base() );
  445. fltx4 fl4LocalOrigin = SubSIMD( fl4WorldPoint, fl4VoxelOrigin );
  446. fltx4 fl4OriginInt = ConvertToSignedIntegerSIMD( fl4LocalOrigin );
  447. fl4OriginInt = ShiftRightSIMD( fl4OriginInt, fl4Shift );
  448. StoreUnaligned3SIMD( (float *)pPoint, fl4OriginInt );
  449. }
  450. inline void CVoxelHash::VoxelIndexFromPoint( const Vector &vecWorldPoint, int pPoint[3] )
  451. {
  452. return VoxelIndexFromPoint( LoadUnaligned3SIMD( vecWorldPoint.Base() ), pPoint );
  453. }
  454. inline Voxel_t CVoxelHash::VoxelIndexFromPoint( const Vector &vecWorldPoint )
  455. {
  456. Voxel_t voxel;
  457. // This code manually schedules the float->int conversion to avoid LHS on PPC
  458. // First we convert the float to int format within a float register
  459. // then we write it back to memory
  460. volatile union doublecnv_t cnvX, cnvY, cnvZ;
  461. cnvX.m_flConverted = FloatConvertToIntegerFormat( vecWorldPoint.x - m_vecVoxelOrigin.x );
  462. cnvY.m_flConverted = FloatConvertToIntegerFormat( vecWorldPoint.y - m_vecVoxelOrigin.y );
  463. cnvZ.m_flConverted = FloatConvertToIntegerFormat( vecWorldPoint.z - m_vecVoxelOrigin.z );
  464. // now we load that value back into an integer register. This will LHS if there aren't enough
  465. // cycles between the stores and the loads but this will allow the compiler to reorder the operations
  466. // and when the conversions are implicit they don't get reordered (load instruction immediately follows the store)
  467. int nX = cnvX.m_nConverted[1];
  468. int nY = cnvY.m_nConverted[1];
  469. int nZ = cnvZ.m_nConverted[1];
  470. voxel.bitsVoxel.x = nX >> m_nLevelShift;
  471. voxel.bitsVoxel.y = nY >> m_nLevelShift;
  472. voxel.bitsVoxel.z = nZ >> m_nLevelShift;
  473. return voxel;
  474. }
  475. inline Voxel_t CVoxelHash::VoxelIndexFromPoint( const fltx4 &fl4WorldPoint )
  476. {
  477. Voxel_t voxel;
  478. fltx4 fl4Shift = (fltx4)ReplicateIX4( m_nLevelShift );
  479. fltx4 fl4VoxelOrigin = LoadUnaligned3SIMD( m_vecVoxelOrigin.Base() );
  480. fltx4 fl4LocalOrigin = SubSIMD( fl4WorldPoint, fl4VoxelOrigin );
  481. fltx4 fl4OriginInt = ConvertToSignedIntegerSIMD( fl4LocalOrigin );
  482. fl4OriginInt = ShiftRightSIMD( fl4OriginInt, fl4Shift );
  483. // UNDONE: Can probably pack these with shift, permute, or
  484. int32 ALIGN16 tmp[4];
  485. StoreAlignedIntSIMD( tmp, fl4OriginInt );
  486. voxel.bitsVoxel.x = tmp[0];
  487. voxel.bitsVoxel.y = tmp[1];
  488. voxel.bitsVoxel.z = tmp[2];
  489. return voxel;
  490. }
  491. #else
  492. inline void CVoxelHash::VoxelIndexFromPoint( const Vector &vecWorldPoint, int pPoint[3] )
  493. {
  494. pPoint[0] = static_cast<int>( vecWorldPoint.x - m_vecVoxelOrigin.x ) >> m_nLevelShift;
  495. pPoint[1] = static_cast<int>( vecWorldPoint.y - m_vecVoxelOrigin.y ) >> m_nLevelShift;
  496. pPoint[2] = static_cast<int>( vecWorldPoint.z - m_vecVoxelOrigin.z ) >> m_nLevelShift;
  497. }
  498. inline Voxel_t CVoxelHash::VoxelIndexFromPoint( const Vector &vecWorldPoint )
  499. {
  500. Voxel_t voxel;
  501. voxel.bitsVoxel.x = static_cast<int>( vecWorldPoint.x - m_vecVoxelOrigin.x ) >> m_nLevelShift;
  502. voxel.bitsVoxel.y = static_cast<int>( vecWorldPoint.y - m_vecVoxelOrigin.y ) >> m_nLevelShift;
  503. voxel.bitsVoxel.z = static_cast<int>( vecWorldPoint.z - m_vecVoxelOrigin.z ) >> m_nLevelShift;
  504. return voxel;
  505. }
  506. #endif
  507. //-----------------------------------------------------------------------------
  508. // Purpose: Computes the voxel count at a particular level of the tree
  509. //-----------------------------------------------------------------------------
  510. int CVoxelHash::ComputeVoxelCountAtLevel( int nLevel )
  511. {
  512. int nVoxelCount = COORD_EXTENT >> SPHASH_VOXEL_SHIFT;
  513. nVoxelCount >>= ( SPHASH_LEVEL_SKIP * nLevel );
  514. return ( nVoxelCount > 0 ) ? nVoxelCount : 1;
  515. }
  516. //-----------------------------------------------------------------------------
  517. // Gets the voxel size for this hash
  518. //-----------------------------------------------------------------------------
  519. inline int CVoxelHash::VoxelSize( ) const
  520. {
  521. return SPHASH_VOXEL_SIZE << ( SPHASH_LEVEL_SKIP * m_nLevel );
  522. }
  523. //-----------------------------------------------------------------------------
  524. // Purpose:
  525. // Input: worldmin -
  526. // worldmax -
  527. //-----------------------------------------------------------------------------
  528. void CVoxelHash::Init( CVoxelTree *pPartition, const Vector &worldmin, const Vector &worldmax, int nLevel )
  529. {
  530. m_pTree = pPartition;
  531. m_nLevel = nLevel;
  532. m_flVoxelSize = VoxelSize();
  533. m_nLevelShift = ( SPHASH_VOXEL_SHIFT + SPHASH_LEVEL_SKIP * nLevel );
  534. // Setup the hash.
  535. MEM_ALLOC_CREDIT();
  536. int nVoxelCount = ComputeVoxelCountAtLevel( nLevel );
  537. m_vecVoxelOrigin.Init( MIN_COORD_FLOAT, MIN_COORD_FLOAT, MIN_COORD_FLOAT );
  538. int nHashBucketCount = SPHASH_BUCKET_COUNT >> nLevel;
  539. if ( nHashBucketCount < 16 )
  540. {
  541. nHashBucketCount = 16;
  542. }
  543. m_nVoxelDelta[0] = nVoxelCount;
  544. m_nVoxelDelta[1] = nVoxelCount;
  545. m_nVoxelDelta[2] = nVoxelCount;
  546. Assert( ( m_nVoxelDelta[0] >= 0 ) && ( m_nVoxelDelta[0] <= ( 1 << 10 ) ) );
  547. Assert( ( m_nVoxelDelta[1] >= 0 ) && ( m_nVoxelDelta[1] <= ( 1 << 10 ) ) );
  548. Assert( ( m_nVoxelDelta[2] >= 0 ) && ( m_nVoxelDelta[2] <= ( 1 << 9 ) ) );
  549. m_aVoxelHash.RemoveAll();
  550. // Setup the entity list pool.
  551. int nGrowSize = SPHASH_ENTITYLIST_BLOCK >> nLevel;
  552. if ( nGrowSize < 16 )
  553. {
  554. nGrowSize = 16;
  555. }
  556. m_aEntityList.Purge();
  557. m_aEntityList.SetGrowSize( nGrowSize );
  558. }
  559. //-----------------------------------------------------------------------------
  560. // Shutdown
  561. //-----------------------------------------------------------------------------
  562. void CVoxelHash::Shutdown( void )
  563. {
  564. m_aEntityList.Purge();
  565. m_aVoxelHash.Purge();
  566. }
  567. //-----------------------------------------------------------------------------
  568. // Purpose: Insert the object into the voxel hash.
  569. //-----------------------------------------------------------------------------
  570. void CVoxelHash::InsertIntoTree( SpatialPartitionHandle_t hPartition, Voxel_t voxelMin, Voxel_t voxelMax )
  571. {
  572. EntityInfo_t &info = m_pTree->EntityInfo( hPartition );
  573. CLeafList &leafList = m_pTree->LeafList();
  574. int treeId = m_pTree->GetTreeId();
  575. uint16 nListMask = m_pTree->EntityInfo( hPartition ).m_fList;
  576. // Set the voxel level
  577. info.m_nLevel[m_pTree->GetTreeId()] = m_nLevel;
  578. Assert( (m_nLevel == 4) ||
  579. (voxelMax.bitsVoxel.x - voxelMin.bitsVoxel.x <= 1) &&
  580. (voxelMax.bitsVoxel.y - voxelMin.bitsVoxel.y <= 1) &&
  581. (voxelMax.bitsVoxel.z - voxelMin.bitsVoxel.z <= 1) );
  582. // Add the object to all the voxels it intersects.
  583. Voxel_t voxel;
  584. unsigned int iX, iY, iZ;
  585. for ( iX = voxelMin.bitsVoxel.x; iX <= voxelMax.bitsVoxel.x; ++iX )
  586. {
  587. voxel.bitsVoxel.x = iX;
  588. for ( iY = voxelMin.bitsVoxel.y; iY <= voxelMax.bitsVoxel.y; ++iY )
  589. {
  590. voxel.bitsVoxel.y = iY;
  591. for ( iZ = voxelMin.bitsVoxel.z; iZ <= voxelMax.bitsVoxel.z; ++iZ )
  592. {
  593. voxel.bitsVoxel.z = iZ;
  594. #if 0
  595. // Debug!
  596. RenderVoxel( voxel );
  597. #endif
  598. // Entity list.
  599. intp iEntity = m_aEntityList.Alloc( true );
  600. m_aEntityList[iEntity].m_handle = hPartition;
  601. m_aEntityList[iEntity].m_nListMask = nListMask;
  602. UtlHashFixedHandle_t hHash = m_aVoxelHash.Find( voxel.uiVoxel );
  603. if ( hHash == m_aVoxelHash.InvalidHandle() )
  604. {
  605. // Add voxel(leaf) to hash.
  606. hHash = m_aVoxelHash.FastInsert( voxel.uiVoxel, iEntity );
  607. }
  608. else
  609. {
  610. intp iHead = m_aVoxelHash.Element( hHash );
  611. m_aEntityList.LinkBefore( iHead, iEntity );
  612. m_aVoxelHash[hHash] = iEntity;
  613. }
  614. // Leaf list.
  615. intp iLeafList = leafList.Alloc( true );
  616. leafList[iLeafList].m_hVoxel = hHash;
  617. leafList[iLeafList].m_iEntity = iEntity;
  618. if ( info.m_iLeafList[treeId] == leafList.InvalidIndex() )
  619. {
  620. info.m_iLeafList[treeId] = iLeafList;
  621. }
  622. else
  623. {
  624. intp iHead = info.m_iLeafList[treeId];
  625. leafList.LinkBefore( iHead, iLeafList );
  626. info.m_iLeafList[treeId] = iLeafList;
  627. }
  628. }
  629. }
  630. }
  631. }
  632. //-----------------------------------------------------------------------------
  633. // Purpose: Removes the object into the voxel hash.
  634. //-----------------------------------------------------------------------------
  635. void CVoxelHash::RemoveFromTree( SpatialPartitionHandle_t hPartition )
  636. {
  637. EntityInfo_t &data = m_pTree->EntityInfo( hPartition );
  638. CLeafList &leafList = m_pTree->LeafList();
  639. int treeId = m_pTree->GetTreeId();
  640. intp iLeaf = data.m_iLeafList[treeId];
  641. intp iNext;
  642. while ( iLeaf != leafList.InvalidIndex() )
  643. {
  644. // Get the next voxel - if any.
  645. iNext = leafList.Next( iLeaf );
  646. UtlHashFixedHandle_t hHash = leafList[iLeaf].m_hVoxel;
  647. if ( hHash == m_aVoxelHash.InvalidHandle() )
  648. {
  649. iLeaf = iNext;
  650. continue;
  651. }
  652. // Get the head of the entity list for the voxel.
  653. intp iEntity = leafList[iLeaf].m_iEntity;
  654. intp iEntityHead = m_aVoxelHash[hHash];
  655. if ( iEntityHead == iEntity )
  656. {
  657. intp iEntityNext = m_aEntityList.Next( iEntityHead );
  658. if ( iEntityNext == m_aEntityList.InvalidIndex() )
  659. {
  660. m_aVoxelHash.Remove( hHash );
  661. }
  662. else
  663. {
  664. m_aVoxelHash[hHash] = iEntityNext;
  665. }
  666. }
  667. // Remove the entity from the entity list for the voxel.
  668. m_aEntityList.Remove( iEntity );
  669. // Remove from the leaf list.
  670. leafList.Remove( iLeaf );
  671. iLeaf = iNext;
  672. }
  673. data.m_iLeafList[treeId] = leafList.InvalidIndex();
  674. }
  675. void CVoxelHash::UpdateListMask( SpatialPartitionHandle_t hPartition )
  676. {
  677. EntityInfo_t &data = m_pTree->EntityInfo( hPartition );
  678. uint16 nListMask = data.m_fList;
  679. Voxel_t vmin = data.m_voxelMin;
  680. Voxel_t vmax = data.m_voxelMax;
  681. // single voxel
  682. if ( vmin.uiVoxel == vmax.uiVoxel )
  683. {
  684. UtlHashFixedHandle_t hHash = m_aVoxelHash.Find( vmin.uiVoxel );
  685. if ( hHash != m_aVoxelHash.InvalidHandle() )
  686. {
  687. for ( intp i = m_aVoxelHash.Element( hHash ); i != m_aEntityList.InvalidIndex(); i = m_aEntityList.Next(i) )
  688. {
  689. SpatialPartitionHandle_t handle = m_aEntityList[i].m_handle;
  690. if ( handle != hPartition )
  691. continue;
  692. m_aEntityList[i].m_nListMask = nListMask;
  693. break;
  694. }
  695. }
  696. }
  697. // spans voxels
  698. Voxel_t vdelta;
  699. vdelta.uiVoxel = vmax.uiVoxel - vmin.uiVoxel;
  700. int cx = vdelta.bitsVoxel.x;
  701. int cy = vdelta.bitsVoxel.y;
  702. int cz = vdelta.bitsVoxel.z;
  703. Voxel_t voxel;
  704. voxel.bitsVoxel.x = vmin.bitsVoxel.x;
  705. for ( int iX = 0; iX <= cx; ++iX, ++voxel.bitsVoxel.x )
  706. {
  707. voxel.bitsVoxel.y = vmin.bitsVoxel.y;
  708. for ( int iY = 0; iY <= cy; ++iY, ++voxel.bitsVoxel.y )
  709. {
  710. voxel.bitsVoxel.z = vmin.bitsVoxel.z;
  711. for ( int iZ = 0; iZ <= cz; ++iZ, ++voxel.bitsVoxel.z )
  712. {
  713. UtlHashFixedHandle_t hHash = m_aVoxelHash.Find( voxel.uiVoxel );
  714. if ( hHash != m_aVoxelHash.InvalidHandle() )
  715. {
  716. for ( intp i = m_aVoxelHash.Element( hHash ); i != m_aEntityList.InvalidIndex(); i = m_aEntityList.Next(i) )
  717. {
  718. if ( m_aEntityList[i].m_handle != hPartition )
  719. continue;
  720. m_aEntityList[i].m_nListMask = nListMask;
  721. break;
  722. }
  723. }
  724. }
  725. }
  726. }
  727. }
  728. //-----------------------------------------------------------------------------
  729. // Purpose:
  730. //-----------------------------------------------------------------------------
  731. inline void ClampStartPoint( Ray_t &ray, const Vector &vecEnd )
  732. {
  733. float flDistStart, flT;
  734. for ( int iAxis = 0; iAxis < 3; ++iAxis )
  735. {
  736. if ( fabs(ray.m_Delta[iAxis]) < 1e-10 )
  737. continue;
  738. if ( ray.m_Delta[iAxis] > 0.0f )
  739. {
  740. if ( ray.m_Start[iAxis] < MIN_COORD_FLOAT )
  741. {
  742. // Add some bloat inward.
  743. flDistStart = ( MIN_COORD_FLOAT + 5.0f ) - ray.m_Start[iAxis];
  744. flT = flDistStart / ray.m_Delta[iAxis];
  745. VectorMA( ray.m_Start, flT, ray.m_Delta, ray.m_Start );
  746. }
  747. }
  748. else
  749. {
  750. if ( ray.m_Start[iAxis] > MAX_COORD_FLOAT )
  751. {
  752. // Add some bloat inward.
  753. flDistStart = ray.m_Start[iAxis] - ( MAX_COORD_FLOAT - 5.0f );
  754. flT = flDistStart / -ray.m_Delta[iAxis];
  755. VectorMA( ray.m_Start, flT, ray.m_Delta, ray.m_Start );
  756. }
  757. }
  758. }
  759. VectorSubtract( vecEnd, ray.m_Start, ray.m_Delta );
  760. }
  761. //-----------------------------------------------------------------------------
  762. // Purpose:
  763. //-----------------------------------------------------------------------------
  764. inline void ClampEndPoint( Ray_t &ray, Vector &vecEnd )
  765. {
  766. float flDistStart, flT;
  767. for ( int iAxis = 0; iAxis < 3; ++iAxis )
  768. {
  769. if ( fabs(ray.m_Delta[iAxis]) < 1e-10 )
  770. continue;
  771. if ( ray.m_Delta[iAxis] < 0.0f )
  772. {
  773. if ( vecEnd[iAxis] < MIN_COORD_FLOAT )
  774. {
  775. // Add some bloat inward.
  776. flDistStart = ray.m_Start[iAxis] - ( MIN_COORD_FLOAT + 5.0f );
  777. flT = flDistStart / -ray.m_Delta[iAxis];
  778. VectorMA( ray.m_Start, flT, ray.m_Delta, vecEnd );
  779. }
  780. }
  781. else
  782. {
  783. if ( vecEnd[iAxis] > MAX_COORD_FLOAT )
  784. {
  785. // Add some bloat inward.
  786. flDistStart = ray.m_Start[iAxis] - ( -MAX_COORD_FLOAT + 5.0f );
  787. flT = flDistStart / ray.m_Delta[iAxis];
  788. VectorMA( ray.m_Start, flT, ray.m_Delta, vecEnd );
  789. }
  790. }
  791. }
  792. VectorSubtract( vecEnd, ray.m_Start, ray.m_Delta );
  793. }
  794. //-----------------------------------------------------------------------------
  795. // Intersection classes
  796. //-----------------------------------------------------------------------------
  797. class CPartitionVisitor
  798. {
  799. public:
  800. CPartitionVisitor( CVoxelTree *pPartition )
  801. {
  802. m_pVisits = pPartition->GetVisits();
  803. m_iTree = pPartition->GetTreeId();
  804. }
  805. ~CPartitionVisitor()
  806. {
  807. }
  808. bool Visit( SpatialPartitionHandle_t hPartition, EntityInfo_t &hInfo ) const
  809. {
  810. int nVisitBit = hInfo.m_nVisitBit[m_iTree];
  811. if ( m_pVisits->IsBitSet( nVisitBit ) )
  812. {
  813. return false;
  814. }
  815. m_pVisits->Set( nVisitBit );
  816. return true;
  817. }
  818. private:
  819. CPartitionVisits *m_pVisits;
  820. int m_iTree;
  821. };
  822. class CIntersectPoint : public CPartitionVisitor
  823. {
  824. public:
  825. CIntersectPoint( CVoxelTree *pPartition, const Vector &pt ) : CPartitionVisitor( pPartition )
  826. {
  827. m_f4Point = LoadUnaligned3SIMD( pt.Base() );
  828. }
  829. bool Intersects( const float *pMins, const float *pMaxs ) const
  830. {
  831. // Ray intersection test
  832. Assert( pMins[0] <= pMaxs[0] );
  833. Assert( pMins[1] <= pMaxs[1] );
  834. Assert( pMins[2] <= pMaxs[2] );
  835. return IsPointInBox( m_f4Point, LoadUnaligned3SIMD( pMins ), LoadUnaligned3SIMD(pMaxs) );
  836. }
  837. private:
  838. fltx4 m_f4Point;
  839. };
  840. class CIntersectBox : public CPartitionVisitor
  841. {
  842. public:
  843. CIntersectBox( CVoxelTree *pPartition, const Vector &vecMins, const Vector &vecMaxs ) : CPartitionVisitor( pPartition ), m_vecMins( vecMins ), m_vecMaxs( vecMaxs )
  844. {
  845. }
  846. bool Intersects( const float *pMins, const float *pMaxs ) const
  847. {
  848. // Box intersection test
  849. Assert( pMins[0] <= pMaxs[0] );
  850. Assert( pMins[1] <= pMaxs[1] );
  851. Assert( pMins[2] <= pMaxs[2] );
  852. return ( pMins[0] <= m_vecMaxs.x ) && ( pMaxs[0] >= m_vecMins.x ) &&
  853. ( pMins[1] <= m_vecMaxs.y ) && ( pMaxs[1] >= m_vecMins.y ) &&
  854. ( pMins[2] <= m_vecMaxs.z ) && ( pMaxs[2] >= m_vecMins.z );
  855. }
  856. private:
  857. const Vector &m_vecMins;
  858. const Vector &m_vecMaxs;
  859. };
  860. class CIntersectRay : public CPartitionVisitor
  861. {
  862. public:
  863. CIntersectRay( CVoxelTree *pPartition, const Ray_t &ray, const Vector &vecInvDelta ) : CPartitionVisitor( pPartition )
  864. {
  865. m_f4Start = LoadUnaligned3SIMD( ray.m_Start.Base() );
  866. m_f4Delta = LoadUnaligned3SIMD( ray.m_Delta.Base() );
  867. m_f4InvDelta = LoadUnaligned3SIMD( vecInvDelta.Base() );
  868. }
  869. bool Intersects( const float *pMins, const float *pMaxs ) const
  870. {
  871. // Ray intersection test
  872. Assert( pMins[0] <= pMaxs[0] );
  873. Assert( pMins[1] <= pMaxs[1] );
  874. Assert( pMins[2] <= pMaxs[2] );
  875. fltx4 f4Mins = LoadUnaligned3SIMD( pMins );
  876. fltx4 f4Maxs = LoadUnaligned3SIMD( pMaxs );
  877. return IsBoxIntersectingRay( f4Mins, f4Maxs, m_f4Start, m_f4Delta, m_f4InvDelta );
  878. }
  879. private:
  880. fltx4 m_f4Start;
  881. fltx4 m_f4Delta;
  882. fltx4 m_f4InvDelta;
  883. };
  884. class CIntersectSweptBox : public CPartitionVisitor
  885. {
  886. public:
  887. CIntersectSweptBox( CVoxelTree *pPartition, const Ray_t &ray, const Vector &vecInvDelta ) : CPartitionVisitor( pPartition )
  888. {
  889. m_f4Start = LoadUnaligned3SIMD( ray.m_Start.Base() );
  890. m_f4Delta = LoadUnaligned3SIMD( ray.m_Delta.Base() );
  891. m_f4InvDelta = LoadUnaligned3SIMD( vecInvDelta.Base() );
  892. m_f4Extents = LoadUnaligned3SIMD( ray.m_Extents.Base() );
  893. }
  894. bool Intersects( const float *pMins, const float *pMaxs ) const
  895. {
  896. // Swept box intersection test
  897. Assert( pMins[0] <= pMaxs[0] );
  898. Assert( pMins[1] <= pMaxs[1] );
  899. Assert( pMins[2] <= pMaxs[2] );
  900. fltx4 f4Mins = LoadUnaligned3SIMD( pMins );
  901. fltx4 f4Maxs = LoadUnaligned3SIMD( pMaxs );
  902. // Does the ray intersect the box?
  903. return IsBoxIntersectingRay( SubSIMD(f4Mins, m_f4Extents), AddSIMD(f4Maxs, m_f4Extents), m_f4Start, m_f4Delta, m_f4InvDelta );
  904. }
  905. private:
  906. fltx4 m_f4Start;
  907. fltx4 m_f4Delta;
  908. fltx4 m_f4InvDelta;
  909. fltx4 m_f4Extents;
  910. };
  911. //-----------------------------------------------------------------------------
  912. // Purpose:
  913. //-----------------------------------------------------------------------------
  914. template <class T>
  915. bool CVoxelHash::EnumerateElementsInVoxel( Voxel_t voxel, const T &intersectTest, SpatialPartitionListMask_t listMask, IPartitionEnumerator* pIterator )
  916. {
  917. // If the voxel doesn't exist, nothing to iterate over
  918. UtlHashFixedHandle_t hHash = m_aVoxelHash.Find( voxel.uiVoxel );
  919. if ( hHash == m_aVoxelHash.InvalidHandle() )
  920. return true;
  921. for ( intp i = m_aVoxelHash.Element( hHash ); i != m_aEntityList.InvalidIndex(); i = m_aEntityList.Next(i) )
  922. {
  923. SpatialPartitionHandle_t handle = m_aEntityList[i].m_handle;
  924. SpatialPartitionListMask_t nListMask = m_aEntityList[i].m_nListMask;
  925. if ( handle == PARTITION_INVALID_HANDLE )
  926. continue;
  927. // Keep going if this dude isn't in the list
  928. if ( !( listMask & nListMask ) )
  929. continue;
  930. EntityInfo_t &hInfo = m_pTree->EntityInfo( handle );
  931. Assert( hInfo.m_fList == nListMask );
  932. if ( hInfo.m_flags & ENTITY_HIDDEN )
  933. continue;
  934. // Has this handle already been visited?
  935. if ( !intersectTest.Visit( handle, hInfo ) )
  936. continue;
  937. // Intersection test
  938. if ( !intersectTest.Intersects( hInfo.m_vecMin.Base(), hInfo.m_vecMax.Base() ) )
  939. continue;
  940. // Okay, this one is good...
  941. if ( pIterator->EnumElement( hInfo.m_pHandleEntity ) == ITERATION_STOP )
  942. return false;
  943. }
  944. return true;
  945. }
  946. //-----------------------------------------------------------------------------
  947. // Enumeration method when only 1 voxel is ever visited
  948. //-----------------------------------------------------------------------------
  949. template <class T>
  950. bool CVoxelHash::EnumerateElementsInSingleVoxel( Voxel_t voxel, const T &intersectTest,
  951. SpatialPartitionListMask_t listMask, IPartitionEnumerator* pIterator )
  952. {
  953. // NOTE: We don't have to do the enum id checking, nor do we have to up the
  954. // nesting level, since this only visits 1 voxel.
  955. intp iEntityList;
  956. UtlHashFixedHandle_t hHash = m_aVoxelHash.Find( voxel.uiVoxel );
  957. if ( hHash != m_aVoxelHash.InvalidHandle() )
  958. {
  959. iEntityList = m_aVoxelHash.Element( hHash );
  960. while ( iEntityList != m_aEntityList.InvalidIndex() )
  961. {
  962. SpatialPartitionHandle_t handle = m_aEntityList[iEntityList].m_handle;
  963. SpatialPartitionListMask_t nListMask = m_aEntityList[iEntityList].m_nListMask;
  964. iEntityList = m_aEntityList.Next( iEntityList );
  965. if ( handle == PARTITION_INVALID_HANDLE )
  966. continue;
  967. // Keep going if this dude isn't in the list
  968. if ( !( listMask & nListMask ) )
  969. continue;
  970. EntityInfo_t &hInfo = m_pTree->EntityInfo( handle );
  971. if ( hInfo.m_flags & ENTITY_HIDDEN )
  972. continue;
  973. // Keep going if there's no collision
  974. if ( !intersectTest.Intersects( hInfo.m_vecMin.Base(), hInfo.m_vecMax.Base() ) )
  975. continue;
  976. // Okay, this one is good...
  977. if ( pIterator->EnumElement( hInfo.m_pHandleEntity ) == ITERATION_STOP )
  978. return false;
  979. }
  980. }
  981. return true;
  982. }
  983. //-----------------------------------------------------------------------------
  984. // Purpose:
  985. //-----------------------------------------------------------------------------
  986. bool CVoxelHash::EnumerateElementsInBox( SpatialPartitionListMask_t listMask,
  987. Voxel_t vmin, Voxel_t vmax, const Vector& mins, const Vector& maxs, IPartitionEnumerator* pIterator )
  988. {
  989. VPROF( "BoxTest/SphereTest" );
  990. Assert( mins.x <= maxs.x );
  991. Assert( mins.y <= maxs.y );
  992. Assert( mins.z <= maxs.z );
  993. // Create the intersection object
  994. bool bSingleVoxel = ( vmin.uiVoxel == vmax.uiVoxel );
  995. CIntersectBox rect( m_pTree, mins, maxs );
  996. // In the same voxel
  997. if ( bSingleVoxel )
  998. return EnumerateElementsInSingleVoxel( vmin, rect, listMask, pIterator );
  999. // Iterate over all voxels
  1000. Voxel_t vdelta;
  1001. vdelta.uiVoxel = vmax.uiVoxel - vmin.uiVoxel;
  1002. int cx = vdelta.bitsVoxel.x;
  1003. int cy = vdelta.bitsVoxel.y;
  1004. int cz = vdelta.bitsVoxel.z;
  1005. // Hijack what can feel like infinite iteration over voxels
  1006. #if defined( _GAMECONSOLE ) && defined( _DEBUG )
  1007. if ( uint64( cx ) * uint64( cy ) * uint64( cz ) > 10000ull )
  1008. {
  1009. Assert( !"CVoxelHash::EnumerateElementsInBox: box too large" );
  1010. return true;
  1011. }
  1012. #endif
  1013. Voxel_t voxel;
  1014. voxel.bitsVoxel.x = vmin.bitsVoxel.x;
  1015. for ( int iX = 0; iX <= cx; ++iX, ++voxel.bitsVoxel.x )
  1016. {
  1017. voxel.bitsVoxel.y = vmin.bitsVoxel.y;
  1018. for ( int iY = 0; iY <= cy; ++iY, ++voxel.bitsVoxel.y )
  1019. {
  1020. voxel.bitsVoxel.z = vmin.bitsVoxel.z;
  1021. for ( int iZ = 0; iZ <= cz; ++iZ, ++voxel.bitsVoxel.z )
  1022. {
  1023. if ( !EnumerateElementsInVoxel( voxel, rect, listMask, pIterator ) )
  1024. return false;
  1025. }
  1026. }
  1027. }
  1028. return true;
  1029. }
  1030. //-----------------------------------------------------------------------------
  1031. // Purpose:
  1032. //-----------------------------------------------------------------------------
  1033. bool CVoxelHash::EnumerateElementsAlongRay( SpatialPartitionListMask_t listMask,
  1034. const Ray_t &ray, const Vector &vecInvDelta, const Vector &vecEnd, IPartitionEnumerator *pIterator )
  1035. {
  1036. Assert( ray.m_IsSwept );
  1037. // Two different methods
  1038. if ( ray.m_IsRay )
  1039. return EnumerateElementsAlongRay_Ray( listMask, ray, vecInvDelta, vecEnd, pIterator );
  1040. return EnumerateElementsAlongRay_ExtrudedRay( listMask, ray, vecInvDelta, vecEnd, pIterator );
  1041. }
  1042. //-----------------------------------------------------------------------------
  1043. // Purpose:
  1044. //-----------------------------------------------------------------------------
  1045. bool CVoxelHash::EnumerateElementsAlongRay_Ray( SpatialPartitionListMask_t listMask,
  1046. const Ray_t &ray, const Vector &vecInvDelta, const Vector &vecEnd, IPartitionEnumerator *pIterator )
  1047. {
  1048. #ifdef _DEBUG
  1049. // For drawing debug objects.
  1050. static int nRenderRayEnumId = 4;
  1051. #endif
  1052. // Find the voxel start + end
  1053. Voxel_t voxelStart = VoxelIndexFromPoint( ray.m_Start );
  1054. Voxel_t voxelEnd = VoxelIndexFromPoint( vecEnd );
  1055. bool bSingleVoxel = ( voxelStart.uiVoxel == voxelEnd.uiVoxel );
  1056. CIntersectRay intersectRay( m_pTree, ray, vecInvDelta );
  1057. // Optimization: Look for single voxel rays
  1058. if ( bSingleVoxel )
  1059. return EnumerateElementsInSingleVoxel( voxelStart, intersectRay, listMask, pIterator );
  1060. Voxel_t voxelCurrent;
  1061. voxelCurrent.uiVoxel = voxelStart.uiVoxel;
  1062. // Setup.
  1063. int nStep[3];
  1064. float tMax[3];
  1065. float tDelta[3];
  1066. LeafListRaySetup( ray, vecEnd, vecInvDelta, voxelStart, nStep, tMax, tDelta );
  1067. // Walk the voxels and visit all elements in each voxel
  1068. while ( 1 )
  1069. {
  1070. if ( !EnumerateElementsInVoxel( voxelCurrent, intersectRay, listMask, pIterator ) )
  1071. return false;
  1072. if ( tMax[0] >= 1.0f && tMax[1] >= 1.0f && tMax[2] >= 1.0f )
  1073. break;
  1074. if ( tMax[0] < tMax[1] )
  1075. {
  1076. if ( tMax[0] < tMax[2] )
  1077. {
  1078. voxelCurrent.bitsVoxel.x += nStep[0];
  1079. tMax[0] += tDelta[0];
  1080. }
  1081. else
  1082. {
  1083. voxelCurrent.bitsVoxel.z += nStep[2];
  1084. tMax[2] += tDelta[2];
  1085. }
  1086. }
  1087. else
  1088. {
  1089. if ( tMax[1] < tMax[2] )
  1090. {
  1091. voxelCurrent.bitsVoxel.y += nStep[1];
  1092. tMax[1] += tDelta[1];
  1093. }
  1094. else
  1095. {
  1096. voxelCurrent.bitsVoxel.z += nStep[2];
  1097. tMax[2] += tDelta[2];
  1098. }
  1099. }
  1100. }
  1101. return true;
  1102. }
  1103. //-----------------------------------------------------------------------------
  1104. // Purpose:
  1105. //-----------------------------------------------------------------------------
  1106. void CVoxelHash::LeafListRaySetup( const Ray_t &ray, const Vector &vecEnd,
  1107. const Vector &vecInvDelta, Voxel_t voxel, int *pStep, float *pMax, float *pDelta )
  1108. {
  1109. int iVoxel[3];
  1110. iVoxel[0] = voxel.bitsVoxel.x;
  1111. iVoxel[1] = voxel.bitsVoxel.y;
  1112. iVoxel[2] = voxel.bitsVoxel.z;
  1113. // Setup.
  1114. float flDist, flDistStart, flDistEnd, flRecipDist;
  1115. Vector vecVoxelStart, vecVoxelEnd;
  1116. VectorSubtract( ray.m_Start, m_vecVoxelOrigin, vecVoxelStart );
  1117. VectorSubtract( vecEnd, m_vecVoxelOrigin, vecVoxelEnd );
  1118. for ( int iAxis = 0; iAxis < 3; ++iAxis )
  1119. {
  1120. if ( vecVoxelStart[iAxis] == vecVoxelEnd[iAxis] )
  1121. {
  1122. pStep[iAxis] = 0;
  1123. pMax[iAxis] = SPHASH_VOXEL_LARGE;
  1124. pDelta[iAxis] = SPHASH_VOXEL_LARGE;
  1125. continue;
  1126. }
  1127. if ( ray.m_Delta[iAxis] < 0.0f )
  1128. {
  1129. pStep[iAxis] = -1;
  1130. flDist = ( iVoxel[iAxis] ) * VoxelSize();
  1131. flDistStart = vecVoxelStart[iAxis] - flDist;
  1132. flDistEnd = vecVoxelEnd[iAxis] - flDist;
  1133. flRecipDist = -vecInvDelta[iAxis];
  1134. }
  1135. else
  1136. {
  1137. pStep[iAxis] = 1;
  1138. flDist = ( iVoxel[iAxis] + 1 ) * -VoxelSize();
  1139. flDistStart = -vecVoxelStart[iAxis] - flDist;
  1140. flDistEnd = -vecVoxelEnd[iAxis] - flDist;
  1141. flRecipDist = vecInvDelta[iAxis];
  1142. }
  1143. if ( ( flDistStart > 0.0f ) && ( flDistEnd > 0.0f ) )
  1144. {
  1145. pMax[iAxis] = SPHASH_VOXEL_LARGE;
  1146. pDelta[iAxis] = SPHASH_VOXEL_LARGE;
  1147. }
  1148. else
  1149. {
  1150. pMax[iAxis] = flDistStart * flRecipDist;
  1151. pDelta[iAxis] = VoxelSize() * flRecipDist;
  1152. }
  1153. }
  1154. }
  1155. //-----------------------------------------------------------------------------
  1156. // Computes the min index of 3 numbers
  1157. //-----------------------------------------------------------------------------
  1158. inline int MinIndex( float v1, float v2, float v3 )
  1159. {
  1160. if ( v1 < v2 )
  1161. return ( v1 < v3 ) ? 0 : 2;
  1162. return ( v2 < v3 ) ? 1 : 2;
  1163. }
  1164. //-----------------------------------------------------------------------------
  1165. // Purpose:
  1166. //-----------------------------------------------------------------------------
  1167. bool CVoxelHash::EnumerateElementsAlongRay_ExtrudedRay( SpatialPartitionListMask_t listMask,
  1168. const Ray_t &ray, const Vector &vecInvDelta, const Vector &vecEnd, IPartitionEnumerator *pIterator )
  1169. {
  1170. // Check the starting position, then proceed with the sweep.
  1171. Vector vecMin, vecMax;
  1172. VectorSubtract( ray.m_Start, ray.m_Extents, vecMin );
  1173. VectorAdd( ray.m_Start, ray.m_Extents, vecMax );
  1174. // Visit each voxel in the box and enumerate its elements.
  1175. int voxelMin[3], voxelMax[3];
  1176. VoxelIndexFromPoint( vecMin, voxelMin );
  1177. VoxelIndexFromPoint( vecMax, voxelMax );
  1178. CIntersectSweptBox intersectSweptBox( m_pTree, ray, vecInvDelta );
  1179. // Iterate over all voxels that intersect the box around the starting ray point
  1180. Voxel_t voxel;
  1181. int iX, iY, iZ;
  1182. for ( iX = voxelMin[0]; iX <= voxelMax[0]; ++iX )
  1183. {
  1184. voxel.bitsVoxel.x = iX;
  1185. for ( iY = voxelMin[1]; iY <= voxelMax[1]; ++iY )
  1186. {
  1187. voxel.bitsVoxel.y = iY;
  1188. for ( iZ = voxelMin[2]; iZ <= voxelMax[2]; ++iZ )
  1189. {
  1190. voxel.bitsVoxel.z = iZ;
  1191. if ( !EnumerateElementsInVoxel( voxel, intersectSweptBox, listMask, pIterator ) )
  1192. return false;
  1193. }
  1194. }
  1195. }
  1196. // Early out: Check to see if the range of voxels at the endpoint
  1197. // is the same as the range at the start point. If so, we're done.
  1198. Vector vecEndMin, vecEndMax;
  1199. VectorSubtract( vecEnd, ray.m_Extents, vecEndMin );
  1200. VectorAdd( vecEnd, ray.m_Extents, vecEndMax );
  1201. int endVoxelMin[3], endVoxelMax[3];
  1202. VoxelIndexFromPoint( vecEndMin, endVoxelMin );
  1203. VoxelIndexFromPoint( vecEndMax, endVoxelMax );
  1204. if ( (endVoxelMin[0] >= voxelMin[0]) && (endVoxelMin[1] >= voxelMin[1]) && (endVoxelMin[2] >= voxelMin[2]) &&
  1205. (endVoxelMax[0] <= voxelMax[0]) && (endVoxelMax[1] <= voxelMax[1]) && (endVoxelMax[2] <= voxelMax[2]) )
  1206. return true;
  1207. // Setup.
  1208. int nStep[3];
  1209. float tMax[3]; // amount of change in t along ray until we hit the next new voxel
  1210. float tMin[3]; // amount of change in t along ray until we leave the last voxel
  1211. float tDelta[3];
  1212. LeafListExtrudedRaySetup( ray, vecInvDelta, vecMin, vecMax, voxelMin, voxelMax, nStep, tMin, tMax, tDelta );
  1213. // Walk the voxels and create the leaf list.
  1214. int iAxis, iMinAxis;
  1215. while ( tMax[0] < 1.0f || tMax[1] < 1.0f || tMax[2] < 1.0f )
  1216. {
  1217. iAxis = MinIndex( tMax[0], tMax[1], tMax[2] );
  1218. iMinAxis = MinIndex( tMin[0], tMin[1], tMin[2] );
  1219. if ( tMin[iMinAxis] < tMax[iAxis] )
  1220. {
  1221. tMin[iMinAxis] += tDelta[iMinAxis];
  1222. if ( nStep[iMinAxis] > 0 )
  1223. {
  1224. voxelMin[iMinAxis] += nStep[iMinAxis];
  1225. }
  1226. else
  1227. {
  1228. voxelMax[iMinAxis] += nStep[iMinAxis];
  1229. }
  1230. }
  1231. else
  1232. {
  1233. tMax[iAxis] += tDelta[iAxis];
  1234. if ( nStep[iAxis] > 0 )
  1235. {
  1236. voxelMax[iAxis] += nStep[iAxis];
  1237. }
  1238. else
  1239. {
  1240. voxelMin[iAxis] += nStep[iAxis];
  1241. }
  1242. if ( !EnumerateElementsAlongRay_ExtrudedRaySlice( listMask, pIterator, intersectSweptBox, voxelMin, voxelMax, iAxis, nStep ) )
  1243. return false;
  1244. }
  1245. }
  1246. return true;
  1247. }
  1248. //-----------------------------------------------------------------------------
  1249. // Purpose:
  1250. //-----------------------------------------------------------------------------
  1251. void CVoxelHash::LeafListExtrudedRaySetup( const Ray_t &ray, const Vector &vecInvDelta,
  1252. const Vector &vecMin, const Vector &vecMax,
  1253. int iVoxelMin[3], int iVoxelMax[3],
  1254. int *pStep, float *pMin, float *pMax, float *pDelta )
  1255. {
  1256. float flDist, flDistStart, flRecipDist, flDistMinStart;
  1257. Vector vecVoxelMin, vecVoxelMax;
  1258. VectorSubtract( vecMin, m_vecVoxelOrigin, vecVoxelMin );
  1259. VectorSubtract( vecMax, m_vecVoxelOrigin, vecVoxelMax );
  1260. for ( int iAxis = 0; iAxis < 3; ++iAxis )
  1261. {
  1262. if ( ray.m_Delta[iAxis] == 0.0f )
  1263. {
  1264. pMax[iAxis] = SPHASH_VOXEL_LARGE;
  1265. pMin[iAxis] = SPHASH_VOXEL_LARGE;
  1266. pDelta[iAxis] = SPHASH_VOXEL_LARGE;
  1267. continue;
  1268. }
  1269. if ( ray.m_Delta[iAxis] < 0.0f )
  1270. {
  1271. pStep[iAxis] = -1;
  1272. flDistStart = vecVoxelMin[iAxis] - ( ( iVoxelMin[iAxis] ) * VoxelSize() );
  1273. flDistMinStart = vecVoxelMax[iAxis] - ( ( iVoxelMax[iAxis] ) * VoxelSize() );
  1274. flDist = -ray.m_Delta[iAxis];
  1275. flRecipDist = -vecInvDelta[iAxis];
  1276. }
  1277. else
  1278. {
  1279. pStep[iAxis] = 1;
  1280. flDistStart = -vecVoxelMax[iAxis] - ( ( iVoxelMax[iAxis] + 1 ) * -VoxelSize() );
  1281. flDistMinStart = -vecVoxelMin[iAxis] - ( ( iVoxelMin[iAxis] + 1 ) * -VoxelSize() );
  1282. flDist = ray.m_Delta[iAxis];
  1283. flRecipDist = vecInvDelta[iAxis];
  1284. }
  1285. if ( flDistStart > flDist )
  1286. {
  1287. pMax[iAxis] = SPHASH_VOXEL_LARGE;
  1288. pDelta[iAxis] = SPHASH_VOXEL_LARGE;
  1289. }
  1290. else
  1291. {
  1292. pMax[iAxis] = flDistStart * flRecipDist;
  1293. pDelta[iAxis] = VoxelSize() * flRecipDist;
  1294. }
  1295. if ( flDistMinStart > flDist )
  1296. {
  1297. pMin[iAxis] = SPHASH_VOXEL_LARGE;
  1298. }
  1299. else
  1300. {
  1301. pMin[iAxis] = flDistMinStart * flRecipDist;
  1302. }
  1303. }
  1304. }
  1305. //-----------------------------------------------------------------------------
  1306. // Purpose:
  1307. //-----------------------------------------------------------------------------
  1308. bool CVoxelHash::EnumerateElementsAlongRay_ExtrudedRaySlice( SpatialPartitionListMask_t listMask,
  1309. IPartitionEnumerator *pIterator, const CIntersectSweptBox &intersectSweptBox,
  1310. int voxelMin[3], int voxelMax[3], int iAxis, int *pStep )
  1311. {
  1312. int mins[3] = { voxelMin[0], voxelMin[1], voxelMin[2] };
  1313. int maxs[3] = { voxelMax[0], voxelMax[1], voxelMax[2] };
  1314. if ( pStep[iAxis] < 0.0f )
  1315. {
  1316. maxs[iAxis] = mins[iAxis];
  1317. }
  1318. else
  1319. {
  1320. mins[iAxis] = maxs[iAxis];
  1321. }
  1322. // Create leaf cache.
  1323. Voxel_t voxel;
  1324. int iX, iY, iZ;
  1325. for ( iX = mins[0]; iX <= maxs[0]; ++iX )
  1326. {
  1327. voxel.bitsVoxel.x = iX;
  1328. for ( iY = mins[1]; iY <= maxs[1]; ++iY )
  1329. {
  1330. voxel.bitsVoxel.y = iY;
  1331. for ( iZ = mins[2]; iZ <= maxs[2]; ++iZ )
  1332. {
  1333. voxel.bitsVoxel.z = iZ;
  1334. if ( !EnumerateElementsInVoxel( voxel, intersectSweptBox, listMask, pIterator ) )
  1335. return false;
  1336. }
  1337. }
  1338. }
  1339. return true;
  1340. }
  1341. //-----------------------------------------------------------------------------
  1342. // Purpose:
  1343. //-----------------------------------------------------------------------------
  1344. bool CVoxelHash::EnumerateElementsAtPoint( SpatialPartitionListMask_t listMask,
  1345. Voxel_t v, const Vector& pt, IPartitionEnumerator* pIterator )
  1346. {
  1347. // NOTE: We don't have to do the enum id checking, nor do we have to up the
  1348. // nesting level, since this only visits 1 voxel.
  1349. intp iEntityList;
  1350. UtlHashFixedHandle_t hHash = m_aVoxelHash.Find( v.uiVoxel );
  1351. if ( hHash != m_aVoxelHash.InvalidHandle() )
  1352. {
  1353. iEntityList = m_aVoxelHash.Element( hHash );
  1354. while ( iEntityList != m_aEntityList.InvalidIndex() )
  1355. {
  1356. SpatialPartitionHandle_t handle = m_aEntityList[iEntityList].m_handle;
  1357. SpatialPartitionListMask_t nListMask = m_aEntityList[iEntityList].m_nListMask;
  1358. iEntityList = m_aEntityList.Next( iEntityList );
  1359. if ( handle == PARTITION_INVALID_HANDLE )
  1360. continue;
  1361. // Keep going if this dude isn't in the list
  1362. if ( !( listMask & nListMask ) )
  1363. continue;
  1364. EntityInfo_t &hInfo = m_pTree->EntityInfo( handle );
  1365. if ( hInfo.m_flags & ENTITY_HIDDEN )
  1366. continue;
  1367. // Keep going if there's no collision
  1368. if ( !IsPointInBox( pt, hInfo.m_vecMin, hInfo.m_vecMax ) )
  1369. continue;
  1370. // Okay, this one is good...
  1371. if ( pIterator->EnumElement( hInfo.m_pHandleEntity ) == ITERATION_STOP )
  1372. return false;
  1373. }
  1374. }
  1375. return true;
  1376. }
  1377. //-----------------------------------------------------------------------------
  1378. // Purpose: Debug! Render a voxel - blue.
  1379. //-----------------------------------------------------------------------------
  1380. void CVoxelHash::RenderVoxel( Voxel_t voxel, float flTime )
  1381. {
  1382. #ifndef DEDICATED
  1383. Vector vecMin, vecMax;
  1384. vecMin.x = ( voxel.bitsVoxel.x * VoxelSize() ) + m_vecVoxelOrigin.x;
  1385. vecMin.y = ( voxel.bitsVoxel.y * VoxelSize() ) + m_vecVoxelOrigin.y;
  1386. vecMin.z = ( voxel.bitsVoxel.z * VoxelSize() ) + m_vecVoxelOrigin.z;
  1387. vecMax.x = ( ( voxel.bitsVoxel.x + 1 ) * VoxelSize() ) + m_vecVoxelOrigin.x;
  1388. vecMax.y = ( ( voxel.bitsVoxel.y + 1 ) * VoxelSize() ) + m_vecVoxelOrigin.y;
  1389. vecMax.z = ( ( voxel.bitsVoxel.z + 1 ) * VoxelSize() ) + m_vecVoxelOrigin.z;
  1390. CDebugOverlay::AddBoxOverlay( vec3_origin, vecMin, vecMax, vec3_angle, s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 30, flTime );
  1391. // Add outline.
  1392. Vector vecPoints[8];
  1393. vecPoints[0].Init( vecMin.x, vecMin.y, vecMin.z );
  1394. vecPoints[1].Init( vecMin.x, vecMax.y, vecMin.z );
  1395. vecPoints[2].Init( vecMax.x, vecMax.y, vecMin.z );
  1396. vecPoints[3].Init( vecMax.x, vecMin.y, vecMin.z );
  1397. vecPoints[4].Init( vecMin.x, vecMin.y, vecMax.z );
  1398. vecPoints[5].Init( vecMin.x, vecMax.y, vecMax.z );
  1399. vecPoints[6].Init( vecMax.x, vecMax.y, vecMax.z );
  1400. vecPoints[7].Init( vecMax.x, vecMin.y, vecMax.z );
  1401. CDebugOverlay::AddLineOverlay( vecPoints[0], vecPoints[1], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1402. CDebugOverlay::AddLineOverlay( vecPoints[1], vecPoints[2], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1403. CDebugOverlay::AddLineOverlay( vecPoints[2], vecPoints[3], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1404. CDebugOverlay::AddLineOverlay( vecPoints[3], vecPoints[0], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1405. CDebugOverlay::AddLineOverlay( vecPoints[4], vecPoints[5], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1406. CDebugOverlay::AddLineOverlay( vecPoints[5], vecPoints[6], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1407. CDebugOverlay::AddLineOverlay( vecPoints[6], vecPoints[7], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1408. CDebugOverlay::AddLineOverlay( vecPoints[7], vecPoints[4], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1409. CDebugOverlay::AddLineOverlay( vecPoints[0], vecPoints[4], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1410. CDebugOverlay::AddLineOverlay( vecPoints[3], vecPoints[7], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1411. CDebugOverlay::AddLineOverlay( vecPoints[1], vecPoints[5], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1412. CDebugOverlay::AddLineOverlay( vecPoints[2], vecPoints[6], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1413. #endif
  1414. }
  1415. //-----------------------------------------------------------------------------
  1416. // Purpose: Debug! Render an object in a voxel - green.
  1417. //-----------------------------------------------------------------------------
  1418. void CVoxelHash::RenderObjectInVoxel( SpatialPartitionHandle_t hPartition, CPartitionVisitor *pVisitor, float flTime )
  1419. {
  1420. #ifndef DEDICATED
  1421. // Add outline.
  1422. if ( hPartition == PARTITION_INVALID_HANDLE )
  1423. return;
  1424. EntityInfo_t &info = m_pTree->EntityInfo( hPartition );
  1425. if ( !pVisitor->Visit( hPartition, info ) )
  1426. {
  1427. return;
  1428. }
  1429. CDebugOverlay::AddBoxOverlay( vec3_origin, info.m_vecMin, info.m_vecMax, vec3_angle, s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 75, flTime );
  1430. // Add outline.
  1431. Vector vecMin, vecMax;
  1432. vecMin = info.m_vecMin;
  1433. vecMax = info.m_vecMax;
  1434. Vector vecPoints[8];
  1435. vecPoints[0].Init( vecMin.x, vecMin.y, vecMin.z );
  1436. vecPoints[1].Init( vecMin.x, vecMax.y, vecMin.z );
  1437. vecPoints[2].Init( vecMax.x, vecMax.y, vecMin.z );
  1438. vecPoints[3].Init( vecMax.x, vecMin.y, vecMin.z );
  1439. vecPoints[4].Init( vecMin.x, vecMin.y, vecMax.z );
  1440. vecPoints[5].Init( vecMin.x, vecMax.y, vecMax.z );
  1441. vecPoints[6].Init( vecMax.x, vecMax.y, vecMax.z );
  1442. vecPoints[7].Init( vecMax.x, vecMin.y, vecMax.z );
  1443. CDebugOverlay::AddLineOverlay( vecPoints[0], vecPoints[1], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1444. CDebugOverlay::AddLineOverlay( vecPoints[1], vecPoints[2], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1445. CDebugOverlay::AddLineOverlay( vecPoints[2], vecPoints[3], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1446. CDebugOverlay::AddLineOverlay( vecPoints[3], vecPoints[0], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1447. CDebugOverlay::AddLineOverlay( vecPoints[4], vecPoints[5], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1448. CDebugOverlay::AddLineOverlay( vecPoints[5], vecPoints[6], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1449. CDebugOverlay::AddLineOverlay( vecPoints[6], vecPoints[7], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1450. CDebugOverlay::AddLineOverlay( vecPoints[7], vecPoints[4], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1451. CDebugOverlay::AddLineOverlay( vecPoints[0], vecPoints[4], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1452. CDebugOverlay::AddLineOverlay( vecPoints[3], vecPoints[7], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1453. CDebugOverlay::AddLineOverlay( vecPoints[1], vecPoints[5], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1454. CDebugOverlay::AddLineOverlay( vecPoints[2], vecPoints[6], s_pVoxelColor[m_nLevel][0], s_pVoxelColor[m_nLevel][1], s_pVoxelColor[m_nLevel][2], 255, true, flTime );
  1455. #endif
  1456. }
  1457. //-----------------------------------------------------------------------------
  1458. // Purpose: Debug! Render the objects in a voxel (optionally, render the voxel!).
  1459. //-----------------------------------------------------------------------------
  1460. void CVoxelHash::RenderObjectsInVoxel( Voxel_t voxel, CPartitionVisitor *pVisitor, bool bRenderVoxel, float flTime )
  1461. {
  1462. UtlHashFixedHandle_t hHash = m_aVoxelHash.Find( voxel.uiVoxel );
  1463. if ( hHash == m_aVoxelHash.InvalidHandle() )
  1464. return;
  1465. intp iEntityList = m_aVoxelHash.Element( hHash );
  1466. while ( iEntityList != m_aEntityList.InvalidIndex() )
  1467. {
  1468. SpatialPartitionHandle_t hPartition = m_aEntityList[iEntityList].m_handle;
  1469. RenderObjectInVoxel( hPartition, pVisitor, flTime );
  1470. iEntityList = m_aEntityList.Next( iEntityList );
  1471. }
  1472. if ( bRenderVoxel )
  1473. {
  1474. RenderVoxel( voxel, flTime );
  1475. }
  1476. }
  1477. //-----------------------------------------------------------------------------
  1478. // Returns number of entities in the hash
  1479. //-----------------------------------------------------------------------------
  1480. int CVoxelHash::EntityCount()
  1481. {
  1482. int nCount = 0;
  1483. int nBucketCount = SPHASH_BUCKET_COUNT;
  1484. for ( int iBucket = 0; iBucket < nBucketCount; ++iBucket )
  1485. {
  1486. if ( m_aVoxelHash.m_aBuckets[iBucket].Count() == 0 )
  1487. continue;
  1488. UtlPtrLinkedListIndex_t hHash = m_aVoxelHash.m_aBuckets[iBucket].Head();
  1489. while ( hHash != m_aVoxelHash.m_aBuckets[iBucket].InvalidIndex() )
  1490. {
  1491. intp iEntity = m_aVoxelHash.m_aBuckets[iBucket][hHash].m_Data;
  1492. while ( iEntity!= m_aEntityList.InvalidIndex() )
  1493. {
  1494. ++nCount;
  1495. iEntity = m_aEntityList.Next( iEntity );
  1496. }
  1497. hHash = m_aVoxelHash.m_aBuckets[iBucket].Next( hHash );
  1498. }
  1499. }
  1500. return nCount;
  1501. }
  1502. //-----------------------------------------------------------------------------
  1503. // Rendering methods
  1504. //-----------------------------------------------------------------------------
  1505. void CVoxelHash::RenderGrid()
  1506. {
  1507. #ifndef DEDICATED
  1508. Vector vecStart, vecEnd;
  1509. for ( int i = 0; i < m_nVoxelDelta[0]; ++i )
  1510. {
  1511. vecStart.x = vecEnd.x = i * VoxelSize() + m_vecVoxelOrigin.x;
  1512. for ( int j = 0; j < m_nVoxelDelta[1]; ++j )
  1513. {
  1514. vecStart.y = vecEnd.y = j * VoxelSize() + m_vecVoxelOrigin.y;
  1515. vecStart.z = m_vecVoxelOrigin.z;
  1516. vecEnd.z = m_nVoxelDelta[2] * VoxelSize() + m_vecVoxelOrigin.z;
  1517. RenderLine( vecStart, vecEnd, s_pVoxelColor[m_nLevel], true );
  1518. }
  1519. }
  1520. for ( int i = 0; i < m_nVoxelDelta[0]; ++i )
  1521. {
  1522. vecStart.x = vecEnd.x = i * VoxelSize() + m_vecVoxelOrigin.x;
  1523. for ( int j = 0; j < m_nVoxelDelta[2]; ++j )
  1524. {
  1525. vecStart.z = vecEnd.z = j * VoxelSize() + m_vecVoxelOrigin.z;
  1526. vecStart.y = m_vecVoxelOrigin.y;
  1527. vecEnd.y = m_nVoxelDelta[2] * VoxelSize() + m_vecVoxelOrigin.y;
  1528. RenderLine( vecStart, vecEnd, s_pVoxelColor[m_nLevel], true );
  1529. }
  1530. }
  1531. for ( int i = 0; i < m_nVoxelDelta[1]; ++i )
  1532. {
  1533. vecStart.y = vecEnd.y = i * VoxelSize() + m_vecVoxelOrigin.y;
  1534. for ( int j = 0; j < m_nVoxelDelta[2]; ++j )
  1535. {
  1536. vecStart.z = vecEnd.z = j * VoxelSize() + m_vecVoxelOrigin.z;
  1537. vecStart.x = m_vecVoxelOrigin.z;
  1538. vecEnd.x = m_nVoxelDelta[2] * VoxelSize() + m_vecVoxelOrigin.x;
  1539. RenderLine( vecStart, vecEnd, s_pVoxelColor[m_nLevel], true );
  1540. }
  1541. }
  1542. #endif
  1543. }
  1544. //-----------------------------------------------------------------------------
  1545. // Purpose: Debug! Render boxes around objects in tree.
  1546. //-----------------------------------------------------------------------------
  1547. void CVoxelHash::RenderAllObjectsInTree( float flTime )
  1548. {
  1549. int nBucketCount = SPHASH_BUCKET_COUNT;
  1550. CPartitionVisits *pPrevVisits = m_pTree->BeginVisit();
  1551. CPartitionVisitor visitor( m_pTree );
  1552. for ( int iBucket = 0; iBucket < nBucketCount; ++iBucket )
  1553. {
  1554. if ( m_aVoxelHash.m_aBuckets[iBucket].Count() == 0 )
  1555. continue;
  1556. UtlPtrLinkedListIndex_t hHash = m_aVoxelHash.m_aBuckets[iBucket].Head();
  1557. while ( hHash != m_aVoxelHash.m_aBuckets[iBucket].InvalidIndex() )
  1558. {
  1559. intp iEntity = m_aVoxelHash.m_aBuckets[iBucket][hHash].m_Data;
  1560. while ( iEntity!= m_aEntityList.InvalidIndex() )
  1561. {
  1562. SpatialPartitionHandle_t hPartition = m_aEntityList[iEntity].m_handle;
  1563. RenderObjectInVoxel( hPartition, &visitor, flTime );
  1564. iEntity = m_aEntityList.Next( iEntity );
  1565. }
  1566. hHash = m_aVoxelHash.m_aBuckets[iBucket].Next( hHash );
  1567. }
  1568. }
  1569. m_pTree->EndVisit( pPrevVisits );
  1570. }
  1571. //-----------------------------------------------------------------------------
  1572. // Purpose:
  1573. //-----------------------------------------------------------------------------
  1574. void CVoxelHash::RenderObjectsInPlayerLeafs( const Vector &vecPlayerMin, const Vector &vecPlayerMax, float flTime )
  1575. {
  1576. // Visit each voxel in the box and enumerate its elements.
  1577. Voxel_t voxelMin, voxelMax;
  1578. voxelMin = VoxelIndexFromPoint( vecPlayerMin );
  1579. voxelMax = VoxelIndexFromPoint( vecPlayerMax );
  1580. CPartitionVisits *pPrevVisits = m_pTree->BeginVisit();
  1581. // Create leaf cache.
  1582. Voxel_t voxel;
  1583. unsigned int iX, iY, iZ;
  1584. CPartitionVisitor visitor( m_pTree );
  1585. for ( iX = voxelMin.bitsVoxel.x; iX <= voxelMax.bitsVoxel.x; ++iX )
  1586. {
  1587. for ( iY = voxelMin.bitsVoxel.y; iY <= voxelMax.bitsVoxel.y; ++iY )
  1588. {
  1589. for ( iZ = voxelMin.bitsVoxel.z; iZ <= voxelMax.bitsVoxel.z; ++iZ )
  1590. {
  1591. voxel.bitsVoxel.x = iX;
  1592. voxel.bitsVoxel.y = iY;
  1593. voxel.bitsVoxel.z = iZ;
  1594. RenderObjectsInVoxel( voxel, &visitor, false, flTime );
  1595. }
  1596. }
  1597. }
  1598. m_pTree->EndVisit( pPrevVisits );
  1599. }
  1600. //-----------------------------------------------------------------------------
  1601. // Purpose: Constructor
  1602. //-----------------------------------------------------------------------------
  1603. CVoxelTree::CVoxelTree() : m_pVoxelHash( NULL ), m_pOwner( NULL ), m_nNextVisitBit( 0 )
  1604. {
  1605. // Compute max number of levels
  1606. m_nLevelCount = 0;
  1607. while ( CVoxelHash::ComputeVoxelCountAtLevel( m_nLevelCount ) > 2 )
  1608. {
  1609. ++m_nLevelCount;
  1610. }
  1611. ++m_nLevelCount; // Account for the level where count = 2;
  1612. // Various optimizations I've made require 4 levels
  1613. Assert( m_nLevelCount == 4 );
  1614. m_pVoxelHash = new CVoxelHash[m_nLevelCount];
  1615. m_AvailableVisitBits.EnsureCapacity( 2048 );
  1616. }
  1617. //-----------------------------------------------------------------------------
  1618. //
  1619. //-----------------------------------------------------------------------------
  1620. CVoxelTree::~CVoxelTree()
  1621. {
  1622. delete[] m_pVoxelHash;
  1623. }
  1624. void ClampVector( Vector &out, const Vector &mins, const Vector &maxs )
  1625. {
  1626. for ( int i = 0; i < 3; i++ )
  1627. {
  1628. out[i] = clamp(out[i], mins[i], maxs[i]);
  1629. }
  1630. }
  1631. //-----------------------------------------------------------------------------
  1632. // Purpose:
  1633. // Input: worldmin -
  1634. // worldmax -
  1635. //-----------------------------------------------------------------------------
  1636. void CVoxelTree::Init( CSpatialPartition *pOwner, int iTree, const Vector &worldmin, const Vector &worldmax )
  1637. {
  1638. m_pOwner = pOwner;
  1639. m_TreeId = iTree;
  1640. // Reset the enumeration id.
  1641. memset( m_pVisits, 0, sizeof( m_pVisits ) );
  1642. for ( int i = 0; i < m_nLevelCount; ++i )
  1643. {
  1644. m_pVoxelHash[i].Init( this, worldmin, worldmax, i );
  1645. }
  1646. // Setup the leaf list pool.
  1647. m_aLeafList.Purge();
  1648. m_aLeafList.SetGrowSize( SPHASH_LEAFLIST_BLOCK );
  1649. }
  1650. //-----------------------------------------------------------------------------
  1651. // Purpose:
  1652. //-----------------------------------------------------------------------------
  1653. void CVoxelTree::Shutdown( void )
  1654. {
  1655. m_aLeafList.Purge();
  1656. for ( int i = 0; i < m_nLevelCount; ++i )
  1657. {
  1658. m_pVoxelHash[i].Shutdown();
  1659. }
  1660. }
  1661. //-----------------------------------------------------------------------------
  1662. // Insert into the appropriate tree
  1663. //-----------------------------------------------------------------------------
  1664. void CVoxelTree::InsertIntoTree( SpatialPartitionHandle_t hPartition, const Vector& mins, const Vector& maxs, bool bReinsert )
  1665. {
  1666. Assert( hPartition != PARTITION_INVALID_HANDLE );
  1667. EntityInfo_t &info = EntityInfo( hPartition );
  1668. // Bloat by an eps before inserting the object into the tree.
  1669. Vector vecMin( mins.x - SPHASH_EPS, mins.y - SPHASH_EPS, mins.z - SPHASH_EPS );
  1670. Vector vecMax( maxs.x + SPHASH_EPS, maxs.y + SPHASH_EPS, maxs.z + SPHASH_EPS );
  1671. ClampVector(vecMin, s_PartitionMin, s_PartitionMax);
  1672. ClampVector(vecMax, s_PartitionMin, s_PartitionMax);
  1673. Vector vecSize;
  1674. VectorSubtract( vecMax, vecMin, vecSize );
  1675. int nLevel;
  1676. for ( nLevel = 0; nLevel < m_nLevelCount - 1; ++nLevel )
  1677. {
  1678. float flVoxelSize = m_pVoxelHash[nLevel].VoxelSizeF();
  1679. if ( (flVoxelSize > vecSize.x) && (flVoxelSize > vecSize.y) && (flVoxelSize > vecSize.z) )
  1680. break;
  1681. }
  1682. // Add the object to the tree.
  1683. Voxel_t voxelMin, voxelMax;
  1684. voxelMin = m_pVoxelHash[nLevel].VoxelIndexFromPoint( vecMin );
  1685. voxelMax = m_pVoxelHash[nLevel].VoxelIndexFromPoint( vecMax );
  1686. bool bDoInsert = true;
  1687. if ( bReinsert )
  1688. {
  1689. // on reinsert we need to either remove/insert or not do anything
  1690. // if the entity spans the same bounding box of voxels no remove/insert is necessary
  1691. if ( info.m_voxelMin.uiVoxel == voxelMin.uiVoxel && info.m_voxelMax.uiVoxel == voxelMax.uiVoxel )
  1692. {
  1693. bDoInsert = false;
  1694. }
  1695. else
  1696. {
  1697. // Remove entity from voxel hash.
  1698. RemoveFromTree( hPartition );
  1699. }
  1700. }
  1701. // Set/update the entity bounding box.
  1702. info.m_vecMin = vecMin;
  1703. info.m_vecMax = vecMax;
  1704. if ( bDoInsert )
  1705. {
  1706. bool bWasReading = ( m_pVisits[g_nThreadID] != NULL );
  1707. if ( bWasReading )
  1708. {
  1709. // If we're recursing in this thread, need to release our read lock to allow ourselves to write
  1710. UnlockRead();
  1711. }
  1712. m_lock.LockForWrite();
  1713. // if these have changed we need to insert
  1714. info.m_voxelMin = voxelMin;
  1715. info.m_voxelMax = voxelMax;
  1716. if ( m_AvailableVisitBits.Count() )
  1717. {
  1718. info.m_nVisitBit[m_TreeId] = m_AvailableVisitBits.Tail();
  1719. m_AvailableVisitBits.Remove( m_AvailableVisitBits.Count() - 1 );
  1720. }
  1721. else
  1722. {
  1723. info.m_nVisitBit[m_TreeId] = m_nNextVisitBit++;
  1724. }
  1725. m_pVoxelHash[nLevel].InsertIntoTree( hPartition, voxelMin, voxelMax );
  1726. m_lock.UnlockWrite();
  1727. if ( bWasReading )
  1728. {
  1729. LockForRead();
  1730. }
  1731. }
  1732. }
  1733. //-----------------------------------------------------------------------------
  1734. // Remove from appropriate tree
  1735. //-----------------------------------------------------------------------------
  1736. void CVoxelTree::RemoveFromTree( SpatialPartitionHandle_t hPartition )
  1737. {
  1738. Assert( hPartition != PARTITION_INVALID_HANDLE );
  1739. EntityInfo_t &info = EntityInfo( hPartition );
  1740. int nLevel = info.m_nLevel[GetTreeId()];
  1741. if ( nLevel >= 0 )
  1742. {
  1743. bool bWasReading = ( m_pVisits[g_nThreadID] != NULL );
  1744. if ( bWasReading )
  1745. {
  1746. // If we're recursing in this thread, need to release our read lock to allow ourselves to write
  1747. UnlockRead();
  1748. }
  1749. m_lock.LockForWrite();
  1750. m_pVoxelHash[nLevel].RemoveFromTree( hPartition );
  1751. m_AvailableVisitBits.AddToTail( info.m_nVisitBit[m_TreeId] );
  1752. info.m_nVisitBit[m_TreeId] = (unsigned short)-1;
  1753. m_lock.UnlockWrite();
  1754. if ( bWasReading )
  1755. {
  1756. LockForRead();
  1757. }
  1758. }
  1759. }
  1760. void CVoxelTree::UpdateListMask( SpatialPartitionHandle_t hPartition )
  1761. {
  1762. EntityInfo_t &info = EntityInfo( hPartition );
  1763. int nLevel = info.m_nLevel[GetTreeId()];
  1764. if ( nLevel >= 0 )
  1765. {
  1766. m_lock.LockForRead();
  1767. m_pVoxelHash[nLevel].UpdateListMask( hPartition );
  1768. m_lock.UnlockRead();
  1769. }
  1770. }
  1771. //-----------------------------------------------------------------------------
  1772. // Called when an element moves
  1773. //-----------------------------------------------------------------------------
  1774. void CVoxelTree::ElementMoved( SpatialPartitionHandle_t hPartition, const Vector& mins, const Vector& maxs )
  1775. {
  1776. if ( hPartition != PARTITION_INVALID_HANDLE )
  1777. {
  1778. // If it doesn't already exist in the tree - add it.
  1779. EntityInfo_t &info = EntityInfo( hPartition );
  1780. if ( info.m_iLeafList[GetTreeId()] == CLeafList::InvalidIndex() )
  1781. {
  1782. InsertIntoTree( hPartition, mins, maxs, false );
  1783. return;
  1784. }
  1785. // Re-insert entity into voxel hash.
  1786. InsertIntoTree( hPartition, mins, maxs, true );
  1787. }
  1788. }
  1789. //-----------------------------------------------------------------------------
  1790. // Purpose:
  1791. //-----------------------------------------------------------------------------
  1792. void CVoxelTree::EnumerateElementsInBox( SpatialPartitionListMask_t listMask,
  1793. const Vector& vecMins, const Vector& vecMaxs,
  1794. bool coarseTest, IPartitionEnumerator* pIterator )
  1795. {
  1796. VPROF( "BoxTest/SphereTest" );
  1797. // If this assertion fails, you're using a list at a point where the spatial partition elements aren't set up!
  1798. // Assert( ( listMask & m_nSuppressedListMask ) == 0 );
  1799. // Early-out.
  1800. if ( listMask == 0 )
  1801. return;
  1802. // Clamp bounds to extant space
  1803. Vector mins, maxs;
  1804. VectorMax( vecMins, s_PartitionMin, mins );
  1805. VectorMin( mins, s_PartitionMax, mins );
  1806. VectorMax( vecMaxs, s_PartitionMin, maxs );
  1807. VectorMin( maxs, s_PartitionMax, maxs );
  1808. // Callbacks.
  1809. CPartitionVisits *pPrevVisits = BeginVisit();
  1810. m_lock.LockForRead();
  1811. Voxel_t vs = m_pVoxelHash[0].VoxelIndexFromPoint( mins );
  1812. Voxel_t ve = m_pVoxelHash[0].VoxelIndexFromPoint( maxs );
  1813. if ( !m_pVoxelHash[0].EnumerateElementsInBox( listMask, vs, ve, mins, maxs, pIterator ) )
  1814. {
  1815. m_lock.UnlockRead();
  1816. EndVisit( pPrevVisits );
  1817. return;
  1818. }
  1819. vs = ConvertToNextLevel( vs );
  1820. ve = ConvertToNextLevel( ve );
  1821. if ( !m_pVoxelHash[1].EnumerateElementsInBox( listMask, vs, ve, mins, maxs, pIterator ) )
  1822. {
  1823. m_lock.UnlockRead();
  1824. EndVisit( pPrevVisits );
  1825. return;
  1826. }
  1827. vs = ConvertToNextLevel( vs );
  1828. ve = ConvertToNextLevel( ve );
  1829. if ( !m_pVoxelHash[2].EnumerateElementsInBox( listMask, vs, ve, mins, maxs, pIterator ) )
  1830. {
  1831. m_lock.UnlockRead();
  1832. EndVisit( pPrevVisits );
  1833. return;
  1834. }
  1835. vs = ConvertToNextLevel( vs );
  1836. ve = ConvertToNextLevel( ve );
  1837. m_pVoxelHash[3].EnumerateElementsInBox( listMask, vs, ve, mins, maxs, pIterator );
  1838. m_lock.UnlockRead();
  1839. EndVisit( pPrevVisits );
  1840. }
  1841. //-----------------------------------------------------------------------------
  1842. // Purpose:
  1843. //-----------------------------------------------------------------------------
  1844. void CVoxelTree::EnumerateElementsInSphere( SpatialPartitionListMask_t listMask,
  1845. const Vector& origin, float radius, bool coarseTest, IPartitionEnumerator* pIterator )
  1846. {
  1847. // Otherwise they might as well just walk the entire ent list!!!
  1848. Assert( radius <= MAX_COORD_FLOAT );
  1849. // If the box test is fast enough - forget about the sphere test?
  1850. Vector vecMin( origin.x - radius, origin.y - radius, origin.z - radius );
  1851. Vector vecMax( origin.x + radius, origin.y + radius, origin.z + radius );
  1852. return EnumerateElementsInBox( listMask, vecMin, vecMax, coarseTest, pIterator );
  1853. }
  1854. //-----------------------------------------------------------------------------
  1855. // Purpose:
  1856. //-----------------------------------------------------------------------------
  1857. bool CVoxelTree::EnumerateElementsAlongRay_Ray( SpatialPartitionListMask_t listMask,
  1858. const Ray_t &ray, const Vector &vecInvDelta, const Vector &vecEnd, IPartitionEnumerator *pIterator )
  1859. {
  1860. // Find the voxel start + end
  1861. Voxel_t voxelStart = m_pVoxelHash[0].VoxelIndexFromPoint( ray.m_Start );
  1862. Voxel_t voxelEnd = m_pVoxelHash[0].VoxelIndexFromPoint( vecEnd );
  1863. bool bSingleVoxel = ( voxelStart.uiVoxel == voxelEnd.uiVoxel );
  1864. CIntersectRay intersectRay( this, ray, vecInvDelta );
  1865. // Optimization: Look for single voxel rays
  1866. if ( bSingleVoxel )
  1867. {
  1868. if ( !m_pVoxelHash[0].EnumerateElementsInSingleVoxel( voxelStart, intersectRay, listMask, pIterator ) )
  1869. return false;
  1870. voxelStart = ConvertToNextLevel( voxelStart );
  1871. if ( !m_pVoxelHash[1].EnumerateElementsInSingleVoxel( voxelStart, intersectRay, listMask, pIterator ) )
  1872. return false;
  1873. voxelStart = ConvertToNextLevel( voxelStart );
  1874. if ( !m_pVoxelHash[2].EnumerateElementsInSingleVoxel( voxelStart, intersectRay, listMask, pIterator ) )
  1875. return false;
  1876. voxelStart = ConvertToNextLevel( voxelStart );
  1877. return m_pVoxelHash[3].EnumerateElementsInSingleVoxel( voxelStart, intersectRay, listMask, pIterator );
  1878. }
  1879. Voxel_t voxelCurrent;
  1880. voxelCurrent.uiVoxel = voxelStart.uiVoxel;
  1881. // Setup.
  1882. int nStep[3];
  1883. float tMax[3];
  1884. float tDelta[3];
  1885. m_pVoxelHash[0].LeafListRaySetup( ray, vecEnd, vecInvDelta, voxelStart, nStep, tMax, tDelta );
  1886. // Walk the voxels and visit all elements in each voxel
  1887. // Deal with all levels
  1888. Voxel_t ov1, ov2, ov3;
  1889. ov1.uiVoxel = ov2.uiVoxel = ov3.uiVoxel = 0xFFFFFFFF;
  1890. Voxel_t v1 = ConvertToNextLevel( voxelCurrent );
  1891. Voxel_t v2 = ConvertToNextLevel( v1 );
  1892. Voxel_t v3 = ConvertToNextLevel( v2 );
  1893. while ( 1 )
  1894. {
  1895. if ( !m_pVoxelHash[0].EnumerateElementsInVoxel( voxelCurrent, intersectRay, listMask, pIterator ) )
  1896. return false;
  1897. if ( v1.uiVoxel != ov1.uiVoxel )
  1898. {
  1899. if ( !m_pVoxelHash[1].EnumerateElementsInVoxel( v1, intersectRay, listMask, pIterator ) )
  1900. return false;
  1901. }
  1902. if ( v2.uiVoxel != ov2.uiVoxel )
  1903. {
  1904. if ( !m_pVoxelHash[2].EnumerateElementsInVoxel( v2, intersectRay, listMask, pIterator ) )
  1905. return false;
  1906. }
  1907. if ( v3.uiVoxel != ov3.uiVoxel )
  1908. {
  1909. if ( !m_pVoxelHash[3].EnumerateElementsInVoxel( v3, intersectRay, listMask, pIterator ) )
  1910. return false;
  1911. }
  1912. if ( tMax[0] >= 1.0f && tMax[1] >= 1.0f && tMax[2] >= 1.0f )
  1913. break;
  1914. if ( tMax[0] < tMax[1] )
  1915. {
  1916. if ( tMax[0] < tMax[2] )
  1917. {
  1918. voxelCurrent.bitsVoxel.x += nStep[0];
  1919. tMax[0] += tDelta[0];
  1920. }
  1921. else
  1922. {
  1923. voxelCurrent.bitsVoxel.z += nStep[2];
  1924. tMax[2] += tDelta[2];
  1925. }
  1926. }
  1927. else
  1928. {
  1929. if ( tMax[1] < tMax[2] )
  1930. {
  1931. voxelCurrent.bitsVoxel.y += nStep[1];
  1932. tMax[1] += tDelta[1];
  1933. }
  1934. else
  1935. {
  1936. voxelCurrent.bitsVoxel.z += nStep[2];
  1937. tMax[2] += tDelta[2];
  1938. }
  1939. }
  1940. ov1 = v1; ov2 = v2; ov3 = v3;
  1941. v1 = ConvertToNextLevel( voxelCurrent );
  1942. v2 = ConvertToNextLevel( v1 );
  1943. v3 = ConvertToNextLevel( v2 );
  1944. }
  1945. return true;
  1946. }
  1947. //-----------------------------------------------------------------------------
  1948. // Purpose:
  1949. //-----------------------------------------------------------------------------
  1950. void CVoxelTree::ComputeSweptRayBounds( const Ray_t &ray, const Vector &vecStartMin, const Vector &vecStartMax, Vector *pVecMin, Vector *pVecMax )
  1951. {
  1952. if ( ray.m_Delta.x < 0 )
  1953. {
  1954. pVecMin->x = vecStartMin.x + ray.m_Delta.x;
  1955. pVecMax->x = vecStartMax.x;
  1956. }
  1957. else
  1958. {
  1959. pVecMin->x = vecStartMin.x;
  1960. pVecMax->x = vecStartMax.x + ray.m_Delta.x;
  1961. }
  1962. if ( ray.m_Delta.y < 0 )
  1963. {
  1964. pVecMin->y = vecStartMin.y + ray.m_Delta.y;
  1965. pVecMax->y = vecStartMax.y;
  1966. }
  1967. else
  1968. {
  1969. pVecMin->y = vecStartMin.y;
  1970. pVecMax->y = vecStartMax.y + ray.m_Delta.y;
  1971. }
  1972. if ( ray.m_Delta.z < 0 )
  1973. {
  1974. pVecMin->z = vecStartMin.z + ray.m_Delta.z;
  1975. pVecMax->z = vecStartMax.z;
  1976. }
  1977. else
  1978. {
  1979. pVecMin->z = vecStartMin.z;
  1980. pVecMax->z = vecStartMax.z + ray.m_Delta.z;
  1981. }
  1982. }
  1983. bool CVoxelTree::EnumerateRayStartVoxels( SpatialPartitionListMask_t listMask, IPartitionEnumerator *pIterator, CIntersectSweptBox &intersectSweptBox, int voxelBounds[4][2][3] )
  1984. {
  1985. // Iterate over all voxels that intersect the box around the starting ray point
  1986. int nMinX = voxelBounds[0][0][0];
  1987. int nMinY = voxelBounds[0][0][1];
  1988. int nMinZ = voxelBounds[0][0][2];
  1989. int nMaxX = voxelBounds[0][1][0];
  1990. int nMaxY = voxelBounds[0][1][1];
  1991. int nMaxZ = voxelBounds[0][1][2];
  1992. for ( int i = 0; i < m_nLevelCount; ++i )
  1993. {
  1994. if ( i != 0 )
  1995. {
  1996. nMinX >>= SPHASH_LEVEL_SKIP;
  1997. nMinY >>= SPHASH_LEVEL_SKIP;
  1998. nMinZ >>= SPHASH_LEVEL_SKIP;
  1999. nMaxX >>= SPHASH_LEVEL_SKIP;
  2000. nMaxY >>= SPHASH_LEVEL_SKIP;
  2001. nMaxZ >>= SPHASH_LEVEL_SKIP;
  2002. voxelBounds[i][0][0] = nMinX;
  2003. voxelBounds[i][0][1] = nMinY;
  2004. voxelBounds[i][0][2] = nMinZ;
  2005. voxelBounds[i][1][0] = nMaxX;
  2006. voxelBounds[i][1][1] = nMaxY;
  2007. voxelBounds[i][1][2] = nMaxZ;
  2008. }
  2009. Voxel_t voxel;
  2010. int iX, iY, iZ;
  2011. for ( iX = nMinX; iX <= nMaxX; ++iX )
  2012. {
  2013. voxel.bitsVoxel.x = iX;
  2014. for ( iY = nMinY; iY <= nMaxY; ++iY )
  2015. {
  2016. voxel.bitsVoxel.y = iY;
  2017. for ( iZ = nMinZ; iZ <= nMaxZ; ++iZ )
  2018. {
  2019. voxel.bitsVoxel.z = iZ;
  2020. if ( !m_pVoxelHash[i].EnumerateElementsInVoxel( voxel, intersectSweptBox, listMask, pIterator ) )
  2021. return false;
  2022. }
  2023. }
  2024. }
  2025. }
  2026. return true;
  2027. }
  2028. //-----------------------------------------------------------------------------
  2029. // Purpose:
  2030. //-----------------------------------------------------------------------------
  2031. bool CVoxelTree::EnumerateElementsAlongRay_ExtrudedRay( SpatialPartitionListMask_t listMask,
  2032. const Ray_t &ray, const Vector &vecInvDelta, const Vector &vecEnd, IPartitionEnumerator *pIterator )
  2033. {
  2034. // Check the starting position, then proceed with the sweep.
  2035. Vector vecMin, vecMax;
  2036. VectorSubtract( ray.m_Start, ray.m_Extents, vecMin );
  2037. VectorAdd( ray.m_Start, ray.m_Extents, vecMax );
  2038. // Visit each voxel in the box and enumerate its elements.
  2039. // Indexed as voxelBounds[level][min/max][x/y/z]
  2040. int voxelBounds[4][2][3];
  2041. m_pVoxelHash[0].VoxelIndexFromPoint( vecMin, voxelBounds[0][0] );
  2042. m_pVoxelHash[0].VoxelIndexFromPoint( vecMax, voxelBounds[0][1] );
  2043. CIntersectSweptBox intersectSweptBox( this, ray, vecInvDelta );
  2044. if ( !EnumerateRayStartVoxels( listMask, pIterator, intersectSweptBox, voxelBounds ) )
  2045. return false;
  2046. // Early out: Check to see if the range of voxels at the endpoint
  2047. // is the same as the range at the start point. If so, we're done.
  2048. #if defined(_X360) || defined(_PS3)
  2049. fltx4 fl4RayEnd = LoadUnaligned3SIMD(vecEnd.Base());
  2050. fltx4 fl4Extents = LoadAlignedSIMD(ray.m_Extents.Base());
  2051. fltx4 vecEndMin = SubSIMD( fl4RayEnd, fl4Extents );
  2052. fltx4 vecEndMax = AddSIMD( fl4RayEnd, fl4Extents );
  2053. #else
  2054. Vector vecEndMin, vecEndMax;
  2055. VectorSubtract( vecEnd, ray.m_Extents, vecEndMin );
  2056. VectorAdd( vecEnd, ray.m_Extents, vecEndMax );
  2057. #endif
  2058. int endVoxelMin[3], endVoxelMax[3];
  2059. m_pVoxelHash[0].VoxelIndexFromPoint( vecEndMin, endVoxelMin );
  2060. m_pVoxelHash[0].VoxelIndexFromPoint( vecEndMax, endVoxelMax );
  2061. if ( (endVoxelMin[0] >= voxelBounds[0][0][0]) && (endVoxelMin[1] >= voxelBounds[0][0][1]) && (endVoxelMin[2] >= voxelBounds[0][0][2]) &&
  2062. (endVoxelMax[0] <= voxelBounds[0][1][0]) && (endVoxelMax[1] <= voxelBounds[0][1][1]) && (endVoxelMax[2] <= voxelBounds[0][1][2]) )
  2063. return true;
  2064. // Setup.
  2065. int nStep[3];
  2066. float tMax[3]; // amount of change in t along ray until we hit the next new voxel
  2067. float tMin[3]; // amount of change in t along ray until we leave the last voxel
  2068. float tDelta[3];
  2069. m_pVoxelHash[0].LeafListExtrudedRaySetup( ray, vecInvDelta, vecMin, vecMax, voxelBounds[0][0], voxelBounds[0][1], nStep, tMin, tMax, tDelta );
  2070. int nLastVoxel1[3];
  2071. int nLastVoxel2[3];
  2072. int nLastVoxel3[3];
  2073. for ( int i = 0; i < 3; ++i )
  2074. {
  2075. int nIndex = ( nStep[i] > 0 ) ? 1 : 0;
  2076. nLastVoxel1[i] = voxelBounds[1][nIndex][i];
  2077. nLastVoxel2[i] = voxelBounds[2][nIndex][i];
  2078. nLastVoxel3[i] = voxelBounds[3][nIndex][i];
  2079. }
  2080. // Walk the voxels and create the leaf list.
  2081. int iAxis, iMinAxis;
  2082. while ( tMax[0] < 1.0f || tMax[1] < 1.0f || tMax[2] < 1.0f )
  2083. {
  2084. iAxis = MinIndex( tMax[0], tMax[1], tMax[2] );
  2085. iMinAxis = MinIndex( tMin[0], tMin[1], tMin[2] );
  2086. if ( tMin[iMinAxis] < tMax[iAxis] )
  2087. {
  2088. tMin[iMinAxis] += tDelta[iMinAxis];
  2089. int nIndex = ( nStep[iMinAxis] > 0 ) ? 0 : 1;
  2090. voxelBounds[0][nIndex][iMinAxis] += nStep[iMinAxis];
  2091. voxelBounds[1][nIndex][iMinAxis] = voxelBounds[0][nIndex][iMinAxis] >> SPHASH_LEVEL_SKIP;
  2092. voxelBounds[2][nIndex][iMinAxis] = voxelBounds[0][nIndex][iMinAxis] >> (2 * SPHASH_LEVEL_SKIP);
  2093. voxelBounds[3][nIndex][iMinAxis] = voxelBounds[0][nIndex][iMinAxis] >> (3 * SPHASH_LEVEL_SKIP);
  2094. }
  2095. else
  2096. {
  2097. tMax[iAxis] += tDelta[iAxis];
  2098. int nIndex = ( nStep[iAxis] > 0 ) ? 1 : 0;
  2099. voxelBounds[0][nIndex][iAxis] += nStep[iAxis];
  2100. voxelBounds[1][nIndex][iAxis] = voxelBounds[0][nIndex][iAxis] >> SPHASH_LEVEL_SKIP;
  2101. voxelBounds[2][nIndex][iAxis] = voxelBounds[0][nIndex][iAxis] >> (2 * SPHASH_LEVEL_SKIP);
  2102. voxelBounds[3][nIndex][iAxis] = voxelBounds[0][nIndex][iAxis] >> (3 * SPHASH_LEVEL_SKIP);
  2103. if ( !m_pVoxelHash[0].EnumerateElementsAlongRay_ExtrudedRaySlice( listMask, pIterator, intersectSweptBox, voxelBounds[0][0], voxelBounds[0][1], iAxis, nStep ) )
  2104. return false;
  2105. if ( nLastVoxel1[iAxis] != voxelBounds[1][nIndex][iAxis] )
  2106. {
  2107. nLastVoxel1[iAxis] = voxelBounds[1][nIndex][iAxis];
  2108. if ( !m_pVoxelHash[1].EnumerateElementsAlongRay_ExtrudedRaySlice( listMask, pIterator, intersectSweptBox, voxelBounds[1][0], voxelBounds[1][1], iAxis, nStep ) )
  2109. return false;
  2110. }
  2111. if ( nLastVoxel2[iAxis] != voxelBounds[2][nIndex][iAxis] )
  2112. {
  2113. nLastVoxel2[iAxis] = voxelBounds[2][nIndex][iAxis];
  2114. if ( !m_pVoxelHash[2].EnumerateElementsAlongRay_ExtrudedRaySlice( listMask, pIterator, intersectSweptBox, voxelBounds[2][0], voxelBounds[2][1], iAxis, nStep ) )
  2115. return false;
  2116. }
  2117. if ( nLastVoxel3[iAxis] != voxelBounds[3][nIndex][iAxis] )
  2118. {
  2119. nLastVoxel3[iAxis] = voxelBounds[3][nIndex][iAxis];
  2120. if ( !m_pVoxelHash[3].EnumerateElementsAlongRay_ExtrudedRaySlice( listMask, pIterator, intersectSweptBox, voxelBounds[3][0], voxelBounds[3][1], iAxis, nStep ) )
  2121. return false;
  2122. }
  2123. }
  2124. }
  2125. return true;
  2126. }
  2127. #ifndef _PS3
  2128. #define THINK_TRACE_COUNTER_COMPILE_FUNCTIONS_ENGINE
  2129. #include "engine/thinktracecounter.h"
  2130. #endif
  2131. #ifdef THINK_TRACE_COUNTER_COMPILED
  2132. ConVar think_trace_limit( "think_trace_limit", "0", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "Break into the debugger if this many or more traces are performed in a single think function. Negative numbers mean that the same think function may be broken into many times (once per [x] may traces), positive numbers mean each think will break only once." );
  2133. CTHREADLOCALINT g_DebugTracesRemainingBeforeTrap(0);
  2134. #endif
  2135. //-----------------------------------------------------------------------------
  2136. // Purpose:
  2137. //-----------------------------------------------------------------------------
  2138. void CVoxelTree::EnumerateElementsAlongRay( SpatialPartitionListMask_t listMask,
  2139. const Ray_t &ray, bool coarseTest, IPartitionEnumerator *pIterator )
  2140. {
  2141. VPROF("EnumerateElementsAlongRay");
  2142. #ifdef THINK_TRACE_COUNTER_COMPILED
  2143. if ( DEBUG_THINK_TRACE_COUNTER_ALLOWED() && think_trace_limit.GetInt() != 0 && g_DebugTracesRemainingBeforeTrap > 0 )
  2144. {
  2145. if ( --g_DebugTracesRemainingBeforeTrap <= 0 )
  2146. {
  2147. if ( Plat_IsInDebugSession() )
  2148. {
  2149. DebuggerBreakIfDebugging();
  2150. if ( think_trace_limit.GetInt() < 0 )
  2151. {
  2152. g_DebugTracesRemainingBeforeTrap = -think_trace_limit.GetInt();
  2153. }
  2154. }
  2155. else
  2156. {
  2157. AssertMsg1( false, "Performed %d traces in a single think function!\n", think_trace_limit.GetInt() );
  2158. }
  2159. }
  2160. }
  2161. #endif
  2162. if ( !ray.m_IsSwept )
  2163. {
  2164. Vector vecMin, vecMax;
  2165. VectorSubtract( ray.m_Start, ray.m_Extents, vecMin );
  2166. VectorAdd( ray.m_Start, ray.m_Extents, vecMax );
  2167. return EnumerateElementsInBox( listMask, vecMin, vecMax, coarseTest, pIterator );
  2168. }
  2169. // If this assertion fails, you're using a list at a point where the spatial partition elements aren't set up!
  2170. // Assert( ( listMask & m_nSuppressedListMask ) == 0 );
  2171. // Early-out.
  2172. if ( listMask == 0 )
  2173. return;
  2174. // Calculate the end of the ray
  2175. Vector vecEnd;
  2176. Vector vecInvDelta;
  2177. Ray_t clippedRay = ray;
  2178. VectorAdd( clippedRay.m_Start, clippedRay.m_Delta, vecEnd );
  2179. bool bStartIn = IsPointInBox( ray.m_Start, s_PartitionMin, s_PartitionMax );
  2180. bool bEndIn = IsPointInBox( vecEnd, s_PartitionMin, s_PartitionMax );
  2181. if ( !bStartIn && !bEndIn )
  2182. return;
  2183. // Callbacks.
  2184. if ( !bStartIn )
  2185. {
  2186. ClampStartPoint( clippedRay, vecEnd );
  2187. }
  2188. else if ( !bEndIn )
  2189. {
  2190. ClampEndPoint( clippedRay, vecEnd );
  2191. }
  2192. vecInvDelta[0] = ( clippedRay.m_Delta[0] != 0.0f ) ? 1.0f / clippedRay.m_Delta[0] : FLT_MAX;
  2193. vecInvDelta[1] = ( clippedRay.m_Delta[1] != 0.0f ) ? 1.0f / clippedRay.m_Delta[1] : FLT_MAX;
  2194. vecInvDelta[2] = ( clippedRay.m_Delta[2] != 0.0f ) ? 1.0f / clippedRay.m_Delta[2] : FLT_MAX;
  2195. CPartitionVisits *pPrevVisits = BeginVisit();
  2196. m_lock.LockForRead();
  2197. if ( ray.m_IsRay )
  2198. {
  2199. EnumerateElementsAlongRay_Ray( listMask, clippedRay, vecInvDelta, vecEnd, pIterator );
  2200. }
  2201. else
  2202. {
  2203. EnumerateElementsAlongRay_ExtrudedRay( listMask, clippedRay, vecInvDelta, vecEnd, pIterator );
  2204. }
  2205. m_lock.UnlockRead();
  2206. EndVisit( pPrevVisits );
  2207. }
  2208. //-----------------------------------------------------------------------------
  2209. // Purpose:
  2210. //-----------------------------------------------------------------------------
  2211. void CVoxelTree::EnumerateElementsAtPoint( SpatialPartitionListMask_t listMask,
  2212. const Vector& pt, bool coarseTest, IPartitionEnumerator* pIterator )
  2213. {
  2214. // If this assertion fails, you're using a list at a point where the spatial partition elements aren't set up!
  2215. // Assert( ( listMask & m_nSuppressedListMask ) == 0 );
  2216. // Early-out.
  2217. if ( listMask == 0 )
  2218. return;
  2219. m_lock.LockForRead();
  2220. // Callbacks.
  2221. Voxel_t v = m_pVoxelHash[0].VoxelIndexFromPoint( pt );
  2222. if ( !m_pVoxelHash[0].EnumerateElementsAtPoint( listMask, v, pt, pIterator ) )
  2223. {
  2224. m_lock.UnlockRead();
  2225. return;
  2226. }
  2227. v = ConvertToNextLevel( v );
  2228. if ( !m_pVoxelHash[1].EnumerateElementsAtPoint( listMask, v, pt, pIterator ) )
  2229. {
  2230. m_lock.UnlockRead();
  2231. return;
  2232. }
  2233. v = ConvertToNextLevel( v );
  2234. if ( !m_pVoxelHash[2].EnumerateElementsAtPoint( listMask, v, pt, pIterator ) )
  2235. {
  2236. m_lock.UnlockRead();
  2237. return;
  2238. }
  2239. v = ConvertToNextLevel( v );
  2240. m_pVoxelHash[3].EnumerateElementsAtPoint( listMask, v, pt, pIterator );
  2241. m_lock.UnlockRead();
  2242. }
  2243. //-----------------------------------------------------------------------------
  2244. // Purpose: Debug! Render boxes around objects in tree.
  2245. //-----------------------------------------------------------------------------
  2246. void CVoxelTree::RenderAllObjectsInTree( float flTime )
  2247. {
  2248. MDLCACHE_CRITICAL_SECTION_(g_pMDLCache);
  2249. m_lock.LockForRead();
  2250. for ( int i = 0; i < m_nLevelCount; ++i )
  2251. {
  2252. m_pVoxelHash[i].RenderAllObjectsInTree( flTime );
  2253. }
  2254. m_lock.UnlockRead();
  2255. }
  2256. //-----------------------------------------------------------------------------
  2257. // Purpose:
  2258. //-----------------------------------------------------------------------------
  2259. void CVoxelTree::RenderObjectsInPlayerLeafs( const Vector &vecPlayerMin, const Vector &vecPlayerMax, float flTime )
  2260. {
  2261. MDLCACHE_CRITICAL_SECTION_(g_pMDLCache);
  2262. m_lock.LockForRead();
  2263. for ( int i = 0; i < m_nLevelCount; ++i )
  2264. {
  2265. m_pVoxelHash[i].RenderObjectsInPlayerLeafs( vecPlayerMin, vecPlayerMax, flTime );
  2266. }
  2267. m_lock.UnlockRead();
  2268. }
  2269. //-----------------------------------------------------------------------------
  2270. // Expose CSpatialPartition to the game + client DLL.
  2271. //-----------------------------------------------------------------------------
  2272. static CSpatialPartition g_SpatialPartition;
  2273. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CSpatialPartition, ISpatialPartition, INTERFACEVERSION_SPATIALPARTITION, g_SpatialPartition );
  2274. //-----------------------------------------------------------------------------
  2275. // Expose ISpatialPartitionInternal to the engine.
  2276. //-----------------------------------------------------------------------------
  2277. ISpatialPartitionInternal *SpatialPartition()
  2278. {
  2279. return &g_SpatialPartition;
  2280. }
  2281. //-----------------------------------------------------------------------------
  2282. // Purpose: Constructor
  2283. //-----------------------------------------------------------------------------
  2284. CSpatialPartition::CSpatialPartition()
  2285. {
  2286. m_nQueryCallbackCount = 0;
  2287. m_aHandles.SetAllocOwner( "CSpatialPartition::m_aHandles" );
  2288. }
  2289. CSpatialPartition::~CSpatialPartition()
  2290. {
  2291. Shutdown();
  2292. }
  2293. //-----------------------------------------------------------------------------
  2294. // Purpose:
  2295. // Input: worldmin -
  2296. // worldmax -
  2297. //-----------------------------------------------------------------------------
  2298. void CSpatialPartition::Init( const Vector &worldmin, const Vector &worldmax )
  2299. {
  2300. // Clear the handle list and ensure some new memory.
  2301. MEM_ALLOC_CREDIT();
  2302. m_aHandles.Purge();
  2303. m_aHandles.EnsureCapacity( SPHASH_HANDLELIST_BLOCK );
  2304. for ( int i = 0; i < NUM_TREES; i++ )
  2305. {
  2306. m_VoxelTrees[i].Init( this, i, worldmin, worldmax );
  2307. }
  2308. }
  2309. //-----------------------------------------------------------------------------
  2310. // Purpose:
  2311. //-----------------------------------------------------------------------------
  2312. void CSpatialPartition::Shutdown( void )
  2313. {
  2314. for ( int i = 0; i < NUM_TREES; i++ )
  2315. {
  2316. m_VoxelTrees[i].Shutdown();
  2317. }
  2318. m_aHandles.Purge();
  2319. }
  2320. //-----------------------------------------------------------------------------
  2321. // Purpose: Add a callback to the query callback list. Functions get called
  2322. // right before a query occurs.
  2323. // Input: pCallback - pointer to the callback function to add
  2324. //-----------------------------------------------------------------------------
  2325. void CSpatialPartition::InstallQueryCallback( IPartitionQueryCallback *pCallback )
  2326. {
  2327. // Verify data.
  2328. Assert( pCallback && m_nQueryCallbackCount < MAX_QUERY_CALLBACK );
  2329. if ( !pCallback || ( m_nQueryCallbackCount >= MAX_QUERY_CALLBACK ) )
  2330. return;
  2331. m_pQueryCallback[m_nQueryCallbackCount] = pCallback;
  2332. ++m_nQueryCallbackCount;
  2333. }
  2334. //-----------------------------------------------------------------------------
  2335. // Purpose: Remove a callback from the query callback list.
  2336. // Input: pCallback - pointer to the callback function to remove
  2337. //-----------------------------------------------------------------------------
  2338. void CSpatialPartition::RemoveQueryCallback( IPartitionQueryCallback *pCallback )
  2339. {
  2340. // Verify data.
  2341. if ( !pCallback )
  2342. return;
  2343. for ( int iQuery = m_nQueryCallbackCount; --iQuery >= 0; )
  2344. {
  2345. if ( m_pQueryCallback[iQuery] == pCallback )
  2346. {
  2347. --m_nQueryCallbackCount;
  2348. m_pQueryCallback[iQuery] = m_pQueryCallback[m_nQueryCallbackCount];
  2349. return;
  2350. }
  2351. }
  2352. }
  2353. //-----------------------------------------------------------------------------
  2354. // Purpose: Invokes the pre-query callbacks.
  2355. //-----------------------------------------------------------------------------
  2356. void CSpatialPartition::InvokeQueryCallbacks( SpatialPartitionListMask_t listMask, bool bDone )
  2357. {
  2358. for ( int iQuery = 0; iQuery < m_nQueryCallbackCount; ++iQuery )
  2359. {
  2360. if ( !bDone )
  2361. {
  2362. m_pQueryCallback[iQuery]->OnPreQuery( listMask );
  2363. }
  2364. else
  2365. {
  2366. m_pQueryCallback[iQuery]->OnPostQuery( listMask );
  2367. }
  2368. }
  2369. }
  2370. //-----------------------------------------------------------------------------
  2371. // Purpose: Create spatial partition object handle.
  2372. // Input: pHandleEntity - entity handle of the object to create a spatial partition handle for
  2373. //-----------------------------------------------------------------------------
  2374. SpatialPartitionHandle_t CSpatialPartition::CreateHandle( IHandleEntity *pHandleEntity )
  2375. {
  2376. m_HandlesMutex.Lock();
  2377. SpatialPartitionHandle_t hPartition = m_aHandles.AddToTail();
  2378. m_HandlesMutex.Unlock();
  2379. m_aHandles[hPartition].m_pHandleEntity = pHandleEntity;
  2380. m_aHandles[hPartition].m_vecMin.Init( FLT_MAX, FLT_MAX, FLT_MAX );
  2381. m_aHandles[hPartition].m_vecMax.Init( FLT_MIN, FLT_MIN, FLT_MIN );
  2382. m_aHandles[hPartition].m_fList = 0;
  2383. m_aHandles[hPartition].m_flags = 0;
  2384. for ( int i = 0; i < NUM_TREES; i++ )
  2385. {
  2386. m_aHandles[hPartition].m_nVisitBit[i] = 0xffff;
  2387. m_aHandles[hPartition].m_nLevel[i] = (uint8)-1;
  2388. m_aHandles[hPartition].m_iLeafList[i] = CLeafList::InvalidIndex();
  2389. }
  2390. return hPartition;
  2391. }
  2392. //-----------------------------------------------------------------------------
  2393. // Purpose: Destroy spatial partition object handle.
  2394. // Input: handle - handle of the spatial partition object handle to destroy
  2395. //-----------------------------------------------------------------------------
  2396. void CSpatialPartition::DestroyHandle( SpatialPartitionHandle_t hPartition )
  2397. {
  2398. if ( hPartition != PARTITION_INVALID_HANDLE )
  2399. {
  2400. RemoveFromTree( hPartition );
  2401. m_HandlesMutex.Lock();
  2402. // memset( &m_aHandles[hPartition], 0xcd, sizeof(EntityInfo_t) );
  2403. m_aHandles.Remove( hPartition );
  2404. m_HandlesMutex.Unlock();
  2405. }
  2406. }
  2407. //-----------------------------------------------------------------------------
  2408. // Purpose: Create spatial partition object handle and insert it into the tree.
  2409. // Input: pHandleEntity - entity handle of the object to create a spatial partition handle for
  2410. // listMask -
  2411. // mins -
  2412. // maxs -
  2413. //-----------------------------------------------------------------------------
  2414. SpatialPartitionHandle_t CSpatialPartition::CreateHandle( IHandleEntity *pHandleEntity,
  2415. SpatialPartitionListMask_t listMask,
  2416. const Vector &mins, const Vector &maxs )
  2417. {
  2418. // CDebugOverlay::AddBoxOverlay( vec3_origin, mins, maxs, vec3_angle, 0, 255, 0, 75, 3600 );
  2419. SpatialPartitionHandle_t hPartition = CreateHandle( pHandleEntity );
  2420. Insert( listMask, hPartition );
  2421. InsertIntoTree( hPartition, mins, maxs );
  2422. return hPartition;
  2423. }
  2424. void CSpatialPartition::UpdateListMask( SpatialPartitionHandle_t hPartition, uint16 nListMask )
  2425. {
  2426. EntityInfo_t &entityInfo = EntityInfo( hPartition );
  2427. if ( entityInfo.m_fList != nListMask )
  2428. {
  2429. entityInfo.m_fList = nListMask;
  2430. if ( entityInfo.m_flags & IN_CLIENT_TREE )
  2431. {
  2432. m_VoxelTrees[CLIENT_TREE].UpdateListMask( hPartition );
  2433. }
  2434. if ( entityInfo.m_flags & IN_SERVER_TREE )
  2435. {
  2436. m_VoxelTrees[SERVER_TREE].UpdateListMask( hPartition );
  2437. }
  2438. }
  2439. }
  2440. //-----------------------------------------------------------------------------
  2441. // Purpose: Insert object handle into group(s).
  2442. // Input: listId - list(s) to insert the object handle into
  2443. // handle - object handle to be inserted into list
  2444. //-----------------------------------------------------------------------------
  2445. void CSpatialPartition::Insert( SpatialPartitionListMask_t listId, SpatialPartitionHandle_t handle )
  2446. {
  2447. Assert( m_aHandles.IsValidIndex( handle ) );
  2448. Assert( listId <= USHRT_MAX );
  2449. UpdateListMask( handle, m_aHandles[handle].m_fList | listId );
  2450. }
  2451. //-----------------------------------------------------------------------------
  2452. // Purpose: Remove object handle from group(s).
  2453. // Input: listId - list(s) to remove the object handle from
  2454. // handle - object handle to be removed from list
  2455. //-----------------------------------------------------------------------------
  2456. void CSpatialPartition::Remove( SpatialPartitionListMask_t listId, SpatialPartitionHandle_t handle )
  2457. {
  2458. Assert( m_aHandles.IsValidIndex( handle ) );
  2459. Assert( listId <= USHRT_MAX );
  2460. UpdateListMask( handle, m_aHandles[handle].m_fList & ~listId );
  2461. }
  2462. //-----------------------------------------------------------------------------
  2463. // Purpose:
  2464. //-----------------------------------------------------------------------------
  2465. void CSpatialPartition::RemoveAndInsert( SpatialPartitionListMask_t removeMask, SpatialPartitionListMask_t insertMask,
  2466. SpatialPartitionHandle_t handle )
  2467. {
  2468. Assert( m_aHandles.IsValidIndex( handle ) );
  2469. Assert( removeMask <= USHRT_MAX );
  2470. Assert( insertMask <= USHRT_MAX );
  2471. uint16 nOriginalListMask = m_aHandles[handle].m_fList;
  2472. uint16 nListMask = (nOriginalListMask & ~removeMask) | insertMask;
  2473. UpdateListMask( handle, nListMask );
  2474. }
  2475. //-----------------------------------------------------------------------------
  2476. // Purpose: Remove object handle from all groups.
  2477. // Input: handle - object handle to be removed from all lists
  2478. //-----------------------------------------------------------------------------
  2479. void CSpatialPartition::Remove( SpatialPartitionHandle_t handle )
  2480. {
  2481. Assert( m_aHandles.IsValidIndex( handle ) );
  2482. UpdateListMask( handle, 0 );
  2483. }
  2484. //-----------------------------------------------------------------------------
  2485. // Purpose: Fast way to re-add (set) a group that was removed (and saved) via the
  2486. // HideElement call.
  2487. //-----------------------------------------------------------------------------
  2488. void CSpatialPartition::UnhideElement( SpatialPartitionHandle_t handle, SpatialTempHandle_t tempHandle )
  2489. {
  2490. Assert( m_aHandles.IsValidIndex( handle ) );
  2491. m_HandlesMutex.Lock();
  2492. m_aHandles[handle].m_flags &= ~ENTITY_HIDDEN;
  2493. m_HandlesMutex.Unlock();
  2494. }
  2495. //-----------------------------------------------------------------------------
  2496. // Purpose: Remove handle quickly saving the old list data, to be restored later
  2497. // via the UnhideElement call.
  2498. //-----------------------------------------------------------------------------
  2499. SpatialTempHandle_t CSpatialPartition::HideElement( SpatialPartitionHandle_t handle )
  2500. {
  2501. Assert( m_aHandles.IsValidIndex( handle ) );
  2502. m_HandlesMutex.Lock();
  2503. m_aHandles[handle].m_flags |= ENTITY_HIDDEN;
  2504. m_HandlesMutex.Unlock();
  2505. return 1;
  2506. }
  2507. //-----------------------------------------------------------------------------
  2508. // Purpose: (Debugging) Suppress queries on particular lists.
  2509. // Input: nListMask - lists to suppress/unsuppress
  2510. // bSuppress - (true/false) suppress/unsuppress
  2511. //-----------------------------------------------------------------------------
  2512. void CSpatialPartition::SuppressLists( SpatialPartitionListMask_t nListMask, bool bSuppress )
  2513. {
  2514. if ( bSuppress )
  2515. {
  2516. m_nSuppressedListMask |= nListMask;
  2517. }
  2518. else
  2519. {
  2520. m_nSuppressedListMask &= ~nListMask;
  2521. }
  2522. }
  2523. //-----------------------------------------------------------------------------
  2524. // Purpose: (Debugging) Get the suppression list.
  2525. // Output: spatial partition suppression list
  2526. //-----------------------------------------------------------------------------
  2527. SpatialPartitionListMask_t CSpatialPartition::GetSuppressedLists( void )
  2528. {
  2529. return m_nSuppressedListMask;
  2530. }
  2531. //-----------------------------------------------------------------------------
  2532. // Purpose:
  2533. //-----------------------------------------------------------------------------
  2534. void CSpatialPartition::ElementMoved( SpatialPartitionHandle_t handle, const Vector& mins, const Vector& maxs )
  2535. {
  2536. EntityInfo_t &entityInfo = EntityInfo( handle );
  2537. SpatialPartitionListMask_t listMask = entityInfo.m_fList;
  2538. if ( CLIENT_TREE != SERVER_TREE )
  2539. {
  2540. if ( listMask & PARTITION_ALL_CLIENT_EDICTS )
  2541. {
  2542. m_VoxelTrees[CLIENT_TREE].ElementMoved( handle, mins, maxs );
  2543. entityInfo.m_flags |= IN_CLIENT_TREE;
  2544. }
  2545. if ( listMask & ~PARTITION_ALL_CLIENT_EDICTS )
  2546. {
  2547. m_VoxelTrees[SERVER_TREE].ElementMoved( handle, mins, maxs );
  2548. entityInfo.m_flags |= IN_SERVER_TREE;
  2549. }
  2550. }
  2551. else
  2552. {
  2553. m_VoxelTrees[CLIENT_TREE].ElementMoved( handle, mins, maxs );
  2554. entityInfo.m_flags |= IN_CLIENT_TREE;
  2555. }
  2556. }
  2557. //-----------------------------------------------------------------------------
  2558. // Purpose:
  2559. //-----------------------------------------------------------------------------
  2560. void CSpatialPartition::EnumerateElementsInBox( SpatialPartitionListMask_t listMask, const Vector& mins, const Vector& maxs, bool coarseTest, IPartitionEnumerator* pIterator )
  2561. {
  2562. MDLCACHE_CRITICAL_SECTION_(g_pMDLCache);
  2563. CVoxelTree *pTree = VoxelTree( listMask );
  2564. InvokeQueryCallbacks( listMask );
  2565. pTree->EnumerateElementsInBox( listMask, mins, maxs, coarseTest, pIterator );
  2566. InvokeQueryCallbacks( listMask, true );
  2567. }
  2568. //-----------------------------------------------------------------------------
  2569. // Purpose:
  2570. //-----------------------------------------------------------------------------
  2571. void CSpatialPartition::EnumerateElementsInSphere( SpatialPartitionListMask_t listMask, const Vector& origin, float radius, bool coarseTest, IPartitionEnumerator* pIterator )
  2572. {
  2573. MDLCACHE_CRITICAL_SECTION_(g_pMDLCache);
  2574. CVoxelTree *pTree = VoxelTree( listMask );
  2575. InvokeQueryCallbacks( listMask );
  2576. pTree->EnumerateElementsInSphere( listMask, origin, radius, coarseTest, pIterator );
  2577. InvokeQueryCallbacks( listMask, true );
  2578. }
  2579. //-----------------------------------------------------------------------------
  2580. // Purpose:
  2581. //-----------------------------------------------------------------------------
  2582. void CSpatialPartition::EnumerateElementsAlongRay( SpatialPartitionListMask_t listMask, const Ray_t& ray, bool coarseTest, IPartitionEnumerator* pIterator )
  2583. {
  2584. MDLCACHE_CRITICAL_SECTION_(g_pMDLCache);
  2585. CVoxelTree *pTree = VoxelTree( listMask );
  2586. InvokeQueryCallbacks( listMask );
  2587. pTree->EnumerateElementsAlongRay( listMask, ray, coarseTest, pIterator );
  2588. InvokeQueryCallbacks( listMask, true );
  2589. }
  2590. //-----------------------------------------------------------------------------
  2591. // Purpose:
  2592. //-----------------------------------------------------------------------------
  2593. void CSpatialPartition::EnumerateElementsAtPoint( SpatialPartitionListMask_t listMask, const Vector& pt, bool coarseTest, IPartitionEnumerator* pIterator )
  2594. {
  2595. MDLCACHE_CRITICAL_SECTION_(g_pMDLCache);
  2596. CVoxelTree *pTree = VoxelTree( listMask );
  2597. InvokeQueryCallbacks( listMask );
  2598. pTree->EnumerateElementsAtPoint( listMask, pt, coarseTest, pIterator );
  2599. InvokeQueryCallbacks( listMask, true );
  2600. }
  2601. //-----------------------------------------------------------------------------
  2602. // Purpose:
  2603. //-----------------------------------------------------------------------------
  2604. void CSpatialPartition::InsertIntoTree( SpatialPartitionHandle_t hPartition, const Vector& mins, const Vector& maxs )
  2605. {
  2606. EntityInfo_t &entityInfo = EntityInfo( hPartition );
  2607. SpatialPartitionListMask_t listMask = entityInfo.m_fList;
  2608. if ( CLIENT_TREE != SERVER_TREE )
  2609. {
  2610. if ( ( listMask & PARTITION_ALL_CLIENT_EDICTS ) && !( entityInfo.m_flags & IN_CLIENT_TREE ) )
  2611. {
  2612. m_VoxelTrees[CLIENT_TREE].InsertIntoTree( hPartition, mins, maxs, false );
  2613. entityInfo.m_flags |= IN_CLIENT_TREE;
  2614. }
  2615. if ( ( listMask & ~PARTITION_ALL_CLIENT_EDICTS ) && !( entityInfo.m_flags & IN_SERVER_TREE ) )
  2616. {
  2617. m_VoxelTrees[SERVER_TREE].InsertIntoTree( hPartition, mins, maxs, false );
  2618. entityInfo.m_flags |= IN_SERVER_TREE;
  2619. }
  2620. }
  2621. else if ( !( entityInfo.m_flags & IN_CLIENT_TREE ) )
  2622. {
  2623. m_VoxelTrees[CLIENT_TREE].InsertIntoTree( hPartition, mins, maxs, false );
  2624. entityInfo.m_flags |= IN_CLIENT_TREE;
  2625. }
  2626. }
  2627. //-----------------------------------------------------------------------------
  2628. // Purpose:
  2629. //-----------------------------------------------------------------------------
  2630. void CSpatialPartition::RemoveFromTree( SpatialPartitionHandle_t hPartition )
  2631. {
  2632. EntityInfo_t &entityInfo = EntityInfo( hPartition );
  2633. if ( entityInfo.m_flags & IN_CLIENT_TREE )
  2634. {
  2635. m_VoxelTrees[CLIENT_TREE].RemoveFromTree( hPartition );
  2636. entityInfo.m_flags &= ~IN_CLIENT_TREE;
  2637. }
  2638. if ( entityInfo.m_flags & IN_SERVER_TREE )
  2639. {
  2640. m_VoxelTrees[SERVER_TREE].RemoveFromTree( hPartition );
  2641. entityInfo.m_flags &= ~IN_SERVER_TREE;
  2642. }
  2643. }
  2644. //-----------------------------------------------------------------------------
  2645. // Purpose:
  2646. //-----------------------------------------------------------------------------
  2647. void CSpatialPartition::RenderObjectsInBox( const Vector &vecMin, const Vector &vecMax, float flTime )
  2648. {
  2649. }
  2650. //-----------------------------------------------------------------------------
  2651. // Purpose:
  2652. //-----------------------------------------------------------------------------
  2653. void CSpatialPartition::RenderObjectsInSphere( const Vector &vecCenter, float flRadius, float flTime )
  2654. {
  2655. }
  2656. void CSpatialPartition::RenderObjectsAlongRay( const Ray_t& ray, float flTime )
  2657. {
  2658. }
  2659. //-----------------------------------------------------------------------------
  2660. // Report stats
  2661. //-----------------------------------------------------------------------------
  2662. void CSpatialPartition::RenderAllObjectsInTree( float flTime )
  2663. {
  2664. for ( int i = 0; i < NUM_TREES; i++ )
  2665. {
  2666. m_VoxelTrees[i].RenderAllObjectsInTree( flTime );
  2667. }
  2668. }
  2669. void CSpatialPartition::RenderObjectsInPlayerLeafs( const Vector &vecPlayerMin, const Vector &vecPlayerMax, float flTime )
  2670. {
  2671. for ( int i = 0; i < NUM_TREES; i++ )
  2672. {
  2673. m_VoxelTrees[i].RenderObjectsInPlayerLeafs( vecPlayerMin, vecPlayerMax, flTime );
  2674. }
  2675. }
  2676. //-----------------------------------------------------------------------------
  2677. // Report stats
  2678. //-----------------------------------------------------------------------------
  2679. void CVoxelTree::ReportStats( const char *pFileName )
  2680. {
  2681. Msg( "Histogram : Entities per level\n" );
  2682. for ( int i = 0; i < m_nLevelCount; ++i )
  2683. {
  2684. Msg( "\t%d - %d\n", i, m_pVoxelHash[i].EntityCount() );
  2685. }
  2686. }
  2687. void CSpatialPartition::ReportStats( const char *pFileName )
  2688. {
  2689. Msg( "Handle Count %d (%d bytes)\n", m_aHandles.Count(), m_aHandles.Count() * ( sizeof(EntityInfo_t) + 2 * sizeof(SpatialPartitionHandle_t) ) );
  2690. for ( int i = 0; i < NUM_TREES; i++ )
  2691. {
  2692. m_VoxelTrees[i].ReportStats( pFileName );
  2693. }
  2694. }
  2695. static ConVar r_partition_level( "r_partition_level", "-1", FCVAR_CHEAT, "Displays a particular level of the spatial partition system. Use -1 to disable it." );
  2696. void CVoxelTree::DrawDebugOverlays()
  2697. {
  2698. int nLevel = r_partition_level.GetInt();
  2699. if ( nLevel < 0 )
  2700. return;
  2701. m_lock.LockForRead();
  2702. for ( int i = 0; i < m_nLevelCount; ++i )
  2703. {
  2704. if ( ( nLevel >= 0 ) && ( nLevel != i ) )
  2705. continue;
  2706. m_pVoxelHash[i].RenderGrid();
  2707. m_pVoxelHash[i].RenderAllObjectsInTree( 0.01f );
  2708. }
  2709. m_lock.UnlockRead();
  2710. }
  2711. void CSpatialPartition::DrawDebugOverlays()
  2712. {
  2713. for ( int i = 0; i < NUM_TREES; i++ )
  2714. {
  2715. m_VoxelTrees[i].DrawDebugOverlays();
  2716. }
  2717. }
  2718. //=============================================================================
  2719. ISpatialPartition *CreateSpatialPartition( const Vector& worldmin, const Vector& worldmax )
  2720. {
  2721. CSpatialPartition *pResult = new CSpatialPartition;
  2722. pResult->Init( worldmin, worldmax );
  2723. return pResult;
  2724. }
  2725. void DestroySpatialPartition( ISpatialPartition *pPartition )
  2726. {
  2727. Assert( pPartition != (ISpatialPartition*)&g_SpatialPartition );
  2728. delete pPartition;
  2729. }