Team Fortress 2 Source Code as on 22/4/2020
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.

352 lines
11 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $Revision: $
  6. // $NoKeywords: $
  7. //
  8. // The BSP tree leaf data system
  9. //
  10. //=============================================================================//
  11. #include "basetypes.h"
  12. #include "bsptreedata.h"
  13. #include "utllinkedlist.h"
  14. #include "utlvector.h"
  15. #include "tier0/dbg.h"
  16. #include "tier0/memdbgon.h"
  17. //-----------------------------------------------------------------------------
  18. // The BSP tree leaf data system
  19. //-----------------------------------------------------------------------------
  20. class CBSPTreeData : public IBSPTreeData, public ISpatialLeafEnumerator
  21. {
  22. public:
  23. // constructor, destructor
  24. CBSPTreeData();
  25. virtual ~CBSPTreeData();
  26. // Methods of IBSPTreeData
  27. void Init( ISpatialQuery* pBSPTree );
  28. void Shutdown();
  29. BSPTreeDataHandle_t Insert( int userId, Vector const& mins, Vector const& maxs );
  30. void Remove( BSPTreeDataHandle_t handle );
  31. void ElementMoved( BSPTreeDataHandle_t handle, Vector const& mins, Vector const& maxs );
  32. // Enumerate elements in a particular leaf
  33. bool EnumerateElementsInLeaf( int leaf, IBSPTreeDataEnumerator* pEnum, int context );
  34. // For convenience, enumerates the leaves along a ray, box, etc.
  35. bool EnumerateLeavesAtPoint( Vector const& pt, ISpatialLeafEnumerator* pEnum, int context );
  36. bool EnumerateLeavesInBox( Vector const& mins, Vector const& maxs, ISpatialLeafEnumerator* pEnum, int context );
  37. bool EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, int context );
  38. bool EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context );
  39. // methods of IBSPLeafEnumerator
  40. bool EnumerateLeaf( int leaf, int context );
  41. // Is the element in any leaves at all?
  42. bool IsElementInTree( BSPTreeDataHandle_t handle ) const;
  43. private:
  44. // Creates a new handle
  45. BSPTreeDataHandle_t NewHandle( int userId );
  46. // Adds a handle to the list of handles
  47. void AddHandleToLeaf( int leaf, BSPTreeDataHandle_t handle );
  48. // insert, remove handles from leaves
  49. void InsertIntoTree( BSPTreeDataHandle_t handle, Vector const& mins, Vector const& maxs );
  50. void RemoveFromTree( BSPTreeDataHandle_t handle );
  51. // Returns the number of elements in a leaf
  52. int CountElementsInLeaf( int leaf );
  53. private:
  54. // All the information associated with a particular handle
  55. struct HandleInfo_t
  56. {
  57. int m_UserId; // Client-defined id
  58. unsigned short m_LeafList; // What leafs is it in?
  59. };
  60. // The leaf contains an index into a list of elements
  61. struct Leaf_t
  62. {
  63. unsigned short m_FirstElement;
  64. };
  65. // The handle knows about the leaves it lies in
  66. struct HandleInLeaf_t
  67. {
  68. int m_Leaf; // what leaf is the handle in?
  69. unsigned short m_LeafElementIndex; // what's the m_LeafElements index of the entry?
  70. };
  71. // Stores data associated with each leaf.
  72. CUtlVector< Leaf_t > m_Leaf;
  73. // Stores all unique handles
  74. CUtlLinkedList< HandleInfo_t, unsigned short > m_Handles;
  75. // Maintains the list of all handles in a particular leaf
  76. CUtlLinkedList< BSPTreeDataHandle_t, unsigned short, true > m_LeafElements;
  77. // Maintains the list of all leaves a particular handle spans
  78. CUtlLinkedList< HandleInLeaf_t, unsigned short, true > m_HandleLeafList;
  79. // Interface to BSP tree
  80. ISpatialQuery* m_pBSPTree;
  81. };
  82. //-----------------------------------------------------------------------------
  83. // Class factory
  84. //-----------------------------------------------------------------------------
  85. IBSPTreeData* CreateBSPTreeData()
  86. {
  87. return new CBSPTreeData;
  88. }
  89. void DestroyBSPTreeData( IBSPTreeData* pTreeData )
  90. {
  91. if (pTreeData)
  92. delete pTreeData;
  93. }
  94. //-----------------------------------------------------------------------------
  95. // constructor, destructor
  96. //-----------------------------------------------------------------------------
  97. CBSPTreeData::CBSPTreeData()
  98. {
  99. }
  100. CBSPTreeData::~CBSPTreeData()
  101. {
  102. }
  103. //-----------------------------------------------------------------------------
  104. // Level init, shutdown
  105. //-----------------------------------------------------------------------------
  106. void CBSPTreeData::Init( ISpatialQuery* pBSPTree )
  107. {
  108. Assert( pBSPTree );
  109. m_pBSPTree = pBSPTree;
  110. m_Handles.EnsureCapacity( 1024 );
  111. m_LeafElements.EnsureCapacity( 1024 );
  112. m_HandleLeafList.EnsureCapacity( 1024 );
  113. // Add all the leaves we'll need
  114. int leafCount = m_pBSPTree->LeafCount();
  115. m_Leaf.EnsureCapacity( leafCount );
  116. Leaf_t newLeaf;
  117. newLeaf.m_FirstElement = m_LeafElements.InvalidIndex();
  118. while ( --leafCount >= 0 )
  119. {
  120. m_Leaf.AddToTail( newLeaf );
  121. }
  122. }
  123. void CBSPTreeData::Shutdown()
  124. {
  125. m_Handles.Purge();
  126. m_LeafElements.Purge();
  127. m_HandleLeafList.Purge();
  128. m_Leaf.Purge();
  129. }
  130. //-----------------------------------------------------------------------------
  131. // Creates a new handle
  132. //-----------------------------------------------------------------------------
  133. BSPTreeDataHandle_t CBSPTreeData::NewHandle( int userId )
  134. {
  135. BSPTreeDataHandle_t handle = m_Handles.AddToTail();
  136. m_Handles[handle].m_UserId = userId;
  137. m_Handles[handle].m_LeafList = m_HandleLeafList.InvalidIndex();
  138. return handle;
  139. }
  140. //-----------------------------------------------------------------------------
  141. // Add/remove handle
  142. //-----------------------------------------------------------------------------
  143. BSPTreeDataHandle_t CBSPTreeData::Insert( int userId, Vector const& mins, Vector const& maxs )
  144. {
  145. BSPTreeDataHandle_t handle = NewHandle( userId );
  146. InsertIntoTree( handle, mins, maxs );
  147. return handle;
  148. }
  149. void CBSPTreeData::Remove( BSPTreeDataHandle_t handle )
  150. {
  151. if (!m_Handles.IsValidIndex(handle))
  152. return;
  153. RemoveFromTree( handle );
  154. m_Handles.Free( handle );
  155. }
  156. //-----------------------------------------------------------------------------
  157. // Adds a handle to a leaf
  158. //-----------------------------------------------------------------------------
  159. void CBSPTreeData::AddHandleToLeaf( int leaf, BSPTreeDataHandle_t handle )
  160. {
  161. // Got to a leaf baby! Add the handle to the leaf's list of elements
  162. unsigned short leafElement = m_LeafElements.Alloc( true );
  163. if (m_Leaf[leaf].m_FirstElement != m_LeafElements.InvalidIndex() )
  164. m_LeafElements.LinkBefore( m_Leaf[leaf].m_FirstElement, leafElement );
  165. m_Leaf[leaf].m_FirstElement = leafElement;
  166. m_LeafElements[leafElement] = handle;
  167. // Insert the leaf into the handles's list of leaves
  168. unsigned short handleElement = m_HandleLeafList.Alloc( true );
  169. if (m_Handles[handle].m_LeafList != m_HandleLeafList.InvalidIndex() )
  170. m_HandleLeafList.LinkBefore( m_Handles[handle].m_LeafList, handleElement );
  171. m_Handles[handle].m_LeafList = handleElement;
  172. m_HandleLeafList[handleElement].m_Leaf = leaf;
  173. m_HandleLeafList[handleElement].m_LeafElementIndex = leafElement;
  174. }
  175. //-----------------------------------------------------------------------------
  176. // Inserts an element into the tree
  177. //-----------------------------------------------------------------------------
  178. bool CBSPTreeData::EnumerateLeaf( int leaf, int context )
  179. {
  180. BSPTreeDataHandle_t handle = (BSPTreeDataHandle_t)context;
  181. AddHandleToLeaf( leaf, handle );
  182. return true;
  183. }
  184. void CBSPTreeData::InsertIntoTree( BSPTreeDataHandle_t handle, Vector const& mins, Vector const& maxs )
  185. {
  186. m_pBSPTree->EnumerateLeavesInBox( mins, maxs, this, handle );
  187. }
  188. //-----------------------------------------------------------------------------
  189. // Removes an element from the tree
  190. //-----------------------------------------------------------------------------
  191. void CBSPTreeData::RemoveFromTree( BSPTreeDataHandle_t handle )
  192. {
  193. // Iterate over the list of all leaves the handle is in
  194. unsigned short i = m_Handles[handle].m_LeafList;
  195. while (i != m_HandleLeafList.InvalidIndex())
  196. {
  197. int leaf = m_HandleLeafList[i].m_Leaf;
  198. unsigned short leafElement = m_HandleLeafList[i].m_LeafElementIndex;
  199. // Unhook the handle from the leaf handle list
  200. if (leafElement == m_Leaf[leaf].m_FirstElement)
  201. m_Leaf[leaf].m_FirstElement = m_LeafElements.Next(leafElement);
  202. m_LeafElements.Free(leafElement);
  203. unsigned short prevNode = i;
  204. i = m_HandleLeafList.Next(i);
  205. m_HandleLeafList.Free(prevNode);
  206. }
  207. m_Handles[handle].m_LeafList = m_HandleLeafList.InvalidIndex();
  208. }
  209. //-----------------------------------------------------------------------------
  210. // Call this when the element moves
  211. //-----------------------------------------------------------------------------
  212. void CBSPTreeData::ElementMoved( BSPTreeDataHandle_t handle, Vector const& mins, Vector const& maxs )
  213. {
  214. if (handle != TREEDATA_INVALID_HANDLE)
  215. {
  216. RemoveFromTree( handle );
  217. InsertIntoTree( handle, mins, maxs );
  218. }
  219. }
  220. //-----------------------------------------------------------------------------
  221. // Is the element in any leaves at all?
  222. //-----------------------------------------------------------------------------
  223. bool CBSPTreeData::IsElementInTree( BSPTreeDataHandle_t handle ) const
  224. {
  225. return m_Handles[handle].m_LeafList != m_HandleLeafList.InvalidIndex();
  226. }
  227. //-----------------------------------------------------------------------------
  228. // Enumerate elements in a particular leaf
  229. //-----------------------------------------------------------------------------
  230. int CBSPTreeData::CountElementsInLeaf( int leaf )
  231. {
  232. int i;
  233. int nCount = 0;
  234. for( i = m_Leaf[leaf].m_FirstElement; i != m_LeafElements.InvalidIndex(); i = m_LeafElements.Next(i) )
  235. {
  236. ++nCount;
  237. }
  238. return nCount;
  239. }
  240. //-----------------------------------------------------------------------------
  241. // Enumerate elements in a particular leaf
  242. //-----------------------------------------------------------------------------
  243. bool CBSPTreeData::EnumerateElementsInLeaf( int leaf, IBSPTreeDataEnumerator* pEnum, int context )
  244. {
  245. #ifdef DBGFLAG_ASSERT
  246. // The enumeration method better damn well not change this list...
  247. int nCount = CountElementsInLeaf(leaf);
  248. #endif
  249. unsigned short idx = m_Leaf[leaf].m_FirstElement;
  250. while (idx != m_LeafElements.InvalidIndex())
  251. {
  252. BSPTreeDataHandle_t handle = m_LeafElements[idx];
  253. if (!pEnum->EnumerateElement( m_Handles[handle].m_UserId, context ))
  254. {
  255. Assert( CountElementsInLeaf(leaf) == nCount );
  256. return false;
  257. }
  258. idx = m_LeafElements.Next(idx);
  259. }
  260. Assert( CountElementsInLeaf(leaf) == nCount );
  261. return true;
  262. }
  263. //-----------------------------------------------------------------------------
  264. // For convenience, enumerates the leaves along a ray, box, etc.
  265. //-----------------------------------------------------------------------------
  266. bool CBSPTreeData::EnumerateLeavesAtPoint( Vector const& pt, ISpatialLeafEnumerator* pEnum, int context )
  267. {
  268. return m_pBSPTree->EnumerateLeavesAtPoint( pt, pEnum, context );
  269. }
  270. bool CBSPTreeData::EnumerateLeavesInBox( Vector const& mins, Vector const& maxs, ISpatialLeafEnumerator* pEnum, int context )
  271. {
  272. return m_pBSPTree->EnumerateLeavesInBox( mins, maxs, pEnum, context );
  273. }
  274. bool CBSPTreeData::EnumerateLeavesInSphere( Vector const& center, float radius, ISpatialLeafEnumerator* pEnum, int context )
  275. {
  276. return m_pBSPTree->EnumerateLeavesInSphere( center, radius, pEnum, context );
  277. }
  278. bool CBSPTreeData::EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context )
  279. {
  280. return m_pBSPTree->EnumerateLeavesAlongRay( ray, pEnum, context );
  281. }