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.

541 lines
16 KiB

  1. //==== Copyright � 1996-2008, Valve Corporation, All rights reserved. =======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #ifndef INDEXDATA_H
  7. #define INDEXDATA_H
  8. #ifdef _WIN32
  9. #pragma once
  10. #endif
  11. #include "tier0/platform.h"
  12. #include "rendersystem/irendercontext.h"
  13. //-----------------------------------------------------------------------------
  14. //
  15. // Helper class used to define index buffers
  16. //
  17. //-----------------------------------------------------------------------------
  18. template < class T > class CIndexData
  19. {
  20. public:
  21. CIndexData( IRenderContext* pRenderContext, HRenderBuffer hIndexBuffer );
  22. CIndexData( IRenderContext* pRenderContext, RenderBufferType_t nType, int nIndexCount, const char *pDebugName, const char *pBudgetGroup );
  23. // This constructor is meant to be used with instance rendering.
  24. // Passing in either 0 or INT_MAX here means the client code
  25. // doesn't know how many instances will be rendered.
  26. CIndexData( IRenderContext* pRenderContext, RenderBufferType_t nType, int nIndexCount, int nMaxInstanceCount, const char *pDebugName, const char *pBudgetGroup );
  27. ~CIndexData();
  28. // Begins, ends modification of the index buffer (returns true if the lock succeeded)
  29. // A lock may not succeed if there isn't enough room
  30. // Passing in 0 locks the entire buffer
  31. bool Lock( int nMaxIndexCount = 0 );
  32. void Unlock();
  33. // returns the number of indices
  34. int IndexCount() const;
  35. // returns the total # of indices in the entire buffer
  36. int GetBufferIndexCount() const;
  37. // Used to define the indices (only used if you aren't using primitives)
  38. void Index( T nIndex );
  39. // NOTE: This version is the one you really want to achieve write-combining;
  40. // Write combining only works if you write in 4 bytes chunks.
  41. void Index2( T nIndex1, T nIndex2 );
  42. /*
  43. void FastTriangle( T nStartVert );
  44. void FastQuad( T nStartVert );
  45. void FastPolygon( T nStartVert, int nEdgeCount );
  46. void FastPolygonList( T nStartVert, int *pVertexCount, int polygonCount );
  47. void FastIndexList( const T *pIndexList, T nStartVert, int indexCount );
  48. */
  49. // Call this to detach ownership of the vertex buffer. Caller is responsible
  50. // for deleting it now
  51. HRenderBuffer TakeOwnership();
  52. protected:
  53. enum
  54. {
  55. BUFFER_OFFSET_UNINITIALIZED = 0xFFFFFFFF
  56. };
  57. void Init( IRenderContext* pRenderContext, RenderBufferType_t nType, int nIndexCount, int nMaxInstanceCount, const char *pDebugName, const char *pBudgetGroup );
  58. void Release();
  59. // Pointer to the memory we're writing
  60. T* m_pMemory;
  61. // The current index
  62. int m_nIndexCount;
  63. // Amount to increase the index count each time (0 if there was a lock failure)
  64. int m_nIndexIncrement;
  65. // The mesh we're modifying
  66. IRenderContext* m_pRenderContext;
  67. HRenderBuffer m_hIndexBuffer;
  68. // Max number of indices
  69. int m_nMaxIndexCount;
  70. int m_nBufferIndexCount : 31;
  71. int m_bShouldDeallocate : 1;
  72. };
  73. //-----------------------------------------------------------------------------
  74. //
  75. // Inline methods related to CIndexData
  76. //
  77. //-----------------------------------------------------------------------------
  78. //-----------------------------------------------------------------------------
  79. // Constructor
  80. //-----------------------------------------------------------------------------
  81. template< class T >
  82. inline CIndexData<T>::CIndexData( IRenderContext* pRenderContext, HRenderBuffer hIndexBuffer )
  83. {
  84. m_pRenderContext = pRenderContext;
  85. m_hIndexBuffer = hIndexBuffer;
  86. m_bShouldDeallocate = false;
  87. BufferDesc_t desc;
  88. pRenderContext->GetDevice()->GetIndexBufferDesc( hIndexBuffer, &desc );
  89. m_nBufferIndexCount = desc.m_nElementCount;
  90. #ifdef _DEBUG
  91. m_nIndexCount = 0;
  92. m_nMaxIndexCount = 0;
  93. m_pMemory = NULL;
  94. m_nIndexIncrement = 0;
  95. #endif
  96. }
  97. template< class T >
  98. inline CIndexData<T>::CIndexData( IRenderContext* pRenderContext, RenderBufferType_t nType, int nIndexCount, const char *pDebugName, const char *pBudgetGroup )
  99. {
  100. Init( pRenderContext, nType, nIndexCount, 0, pDebugName, pBudgetGroup );
  101. }
  102. template< class T >
  103. inline CIndexData<T>::CIndexData( IRenderContext* pRenderContext, RenderBufferType_t nType, int nIndexCount, int nMaxInstanceCount, const char *pDebugName, const char *pBudgetGroup )
  104. {
  105. if ( nMaxInstanceCount == 0 )
  106. {
  107. nMaxInstanceCount = INT_MAX;
  108. }
  109. Init( pRenderContext, nType, nIndexCount, nMaxInstanceCount, pDebugName, pBudgetGroup );
  110. }
  111. template< class T >
  112. inline void CIndexData<T>::Init( IRenderContext* pRenderContext, RenderBufferType_t nType,
  113. int nIndexCount, int nMaxInstanceCount, const char *pDebugName, const char *pBudgetGroup )
  114. {
  115. m_pRenderContext = pRenderContext;
  116. BufferDesc_t indexDesc;
  117. indexDesc.m_nElementSizeInBytes = sizeof(T);
  118. indexDesc.m_nElementCount = nIndexCount;
  119. indexDesc.m_pDebugName = pDebugName;
  120. indexDesc.m_pBudgetGroupName = pBudgetGroup;
  121. m_hIndexBuffer = pRenderContext->GetDevice()->CreateIndexBuffer( nType, indexDesc, nMaxInstanceCount );
  122. m_nBufferIndexCount = nIndexCount;
  123. m_bShouldDeallocate = true;
  124. ResourceAddRef( m_hIndexBuffer );
  125. #ifdef _DEBUG
  126. m_nIndexCount = 0;
  127. m_nMaxIndexCount = 0;
  128. m_pMemory = NULL;
  129. m_nIndexIncrement = 0;
  130. #endif
  131. }
  132. template< class T >
  133. inline CIndexData<T>::~CIndexData()
  134. {
  135. // If this assertion fails, you forgot to unlock
  136. Assert( !m_pMemory );
  137. Release();
  138. }
  139. //-----------------------------------------------------------------------------
  140. // Release
  141. //-----------------------------------------------------------------------------
  142. template< class T >
  143. void CIndexData<T>::Release()
  144. {
  145. if ( m_bShouldDeallocate && ( m_hIndexBuffer != RENDER_BUFFER_HANDLE_INVALID ) )
  146. {
  147. ResourceRelease( m_hIndexBuffer );
  148. m_pRenderContext->GetDevice()->DestroyIndexBuffer( m_hIndexBuffer );
  149. m_hIndexBuffer = RENDER_BUFFER_HANDLE_INVALID;
  150. m_bShouldDeallocate = false;
  151. }
  152. }
  153. //-----------------------------------------------------------------------------
  154. // Call this to take ownership of the vertex buffer
  155. //-----------------------------------------------------------------------------
  156. template< class T >
  157. inline HRenderBuffer CIndexData<T>::TakeOwnership()
  158. {
  159. if ( m_bShouldDeallocate )
  160. {
  161. ResourceRelease( m_hIndexBuffer );
  162. }
  163. m_bShouldDeallocate = false;
  164. return m_hIndexBuffer;
  165. }
  166. //-----------------------------------------------------------------------------
  167. // Returns the buffer vertex count
  168. //-----------------------------------------------------------------------------
  169. template< class T >
  170. inline int CIndexData<T>::GetBufferIndexCount() const
  171. {
  172. return m_nBufferIndexCount;
  173. }
  174. //-----------------------------------------------------------------------------
  175. // Begins, ends modification of the index buffer
  176. //-----------------------------------------------------------------------------
  177. template< class T >
  178. inline bool CIndexData<T>::Lock( int nMaxIndexCount )
  179. {
  180. if ( nMaxIndexCount == 0 )
  181. {
  182. nMaxIndexCount = m_nBufferIndexCount;
  183. }
  184. // Lock the index buffer
  185. LockDesc_t desc;
  186. bool bOk = m_pRenderContext->LockIndexBuffer( m_hIndexBuffer, nMaxIndexCount * sizeof(T), &desc );
  187. m_nIndexIncrement = bOk ? 1 : 0;
  188. m_nMaxIndexCount = nMaxIndexCount * m_nIndexIncrement;
  189. m_nIndexCount = 0;
  190. m_pMemory = (T*)desc.m_pMemory;
  191. return bOk;
  192. }
  193. template< class T >
  194. inline void CIndexData<T>::Unlock()
  195. {
  196. LockDesc_t desc;
  197. desc.m_pMemory = m_pMemory;
  198. m_pRenderContext->UnlockIndexBuffer( m_hIndexBuffer, m_nIndexCount * sizeof(T), &desc );
  199. #ifdef _DEBUG
  200. m_nIndexCount = 0;
  201. m_nMaxIndexCount = 0;
  202. m_pMemory = 0;
  203. m_nIndexIncrement = 0;
  204. #endif
  205. }
  206. /*
  207. //-----------------------------------------------------------------------------
  208. // Binds this index buffer
  209. //-----------------------------------------------------------------------------
  210. inline void CIndexData<T>::Bind( IMatRenderContext *pContext )
  211. {
  212. pContext->BindIndexBuffer( m_pIndexBuffer, 0 );
  213. }
  214. */
  215. //-----------------------------------------------------------------------------
  216. // returns the number of indices
  217. //-----------------------------------------------------------------------------
  218. template< class T >
  219. inline int CIndexData<T>::IndexCount() const
  220. {
  221. return m_nIndexCount;
  222. }
  223. //-----------------------------------------------------------------------------
  224. // Used to write data into the index buffer
  225. //-----------------------------------------------------------------------------
  226. template< class T >
  227. inline void CIndexData<T>::Index( T nIndex )
  228. {
  229. // FIXME: Should we prevent use of this with T = uint16? (write-combining)
  230. Assert( m_pMemory );
  231. Assert( ( m_nIndexIncrement == 0 ) || ( m_nIndexCount < m_nMaxIndexCount ) );
  232. m_pMemory[m_nIndexCount] = nIndex;
  233. m_nIndexCount += m_nIndexIncrement;
  234. }
  235. //-----------------------------------------------------------------------------
  236. // NOTE: This version is the one you really want to achieve write-combining;
  237. // Write combining only works if you write in 4 bytes chunks.
  238. //-----------------------------------------------------------------------------
  239. template< >
  240. inline void CIndexData<uint16>::Index2( uint16 nIndex1, uint16 nIndex2 )
  241. {
  242. Assert( m_pMemory );
  243. Assert( ( m_nIndexIncrement == 0 ) || ( m_nIndexCount < m_nMaxIndexCount - 1 ) );
  244. #ifndef _X360
  245. uint32 nIndices = ( (uint32)nIndex1 ) | ( ( (uint32)nIndex2 ) << 16 );
  246. #else
  247. uint32 nIndices = ( (uint32)nIndex2 ) | ( ( (uint32)nIndex1 ) << 16 );
  248. #endif
  249. *(uint32*)( &m_pMemory[m_nIndexCount] ) = nIndices;
  250. m_nIndexCount += m_nIndexIncrement + m_nIndexIncrement;
  251. }
  252. template< >
  253. inline void CIndexData<uint32>::Index2( uint32 nIndex1, uint32 nIndex2 )
  254. {
  255. Assert( m_pMemory );
  256. Assert( ( m_nIndexIncrement == 0 ) || ( m_nIndexCount < m_nMaxIndexCount - 1 ) );
  257. m_pMemory[m_nIndexCount] = nIndex1;
  258. m_pMemory[m_nIndexCount+1] = nIndex2;
  259. m_nIndexCount += m_nIndexIncrement + m_nIndexIncrement;
  260. }
  261. template< class T >
  262. inline void CIndexData<T>::Index2( T nIndex1, T nIndex2 )
  263. {
  264. COMPILE_TIME_ASSERT( 0 );
  265. }
  266. #if 0
  267. template< class T >
  268. inline void CIndexData<T>::FastTriangle( int startVert )
  269. {
  270. startVert += m_nIndexOffset;
  271. m_pIndices[m_nCurrentIndex+0] = startVert;
  272. m_pIndices[m_nCurrentIndex+1] = startVert + 1;
  273. m_pIndices[m_nCurrentIndex+2] = startVert + 2;
  274. AdvanceIndices(3);
  275. }
  276. template< class T >
  277. inline void CIndexData<T>::FastQuad( int startVert )
  278. {
  279. startVert += m_nIndexOffset;
  280. m_pIndices[m_nCurrentIndex+0] = startVert;
  281. m_pIndices[m_nCurrentIndex+1] = startVert + 1;
  282. m_pIndices[m_nCurrentIndex+2] = startVert + 2;
  283. m_pIndices[m_nCurrentIndex+3] = startVert;
  284. m_pIndices[m_nCurrentIndex+4] = startVert + 2;
  285. m_pIndices[m_nCurrentIndex+5] = startVert + 3;
  286. AdvanceIndices(6);
  287. }
  288. template< class T >
  289. inline void CIndexData<T>::FastPolygon( int startVert, int triangleCount )
  290. {
  291. unsigned short *pIndex = &m_pIndices[m_nCurrentIndex];
  292. startVert += m_nIndexOffset;
  293. if ( !IsX360() )
  294. {
  295. // NOTE: IndexSize is 1 or 0 (0 for alt-tab)
  296. // This prevents us from writing into bogus memory
  297. Assert( m_nIndexSize == 0 || m_nIndexSize == 1 );
  298. triangleCount *= m_nIndexSize;
  299. }
  300. for ( int v = 0; v < triangleCount; ++v )
  301. {
  302. *pIndex++ = startVert;
  303. *pIndex++ = startVert + v + 1;
  304. *pIndex++ = startVert + v + 2;
  305. }
  306. AdvanceIndices(triangleCount*3);
  307. }
  308. template< class T >
  309. inline void CIndexData<T>::FastPolygonList( int startVert, int *pVertexCount, int polygonCount )
  310. {
  311. unsigned short *pIndex = &m_pIndices[m_nCurrentIndex];
  312. startVert += m_nIndexOffset;
  313. int indexOut = 0;
  314. if ( !IsX360() )
  315. {
  316. // NOTE: IndexSize is 1 or 0 (0 for alt-tab)
  317. // This prevents us from writing into bogus memory
  318. Assert( m_nIndexSize == 0 || m_nIndexSize == 1 );
  319. polygonCount *= m_nIndexSize;
  320. }
  321. for ( int i = 0; i < polygonCount; i++ )
  322. {
  323. int vertexCount = pVertexCount[i];
  324. int triangleCount = vertexCount-2;
  325. for ( int v = 0; v < triangleCount; ++v )
  326. {
  327. *pIndex++ = startVert;
  328. *pIndex++ = startVert + v + 1;
  329. *pIndex++ = startVert + v + 2;
  330. }
  331. startVert += vertexCount;
  332. indexOut += triangleCount * 3;
  333. }
  334. AdvanceIndices(indexOut);
  335. }
  336. template< class T >
  337. inline void CIndexData<T>::FastIndexList( const unsigned short *pIndexList, int startVert, int indexCount )
  338. {
  339. unsigned short *pIndexOut = &m_pIndices[m_nCurrentIndex];
  340. startVert += m_nIndexOffset;
  341. if ( !IsX360() )
  342. {
  343. // NOTE: IndexSize is 1 or 0 (0 for alt-tab)
  344. // This prevents us from writing into bogus memory
  345. Assert( m_nIndexSize == 0 || m_nIndexSize == 1 );
  346. indexCount *= m_nIndexSize;
  347. }
  348. for ( int i = 0; i < indexCount; ++i )
  349. {
  350. pIndexOut[i] = startVert + pIndexList[i];
  351. }
  352. AdvanceIndices(indexCount);
  353. }
  354. #endif
  355. //-----------------------------------------------------------------------------
  356. // Dynamic index field creation
  357. // NOTE: Draw call must occur prior to destruction of this class!
  358. //-----------------------------------------------------------------------------
  359. template< class T > class CDynamicIndexData : public CIndexData< T >
  360. {
  361. typedef CIndexData< T > BaseClass;
  362. public:
  363. CDynamicIndexData( IRenderContext* pRenderContext, int nIndexCount, const char *pDebugName, const char *pBudgetGroup );
  364. // This constructor is meant to be used with instance rendering.
  365. // Passing in either 0 or INT_MAX here means the client code
  366. // doesn't know how many instances will be rendered.
  367. CDynamicIndexData( IRenderContext* pRenderContext, int nIndexCount, int nMaxInstanceCount, const char *pDebugName, const char *pBudgetGroup );
  368. ~CDynamicIndexData();
  369. void Release();
  370. // Begins, ends modification of the vertex buffer (returns true if the lock succeeded)
  371. // A lock may not succeed if there isn't enough room
  372. bool Lock( );
  373. // Binds the vb to a particular slot using a particular offset
  374. void Bind( int nOffset );
  375. private:
  376. void Init( IRenderContext* pRenderContext, int nIndexCount, int nMaxInstanceCount, const char *pDebugName, const char *pBudgetGroup );
  377. };
  378. //-----------------------------------------------------------------------------
  379. //
  380. // Inline methods related to CDynamicIndexData
  381. //
  382. //-----------------------------------------------------------------------------
  383. //-----------------------------------------------------------------------------
  384. // Constructor
  385. //-----------------------------------------------------------------------------
  386. template< class T >
  387. inline CDynamicIndexData<T>::CDynamicIndexData( IRenderContext* pRenderContext,
  388. int nIndexCount, const char *pDebugName, const char *pBudgetGroup ) :
  389. BaseClass( pRenderContext, RENDER_BUFFER_HANDLE_INVALID )
  390. {
  391. Init( pRenderContext, nIndexCount, 0, pDebugName, pBudgetGroup );
  392. }
  393. template< class T >
  394. inline CDynamicIndexData<T>::CDynamicIndexData( IRenderContext* pRenderContext,
  395. int nIndexCount, int nMaxInstanceCount, const char *pDebugName, const char *pBudgetGroup ) :
  396. BaseClass( pRenderContext, RENDER_BUFFER_HANDLE_INVALID )
  397. {
  398. if ( nMaxInstanceCount == 0 )
  399. {
  400. nMaxInstanceCount = INT_MAX;
  401. }
  402. Init( pRenderContext, nIndexCount, nMaxInstanceCount, pDebugName, pBudgetGroup );
  403. }
  404. template< class T >
  405. inline void CDynamicIndexData<T>::Init( IRenderContext* pRenderContext,
  406. int nIndexCount, int nMaxInstanceCount, const char *pDebugName, const char *pBudgetGroup )
  407. {
  408. BufferDesc_t indexDesc;
  409. indexDesc.m_nElementSizeInBytes = sizeof(T);
  410. indexDesc.m_nElementCount = nIndexCount;
  411. indexDesc.m_pDebugName = pDebugName;
  412. indexDesc.m_pBudgetGroupName = pBudgetGroup;
  413. this->m_hIndexBuffer = pRenderContext->CreateDynamicIndexBuffer( indexDesc, nMaxInstanceCount );
  414. this->m_nBufferIndexCount = nIndexCount;
  415. ResourceAddRef( m_hIndexBuffer );
  416. }
  417. template< class T >
  418. inline CDynamicIndexData<T>::~CDynamicIndexData()
  419. {
  420. Release();
  421. }
  422. //-----------------------------------------------------------------------------
  423. // Release
  424. //-----------------------------------------------------------------------------
  425. template< class T >
  426. void CDynamicIndexData<T>::Release()
  427. {
  428. if ( this->m_hIndexBuffer != RENDER_BUFFER_HANDLE_INVALID )
  429. {
  430. this->m_pRenderContext->DestroyDynamicIndexBuffer( this->m_hIndexBuffer );
  431. ResourceRelease( m_hIndexBuffer );
  432. this->m_hIndexBuffer = RENDER_BUFFER_HANDLE_INVALID;
  433. }
  434. }
  435. //-----------------------------------------------------------------------------
  436. // Begins, ends modification of the buffer
  437. //-----------------------------------------------------------------------------
  438. template< class T >
  439. inline bool CDynamicIndexData<T>::Lock( )
  440. {
  441. Assert( this->m_hIndexBuffer != RENDER_BUFFER_HANDLE_INVALID );
  442. return BaseClass::Lock( );
  443. }
  444. //-----------------------------------------------------------------------------
  445. // Binds the ib to a particular stream using a particular offset
  446. //-----------------------------------------------------------------------------
  447. template< class T >
  448. inline void CDynamicIndexData<T>::Bind( int nOffset )
  449. {
  450. this->m_pRenderContext->BindIndexBuffer( this->m_hIndexBuffer, nOffset );
  451. }
  452. #endif // INDEXDATA_H