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.

5980 lines
172 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #define DISABLE_PROTECTED_THINGS
  7. #include "locald3dtypes.h"
  8. #include "imeshdx8.h"
  9. #include "shaderapidx8_global.h"
  10. #include "materialsystem/IShader.h"
  11. #include "tier0/vprof.h"
  12. #include "studio.h"
  13. #include "tier1/fmtstr.h"
  14. #include "tier0/platform.h"
  15. #include "tier0/systeminformation.h"
  16. // fixme - stick this in a header file.
  17. #if defined( _DEBUG ) && !defined( _X360 )
  18. // define this if you want to range check all indices when drawing
  19. #define CHECK_INDICES
  20. #endif
  21. #ifdef CHECK_INDICES
  22. #define CHECK_INDICES_MAX_NUM_STREAMS 2
  23. #endif
  24. #include "dynamicib.h"
  25. #include "dynamicvb.h"
  26. #include "utlvector.h"
  27. #include "shaderapi/ishaderapi.h"
  28. #include "imaterialinternal.h"
  29. #include "imaterialsysteminternal.h"
  30. #include "shaderapidx8.h"
  31. #include "shaderapi/ishaderutil.h"
  32. #include "materialsystem/imaterialsystemhardwareconfig.h"
  33. #include "materialsystem/materialsystem_config.h"
  34. #include "materialsystem/ivballoctracker.h"
  35. #include "tier1/strtools.h"
  36. #include "convar.h"
  37. #include "shaderdevicedx8.h"
  38. // memdbgon must be the last include file in a .cpp file!!!
  39. #include "tier0/memdbgon.h"
  40. //-----------------------------------------------------------------------------
  41. // Uncomment this to test buffered state
  42. //-----------------------------------------------------------------------------
  43. //#define DEBUG_BUFFERED_MESHES 1
  44. #define MAX_DX8_STREAMS 16
  45. #define VERTEX_FORMAT_INVALID 0xFFFFFFFFFFFFFFFFull
  46. // this is hooked into the engines convar
  47. extern ConVar mat_debugalttab;
  48. //#define DRAW_SELECTION 1
  49. static bool g_bDrawSelection = true; // only used in DRAW_SELECTION
  50. static unsigned short g_nScratchIndexBuffer[6]; // large enough for a fast quad; used when device is not active
  51. #ifdef _DEBUG
  52. int CVertexBuffer::s_BufferCount = 0;
  53. int CIndexBuffer::s_BufferCount = 0;
  54. #endif
  55. //-----------------------------------------------------------------------------
  56. // Important enumerations
  57. //-----------------------------------------------------------------------------
  58. enum
  59. {
  60. VERTEX_BUFFER_SIZE = 32768,
  61. MAX_QUAD_INDICES = 16384,
  62. };
  63. //-----------------------------------------------------------------------------
  64. //
  65. // Code related to vertex buffers start here
  66. //
  67. //-----------------------------------------------------------------------------
  68. class CVertexBufferDx8 : public CVertexBufferBase
  69. {
  70. typedef CVertexBufferBase BaseClass;
  71. // Methods of IVertexBuffer
  72. public:
  73. virtual int VertexCount() const;
  74. virtual VertexFormat_t GetVertexFormat() const;
  75. virtual bool IsDynamic() const;
  76. virtual void BeginCastBuffer( VertexFormat_t format );
  77. virtual void EndCastBuffer( );
  78. virtual int GetRoomRemaining() const;
  79. virtual bool Lock( int nVertexCount, bool bAppend, VertexDesc_t &desc );
  80. virtual void Unlock( int nVertexCount, VertexDesc_t &desc );
  81. public:
  82. // constructor
  83. CVertexBufferDx8( ShaderBufferType_t type, VertexFormat_t fmt, int nVertexCount, const char *pBudgetGroupName );
  84. virtual ~CVertexBufferDx8();
  85. // Allocates, deallocates the index buffer
  86. bool Allocate( );
  87. void Free();
  88. // Returns the vertex size
  89. int VertexSize() const;
  90. // Only used by dynamic buffers, indicates the next lock should perform a discard.
  91. void Flush();
  92. // Returns the D3D buffer
  93. IDirect3DVertexBuffer9* GetDx9Buffer();
  94. // Used to measure how much static buffer memory is touched each frame
  95. void HandlePerFrameTextureStats( int nFrame );
  96. protected:
  97. IDirect3DVertexBuffer9 *m_pVertexBuffer;
  98. VertexFormat_t m_VertexFormat;
  99. int m_nVertexCount;
  100. int m_nBufferSize;
  101. int m_nFirstUnwrittenOffset; // Used only for dynamic buffers, indicates where it's safe to write (nooverwrite)
  102. // Is it locked?
  103. bool m_bIsLocked : 1;
  104. bool m_bIsDynamic : 1;
  105. bool m_bFlush : 1; // Used only for dynamic buffers, indicates to discard the next time
  106. #ifdef VPROF_ENABLED
  107. int m_nVProfFrame;
  108. int *m_pFrameCounter;
  109. int *m_pGlobalCounter;
  110. #endif
  111. #ifdef _DEBUG
  112. static int s_nBufferCount;
  113. #endif
  114. };
  115. //-----------------------------------------------------------------------------
  116. //
  117. // Code related to index buffers start here
  118. //
  119. //-----------------------------------------------------------------------------
  120. class CIndexBufferDx8 : public CIndexBufferBase
  121. {
  122. typedef CIndexBufferBase BaseClass;
  123. // Methods of IIndexBuffer
  124. public:
  125. virtual int IndexCount( ) const;
  126. virtual MaterialIndexFormat_t IndexFormat() const;
  127. virtual int GetRoomRemaining() const;
  128. virtual bool Lock( int nIndexCount, bool bAppend, IndexDesc_t &desc );
  129. virtual void Unlock( int nIndexCount, IndexDesc_t &desc );
  130. virtual void BeginCastBuffer( MaterialIndexFormat_t format );
  131. virtual void EndCastBuffer( );
  132. virtual bool IsDynamic() const;
  133. virtual void ModifyBegin( bool bReadOnly, int nFirstIndex, int nIndexCount, IndexDesc_t& desc ) { Assert(0); }
  134. virtual void ModifyEnd( IndexDesc_t& desc ) { Assert(0); }
  135. public:
  136. // constructor
  137. CIndexBufferDx8( ShaderBufferType_t bufferType, MaterialIndexFormat_t fmt, int nIndexCount, const char *pBudgetGroupName );
  138. virtual ~CIndexBufferDx8();
  139. // Allocates, deallocates the index buffer
  140. bool Allocate( );
  141. void Free();
  142. // Returns the index size
  143. int IndexSize() const;
  144. // Only used by dynamic buffers, indicates the next lock should perform a discard.
  145. void Flush();
  146. // Returns the D3D buffer
  147. IDirect3DIndexBuffer9* GetDx9Buffer();
  148. // Used to measure how much static buffer memory is touched each frame
  149. void HandlePerFrameTextureStats( int nFrame );
  150. #ifdef CHECK_INDICES
  151. unsigned short GetShadowIndex( int i ) const;
  152. #endif
  153. private:
  154. IDirect3DIndexBuffer9 *m_pIndexBuffer;
  155. MaterialIndexFormat_t m_IndexFormat;
  156. int m_nIndexCount;
  157. int m_nBufferSize;
  158. int m_nFirstUnwrittenOffset; // Used only for dynamic buffers, indicates where it's safe to write (nooverwrite)
  159. // Is it locked?
  160. bool m_bIsLocked : 1;
  161. bool m_bIsDynamic : 1;
  162. bool m_bFlush : 1; // Used only for dynamic buffers, indicates to discard the next time
  163. #ifdef CHECK_INDICES
  164. unsigned char *m_pShadowIndices;
  165. void *m_pLockIndexBuffer;
  166. int m_nLockIndexBufferSize;
  167. int m_nLockIndexOffset;
  168. #endif
  169. #ifdef VPROF_ENABLED
  170. int m_nVProfFrame;
  171. #endif
  172. #ifdef _DEBUG
  173. static int s_nBufferCount;
  174. #endif
  175. };
  176. //-----------------------------------------------------------------------------
  177. //
  178. // Backward compat mesh code; will go away soon
  179. //
  180. //-----------------------------------------------------------------------------
  181. abstract_class CBaseMeshDX8 : public CMeshBase
  182. {
  183. public:
  184. // constructor, destructor
  185. CBaseMeshDX8();
  186. virtual ~CBaseMeshDX8();
  187. // FIXME: Make this work! Unsupported methods of IIndexBuffer + IVertexBuffer
  188. virtual bool Lock( int nMaxIndexCount, bool bAppend, IndexDesc_t& desc ) { Assert(0); return false; }
  189. virtual void Unlock( int nWrittenIndexCount, IndexDesc_t& desc ) { Assert(0); }
  190. virtual void ModifyBegin( bool bReadOnly, int nFirstIndex, int nIndexCount, IndexDesc_t& desc ) { Assert(0); }
  191. virtual void ModifyEnd( IndexDesc_t& desc ) { Assert(0); }
  192. virtual void Spew( int nIndexCount, const IndexDesc_t & desc ) { Assert(0); }
  193. virtual void ValidateData( int nIndexCount, const IndexDesc_t &desc ) { Assert(0); }
  194. virtual bool Lock( int nVertexCount, bool bAppend, VertexDesc_t &desc ) { Assert(0); return false; }
  195. virtual void Unlock( int nVertexCount, VertexDesc_t &desc ) { Assert(0); }
  196. virtual void Spew( int nVertexCount, const VertexDesc_t &desc ) { Assert(0); }
  197. virtual void ValidateData( int nVertexCount, const VertexDesc_t & desc ) { Assert(0); }
  198. // Locks mesh for modifying
  199. void ModifyBeginEx( bool bReadOnly, int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc );
  200. void ModifyBegin( int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc );
  201. void ModifyEnd( MeshDesc_t& desc );
  202. // Sets/gets the vertex format
  203. virtual void SetVertexFormat( VertexFormat_t format );
  204. virtual VertexFormat_t GetVertexFormat() const;
  205. // Sets/gets the morph format
  206. virtual void SetMorphFormat( MorphFormat_t format );
  207. virtual MorphFormat_t GetMorphFormat() const;
  208. // Am I using morph data?
  209. virtual bool IsUsingMorphData() const;
  210. bool IsUsingVertexID() const
  211. {
  212. return ShaderAPI()->GetBoundMaterial()->IsUsingVertexID();
  213. }
  214. // Sets the material
  215. virtual void SetMaterial( IMaterial* pMaterial );
  216. // returns the # of vertices (static meshes only)
  217. int VertexCount() const { return 0; }
  218. void SetColorMesh( IMesh *pColorMesh, int nVertexOffsetInBytes )
  219. {
  220. Assert( 0 );
  221. }
  222. void SetFlexMesh( IMesh *pMesh, int nVertexOffsetInBytes )
  223. {
  224. Assert( pMesh == NULL && nVertexOffsetInBytes == 0 );
  225. }
  226. void DisableFlexMesh( )
  227. {
  228. Assert( 0 );
  229. }
  230. void MarkAsDrawn() {}
  231. bool HasColorMesh( ) const { return false; }
  232. bool HasFlexMesh( ) const { return false; }
  233. // Draws the mesh
  234. void DrawMesh( );
  235. // Begins a pass
  236. void BeginPass( );
  237. // Spews the mesh data
  238. virtual void Spew( int nVertexCount, int nIndexCount, const MeshDesc_t & desc );
  239. // Call this in debug mode to make sure our data is good.
  240. virtual void ValidateData( int nVertexCount, int nIndexCount, const MeshDesc_t & desc );
  241. virtual void HandleLateCreation( ) = 0;
  242. void Draw( CPrimList *pLists, int nLists );
  243. // Copy verts and/or indices to a mesh builder. This only works for temp meshes!
  244. virtual void CopyToMeshBuilder(
  245. int iStartVert, // Which vertices to copy.
  246. int nVerts,
  247. int iStartIndex, // Which indices to copy.
  248. int nIndices,
  249. int indexOffset, // This is added to each index.
  250. CMeshBuilder &builder );
  251. // returns the primitive type
  252. virtual MaterialPrimitiveType_t GetPrimitiveType() const = 0;
  253. // Returns the number of indices in a mesh..
  254. virtual int IndexCount( ) const = 0;
  255. // FIXME: Make this work!
  256. virtual MaterialIndexFormat_t IndexFormat() const { return MATERIAL_INDEX_FORMAT_16BIT; }
  257. // NOTE: For dynamic index buffers only!
  258. // Casts the memory of the dynamic index buffer to the appropriate type
  259. virtual void BeginCastBuffer( MaterialIndexFormat_t format ) { Assert(0); }
  260. virtual void BeginCastBuffer( VertexFormat_t format ) { Assert(0); }
  261. virtual void EndCastBuffer( ) { Assert(0); }
  262. virtual int GetRoomRemaining() const { Assert(0); return 0; }
  263. // returns a static vertex buffer...
  264. virtual CVertexBuffer *GetVertexBuffer() { return 0; }
  265. virtual CIndexBuffer *GetIndexBuffer() { return 0; }
  266. // Do I need to reset the vertex format?
  267. virtual bool NeedsVertexFormatReset( VertexFormat_t fmt ) const;
  268. // Do I have enough room?
  269. virtual bool HasEnoughRoom( int nVertexCount, int nIndexCount ) const;
  270. // Operation to do pre-lock
  271. virtual void PreLock() {}
  272. virtual unsigned ComputeMemoryUsed();
  273. bool m_bMeshLocked;
  274. protected:
  275. bool DebugTrace() const;
  276. // The vertex format we're using...
  277. VertexFormat_t m_VertexFormat;
  278. // The morph format we're using
  279. MorphFormat_t m_MorphFormat;
  280. #ifdef DBGFLAG_ASSERT
  281. IMaterialInternal* m_pMaterial;
  282. bool m_IsDrawing;
  283. #endif
  284. };
  285. //-----------------------------------------------------------------------------
  286. // Implementation of the mesh
  287. //-----------------------------------------------------------------------------
  288. class CMeshDX8 : public CBaseMeshDX8
  289. {
  290. public:
  291. // constructor
  292. CMeshDX8( const char *pTextureGroupName );
  293. virtual ~CMeshDX8();
  294. // Locks/unlocks the mesh
  295. void LockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc );
  296. void UnlockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc );
  297. // Locks mesh for modifying
  298. void ModifyBeginEx( bool bReadOnly, int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc );
  299. void ModifyBegin( int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc );
  300. void ModifyEnd( MeshDesc_t& desc );
  301. // returns the # of vertices (static meshes only)
  302. int VertexCount() const;
  303. // returns the # of indices
  304. virtual int IndexCount( ) const;
  305. // Sets up the vertex and index buffers
  306. void UseIndexBuffer( CIndexBuffer* pBuffer );
  307. void UseVertexBuffer( CVertexBuffer* pBuffer );
  308. // returns a static vertex buffer...
  309. CVertexBuffer *GetVertexBuffer() { return m_pVertexBuffer; }
  310. CIndexBuffer *GetIndexBuffer() { return m_pIndexBuffer; }
  311. void SetColorMesh( IMesh *pColorMesh, int nVertexOffsetInBytes );
  312. void SetFlexMesh( IMesh *pMesh, int nVertexOffsetInBytes );
  313. void DisableFlexMesh();
  314. virtual void HandleLateCreation( );
  315. bool HasColorMesh( ) const;
  316. bool HasFlexMesh( ) const;
  317. // Draws the mesh
  318. void Draw( int nFirstIndex, int nIndexCount );
  319. void Draw( CPrimList *pLists, int nLists );
  320. void DrawInternal( CPrimList *pLists, int nLists );
  321. // Draws a single pass
  322. void RenderPass();
  323. // Sets the primitive type
  324. void SetPrimitiveType( MaterialPrimitiveType_t type );
  325. MaterialPrimitiveType_t GetPrimitiveType() const;
  326. bool IsDynamic() const { return false; }
  327. protected:
  328. // Sets the render state.
  329. bool SetRenderState( int nVertexOffsetInBytes, int nFirstVertexIdx, VertexFormat_t vertexFormat = VERTEX_FORMAT_INVALID );
  330. // Is the vertex format valid?
  331. bool IsValidVertexFormat( VertexFormat_t vertexFormat = VERTEX_FORMAT_INVALID );
  332. // Locks/ unlocks the vertex buffer
  333. bool Lock( int nVertexCount, bool bAppend, VertexDesc_t &desc );
  334. void Unlock( int nVertexCount, VertexDesc_t &desc );
  335. // Locks/unlocks the index buffer
  336. // Pass in nFirstIndex=-1 to lock wherever the index buffer is. Pass in a value
  337. // >= 0 to specify where to lock.
  338. int Lock( bool bReadOnly, int nFirstIndex, int nIndexCount, IndexDesc_t &pIndices );
  339. void Unlock( int nIndexCount, IndexDesc_t &desc );
  340. // computes how many primitives we've got
  341. int NumPrimitives( int nVertexCount, int nIndexCount ) const;
  342. // Debugging output...
  343. void SpewMaterialVerts( );
  344. // Stream source setting methods
  345. void SetVertexIDStreamState( );
  346. void SetColorStreamState( );
  347. void SetVertexStreamState( int nVertOffsetInBytes );
  348. void SetIndexStreamState( int firstVertexIdx );
  349. void CheckIndices( CPrimList *pPrim, int numPrimitives );
  350. // The vertex and index buffers
  351. CVertexBuffer* m_pVertexBuffer;
  352. CIndexBuffer* m_pIndexBuffer;
  353. // The current color mesh (to be bound to stream 1)
  354. // The vertex offset allows use of a global, shared color mesh VB
  355. CMeshDX8 * m_pColorMesh;
  356. int m_nColorMeshVertOffsetInBytes;
  357. CVertexBuffer *m_pFlexVertexBuffer;
  358. bool m_bHasFlexVerts;
  359. int m_nFlexVertOffsetInBytes;
  360. int m_flexVertCount;
  361. // Primitive type
  362. MaterialPrimitiveType_t m_Type;
  363. // Primitive mode
  364. D3DPRIMITIVETYPE m_Mode;
  365. // Number of primitives
  366. unsigned int m_NumIndices;
  367. unsigned short m_NumVertices;
  368. // Is it locked?
  369. bool m_IsVBLocked;
  370. bool m_IsIBLocked;
  371. // Used in rendering sub-parts of the mesh
  372. static CPrimList *s_pPrims;
  373. static int s_nPrims;
  374. static unsigned int s_FirstVertex; // Gets reset during CMeshDX8::DrawInternal
  375. static unsigned int s_NumVertices;
  376. int m_FirstIndex;
  377. #ifdef RECORDING
  378. int m_LockVertexBufferSize;
  379. void *m_LockVertexBuffer;
  380. #endif
  381. #if defined( RECORDING ) || defined( CHECK_INDICES )
  382. void *m_LockIndexBuffer;
  383. int m_LockIndexBufferSize;
  384. #endif
  385. const char *m_pTextureGroupName;
  386. friend class CMeshMgr; // MESHFIXME
  387. };
  388. //-----------------------------------------------------------------------------
  389. // A little extra stuff for the dynamic version
  390. //-----------------------------------------------------------------------------
  391. class CDynamicMeshDX8 : public CMeshDX8
  392. {
  393. public:
  394. // constructor, destructor
  395. CDynamicMeshDX8();
  396. virtual ~CDynamicMeshDX8();
  397. // Initializes the dynamic mesh
  398. void Init( int nBufferId );
  399. // Sets the vertex format
  400. virtual void SetVertexFormat( VertexFormat_t format );
  401. // Resets the state in case of a task switch
  402. void Reset();
  403. // Do I have enough room in the buffer?
  404. bool HasEnoughRoom( int nVertexCount, int nIndexCount ) const;
  405. // returns the # of indices
  406. int IndexCount( ) const;
  407. // Locks the mesh
  408. void LockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc );
  409. // Unlocks the mesh
  410. void UnlockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc );
  411. // Override vertex + index buffer
  412. void OverrideVertexBuffer( CVertexBuffer *pStaticVertexBuffer );
  413. void OverrideIndexBuffer( CIndexBuffer *pStaticIndexBuffer );
  414. // Do I need to reset the vertex format?
  415. bool NeedsVertexFormatReset(VertexFormat_t fmt) const;
  416. // Draws it
  417. void Draw( int nFirstIndex, int nIndexCount );
  418. void MarkAsDrawn() { m_HasDrawn = true; }
  419. // Simply draws what's been buffered up immediately, without state change
  420. void DrawSinglePassImmediately();
  421. // Operation to do pre-lock
  422. void PreLock();
  423. bool IsDynamic() const { return true; }
  424. private:
  425. // Resets buffering state
  426. void ResetVertexAndIndexCounts();
  427. // Buffer Id
  428. int m_nBufferId;
  429. // total queued vertices
  430. int m_TotalVertices;
  431. int m_TotalIndices;
  432. // the first vertex and index since the last draw
  433. int m_nFirstVertex;
  434. int m_FirstIndex;
  435. // Have we drawn since the last lock?
  436. bool m_HasDrawn;
  437. // Any overrides?
  438. bool m_VertexOverride;
  439. bool m_IndexOverride;
  440. };
  441. //-----------------------------------------------------------------------------
  442. // A mesh that stores temporary vertex data in the correct format (for modification)
  443. //-----------------------------------------------------------------------------
  444. class CTempMeshDX8 : public CBaseMeshDX8
  445. {
  446. public:
  447. // constructor, destructor
  448. CTempMeshDX8( bool isDynamic );
  449. virtual ~CTempMeshDX8();
  450. // Sets the material
  451. virtual void SetVertexFormat( VertexFormat_t format );
  452. // Locks/unlocks the mesh
  453. void LockMesh( int nVertexCount, int nIndexCount, MeshDesc_t &desc );
  454. void UnlockMesh( int nVertexCount, int nIndexCount, MeshDesc_t &desc );
  455. // Locks mesh for modifying
  456. virtual void ModifyBeginEx( bool bReadOnly, int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc );
  457. virtual void ModifyBegin( int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc );
  458. virtual void ModifyEnd( MeshDesc_t& desc );
  459. // Number of indices + vertices
  460. int VertexCount() const;
  461. virtual int IndexCount() const;
  462. virtual bool IsDynamic() const;
  463. // Sets the primitive type
  464. void SetPrimitiveType( MaterialPrimitiveType_t type );
  465. MaterialPrimitiveType_t GetPrimitiveType() const;
  466. // Begins a pass
  467. void BeginPass( );
  468. // Draws a single pass
  469. void RenderPass();
  470. virtual void HandleLateCreation()
  471. {
  472. Assert( !"TBD - CTempMeshDX8::HandleLateCreation()" );
  473. }
  474. // Draws the entire beast
  475. void Draw( int nFirstIndex, int nIndexCount );
  476. virtual void CopyToMeshBuilder(
  477. int iStartVert, // Which vertices to copy.
  478. int nVerts,
  479. int iStartIndex, // Which indices to copy.
  480. int nIndices,
  481. int indexOffset, // This is added to each index.
  482. CMeshBuilder &builder );
  483. private:
  484. // Selection mode
  485. void TestSelection( );
  486. void ClipTriangle( D3DXVECTOR3 **ppVert, float zNear, D3DXMATRIX &proj );
  487. CDynamicMeshDX8 *GetDynamicMesh();
  488. CUtlVector< unsigned char, CUtlMemoryAligned< unsigned char, 32 > > m_VertexData;
  489. CUtlVector< unsigned short > m_IndexData;
  490. unsigned short m_VertexSize;
  491. MaterialPrimitiveType_t m_Type;
  492. int m_LockedVerts;
  493. int m_LockedIndices;
  494. bool m_IsDynamic;
  495. // Used in rendering sub-parts of the mesh
  496. static unsigned int s_NumIndices;
  497. static unsigned int s_FirstIndex;
  498. #ifdef DBGFLAG_ASSERT
  499. bool m_Locked;
  500. bool m_InPass;
  501. #endif
  502. };
  503. #if 0
  504. //-----------------------------------------------------------------------------
  505. // A mesh that stores temporary vertex data in the correct format (for modification)
  506. //-----------------------------------------------------------------------------
  507. class CTempIndexBufferDX8 : public CIndexBufferBase
  508. {
  509. public:
  510. // constructor, destructor
  511. CTempIndexBufferDX8( bool isDynamic );
  512. virtual ~CTempIndexBufferDX8();
  513. // Locks/unlocks the mesh
  514. void LockIndexBuffer( int nIndexCount );
  515. void UnlockMesh( int nIndexCount );
  516. // Locks mesh for modifying
  517. virtual void ModifyBeginEx( bool bReadOnly, int nFirstIndex, int nIndexCount );
  518. virtual void ModifyEnd();
  519. // Number of indices
  520. virtual int IndexCount() const;
  521. virtual bool IsDynamic() const;
  522. virtual void CopyToIndexBuilder(
  523. int iStartIndex, // Which indices to copy.
  524. int nIndices,
  525. int indexOffset, // This is added to each index.
  526. CIndexBuilder &builder );
  527. private:
  528. // Selection mode
  529. void TestSelection( );
  530. CDynamicMeshDX8 *GetDynamicMesh();
  531. CUtlVector< unsigned short > m_IndexData;
  532. MaterialPrimitiveType_t m_Type;
  533. int m_LockedIndices;
  534. bool m_IsDynamic;
  535. // Used in rendering sub-parts of the mesh
  536. static unsigned int s_NumIndices;
  537. static unsigned int s_FirstIndex;
  538. #ifdef DBGFLAG_ASSERT
  539. bool m_Locked;
  540. bool m_InPass;
  541. #endif
  542. };
  543. #endif
  544. //-----------------------------------------------------------------------------
  545. // This is a version that buffers up vertex data so we can blast through it later
  546. //-----------------------------------------------------------------------------
  547. class CBufferedMeshDX8 : public CBaseMeshDX8
  548. {
  549. public:
  550. // constructor, destructor
  551. CBufferedMeshDX8();
  552. virtual ~CBufferedMeshDX8();
  553. // checks to see if it was rendered..
  554. void ResetRendered();
  555. bool WasNotRendered() const;
  556. // Sets the mesh we're really going to draw into
  557. void SetMesh( CBaseMeshDX8* pMesh );
  558. const CBaseMeshDX8* GetMesh() const { return m_pMesh; }
  559. // Spews the mesh data
  560. virtual void Spew( int nVertexCount, int nIndexCount, const MeshDesc_t &spewDesc );
  561. // Sets the vertex format
  562. virtual void SetVertexFormat( VertexFormat_t format );
  563. virtual VertexFormat_t GetVertexFormat() const;
  564. // Sets the morph format
  565. virtual void SetMorphFormat( MorphFormat_t format );
  566. // Sets the material
  567. void SetMaterial( IMaterial *pMaterial );
  568. // returns the number of indices (should never be called!)
  569. virtual int IndexCount() const { Assert(0); return 0; }
  570. virtual MaterialIndexFormat_t IndexFormat() const { Assert(0); return MATERIAL_INDEX_FORMAT_16BIT; }
  571. virtual bool IsDynamic() const { Assert(0); return true; }
  572. virtual void BeginCastBuffer( MaterialIndexFormat_t format ) { Assert(0); }
  573. virtual void EndCastBuffer( ) { Assert(0); }
  574. virtual int GetRoomRemaining() const { Assert(0); return 0; }
  575. // Locks the mesh
  576. void LockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc );
  577. void UnlockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc );
  578. // Sets the primitive type
  579. void SetPrimitiveType( MaterialPrimitiveType_t type );
  580. MaterialPrimitiveType_t GetPrimitiveType( ) const;
  581. void ValidateData( int nVertexCount, int nIndexCount, const MeshDesc_t & spewDesc );
  582. virtual void HandleLateCreation( )
  583. {
  584. if ( m_pMesh )
  585. {
  586. m_pMesh->HandleLateCreation();
  587. }
  588. }
  589. // Draws it
  590. void Draw( int nFirstIndex, int nIndexCount );
  591. // Renders a pass
  592. void RenderPass();
  593. // Flushes queued data
  594. void Flush( );
  595. void SetFlexMesh( IMesh *pMesh, int nVertexOffsetInBytes );
  596. private:
  597. // The actual mesh we need to render....
  598. CBaseMeshDX8* m_pMesh;
  599. // The index of the last vertex (for tristrip fixup)
  600. unsigned short m_LastIndex;
  601. // Extra padding indices for tristrips
  602. unsigned short m_ExtraIndices;
  603. // Am I currently flushing?
  604. bool m_IsFlushing;
  605. // has the dynamic mesh been rendered?
  606. bool m_WasRendered;
  607. // Do I need to flush?
  608. bool m_FlushNeeded;
  609. #ifdef DEBUG_BUFFERED_MESHES
  610. // for debugging only
  611. bool m_BufferedStateSet;
  612. BufferedState_t m_BufferedState;
  613. #endif
  614. };
  615. //-----------------------------------------------------------------------------
  616. // Implementation of the mesh manager
  617. //-----------------------------------------------------------------------------
  618. class CMeshMgr : public IMeshMgr
  619. {
  620. public:
  621. // constructor, destructor
  622. CMeshMgr();
  623. virtual ~CMeshMgr();
  624. // Initialize, shutdown
  625. void Init();
  626. void Shutdown();
  627. // Task switch...
  628. void ReleaseBuffers();
  629. void RestoreBuffers();
  630. // Releases all dynamic vertex buffers
  631. void DestroyVertexBuffers();
  632. // Flushes the dynamic mesh
  633. void Flush();
  634. // Flushes the vertex buffers
  635. void DiscardVertexBuffers();
  636. // Creates, destroys static meshes
  637. IMesh *CreateStaticMesh( VertexFormat_t vertexFormat, const char *pTextureBudgetGroup, IMaterial *pMaterial = NULL );
  638. void DestroyStaticMesh( IMesh *pMesh );
  639. // Gets at the dynamic mesh (spoofs it though)
  640. IMesh *GetDynamicMesh( IMaterial *pMaterial, VertexFormat_t vertexFormat, int nHWSkinBoneCount, bool buffered,
  641. IMesh *pVertexOverride, IMesh *pIndexOverride );
  642. // -----------------------------------------------------------
  643. // ------------ New Vertex/Index Buffer interface ----------------------------
  644. // Do we need support for bForceTempMesh and bSoftwareVertexShader?
  645. // I don't think we use bSoftwareVertexShader anymore. .need to look into bForceTempMesh.
  646. IVertexBuffer *CreateVertexBuffer( ShaderBufferType_t type, VertexFormat_t fmt, int nVertexCount, const char *pBudgetGroup );
  647. IIndexBuffer *CreateIndexBuffer( ShaderBufferType_t bufferType, MaterialIndexFormat_t fmt, int nIndexCount, const char *pBudgetGroup );
  648. void DestroyVertexBuffer( IVertexBuffer * );
  649. void DestroyIndexBuffer( IIndexBuffer * );
  650. // Do we need to specify the stream here in the case of locking multiple dynamic VBs on different streams?
  651. IVertexBuffer *GetDynamicVertexBuffer( int streamID, VertexFormat_t vertexFormat, bool bBuffered = true );
  652. IIndexBuffer *GetDynamicIndexBuffer( MaterialIndexFormat_t fmt, bool bBuffered = true );
  653. void BindVertexBuffer( int streamID, IVertexBuffer *pVertexBuffer, int nOffsetInBytes, int nFirstVertex, int nVertexCount, VertexFormat_t fmt, int nRepetitions = 1 );
  654. void BindIndexBuffer( IIndexBuffer *pIndexBuffer, int nOffsetInBytes );
  655. void Draw( MaterialPrimitiveType_t primitiveType, int nFirstIndex, int nIndexCount );
  656. // ------------ End ----------------------------
  657. void RenderPassWithVertexAndIndexBuffers( void );
  658. VertexFormat_t GetCurrentVertexFormat( void ) const { return m_CurrentVertexFormat; }
  659. // Gets at the *actual* dynamic mesh
  660. IMesh* GetActualDynamicMesh( VertexFormat_t vertexFormat );
  661. IMesh *GetFlexMesh();
  662. // Computes vertex format from a list of ingredients
  663. VertexFormat_t ComputeVertexFormat( unsigned int flags,
  664. int numTexCoords, int *pTexCoordDimensions, int numBoneWeights,
  665. int userDataSize ) const;
  666. // Use fat vertices (for tools)
  667. virtual void UseFatVertices( bool bUseFat );
  668. // Returns the number of vertices we can render using the dynamic mesh
  669. virtual void GetMaxToRender( IMesh *pMesh, bool bMaxUntilFlush, int *pMaxVerts, int *pMaxIndices );
  670. virtual int GetMaxVerticesToRender( IMaterial *pMaterial );
  671. virtual int GetMaxIndicesToRender( );
  672. // Returns a vertex buffer appropriate for the flags
  673. CVertexBuffer *FindOrCreateVertexBuffer( int nDynamicBufferId, VertexFormat_t fmt );
  674. CIndexBuffer *GetDynamicIndexBuffer();
  675. // Is the mesh dynamic?
  676. bool IsDynamicMesh( IMesh *pMesh ) const;
  677. bool IsBufferedDynamicMesh( IMesh *pMesh ) const;
  678. // Is the vertex buffer dynamic?
  679. bool IsDynamicVertexBuffer( IVertexBuffer *pVertexBuffer ) const;
  680. // Is the index buffer dynamic?
  681. bool IsDynamicIndexBuffer( IIndexBuffer *pIndexBuffer ) const;
  682. // Returns the vertex size
  683. int VertexFormatSize( VertexFormat_t vertexFormat ) const
  684. {
  685. return CVertexBufferBase::VertexFormatSize( vertexFormat );
  686. }
  687. // Computes the vertex buffer pointers
  688. void ComputeVertexDescription( unsigned char *pBuffer,
  689. VertexFormat_t vertexFormat, MeshDesc_t &desc ) const;
  690. // Returns the number of buffers...
  691. int BufferCount() const
  692. {
  693. #ifdef _DEBUG
  694. return CVertexBuffer::BufferCount() + CIndexBuffer::BufferCount();
  695. #else
  696. return 0;
  697. #endif
  698. }
  699. CVertexBuffer *GetVertexIDBuffer();
  700. IVertexBuffer *GetDynamicVertexBuffer( IMaterial *pMaterial, bool buffered = true );
  701. IIndexBuffer *GetDynamicIndexBuffer( IMaterial *pMaterial, bool buffered = true );
  702. virtual void MarkUnusedVertexFields( unsigned int nFlags, int nTexCoordCount, bool *pUnusedTexCoords );
  703. int UnusedVertexFields() const { return m_nUnusedVertexFields; }
  704. int UnusedTextureCoords() const { return m_nUnusedTextureCoords; }
  705. IDirect3DVertexBuffer9 *GetZeroVertexBuffer() const { return m_pZeroVertexBuffer; }
  706. private:
  707. void SetVertexIDStreamState( );
  708. void SetColorStreamState( );
  709. void SetVertexStreamState( int nVertOffsetInBytes, int nVertexStride );
  710. void SetIndexStreamState( int firstVertexIdx );
  711. bool SetRenderState( int nVertexOffsetInBytes, int nFirstVertexIdx, VertexFormat_t vertexFormat, int nVertexStride );
  712. struct VertexBufferLookup_t
  713. {
  714. CVertexBuffer* m_pBuffer;
  715. int m_VertexSize;
  716. };
  717. void CopyStaticMeshIndexBufferToTempMeshIndexBuffer( CTempMeshDX8 *pDstIndexMesh, CMeshDX8 *pSrcIndexMesh );
  718. // Cleans up the class
  719. void CleanUp();
  720. // Creates, destroys the dynamic index
  721. void CreateDynamicIndexBuffer();
  722. void DestroyDynamicIndexBuffer();
  723. // Creates, destroys the vertexID buffer
  724. void CreateVertexIDBuffer();
  725. void DestroyVertexIDBuffer();
  726. void CreateZeroVertexBuffer();
  727. void DestroyZeroVertexBuffer();
  728. // Fills a vertexID buffer
  729. void FillVertexIDBuffer( CVertexBuffer *pVertexIDBuffer, int nCount );
  730. // The dynamic index buffer
  731. CIndexBuffer *m_pDynamicIndexBuffer;
  732. // A static vertexID buffer
  733. CVertexBuffer *m_pVertexIDBuffer;
  734. // The dynamic vertex buffers
  735. CUtlVector< VertexBufferLookup_t > m_DynamicVertexBuffers;
  736. // The buffered mesh
  737. CBufferedMeshDX8 m_BufferedMesh;
  738. // The current dynamic mesh
  739. CDynamicMeshDX8 m_DynamicMesh;
  740. CDynamicMeshDX8 m_DynamicFlexMesh;
  741. // The current dynamic vertex buffer
  742. CVertexBufferDx8 m_DynamicVertexBuffer;
  743. // The current dynamic index buffer
  744. CIndexBufferDx8 m_DynamicIndexBuffer;
  745. // The dynamic mesh temp version (for shaders that modify vertex data)
  746. CTempMeshDX8 m_DynamicTempMesh;
  747. // Am I buffering or not?
  748. bool m_BufferedMode;
  749. // Using fat vertices?
  750. bool m_bUseFatVertices;
  751. CVertexBufferDx8 *m_pCurrentVertexBuffer;
  752. VertexFormat_t m_CurrentVertexFormat;
  753. int m_pVertexBufferOffset[MAX_DX8_STREAMS];
  754. int m_pCurrentVertexStride[MAX_DX8_STREAMS];
  755. int m_pFirstVertex[MAX_DX8_STREAMS];
  756. int m_pVertexCount[MAX_DX8_STREAMS];
  757. CIndexBufferBase *m_pCurrentIndexBuffer;
  758. int m_nIndexBufferOffset;
  759. MaterialPrimitiveType_t m_PrimitiveType;
  760. int m_nFirstIndex;
  761. int m_nNumIndices;
  762. unsigned int m_nUnusedVertexFields;
  763. unsigned int m_nUnusedTextureCoords;
  764. // 4096 byte static VB containing all-zeros
  765. IDirect3DVertexBuffer9 *m_pZeroVertexBuffer;
  766. };
  767. //-----------------------------------------------------------------------------
  768. // Singleton...
  769. //-----------------------------------------------------------------------------
  770. static CMeshMgr g_MeshMgr;
  771. IMeshMgr* MeshMgr()
  772. {
  773. return &g_MeshMgr;
  774. }
  775. //-----------------------------------------------------------------------------
  776. // Tracks stream state and queued data
  777. //-----------------------------------------------------------------------------
  778. static CIndexBuffer *g_pLastIndex = NULL;
  779. static IDirect3DIndexBuffer9 *g_pLastIndexBuffer = NULL;
  780. static CVertexBuffer *g_pLastVertex = NULL;
  781. static IDirect3DVertexBuffer9 *g_pLastVertexBuffer = NULL;
  782. static int g_nLastVertOffsetInBytes = 0;
  783. static int g_nLastVertStride = 0;
  784. static int g_LastVertexIdx = -1;
  785. static CMeshDX8 *g_pLastColorMesh = NULL;
  786. static int g_nLastColorMeshVertOffsetInBytes = 0;
  787. static bool g_bUsingVertexID = false;
  788. static bool g_bFlexMeshStreamSet = false;
  789. static VertexFormat_t g_LastVertexFormat = 0;
  790. inline void D3DSetStreamSource( unsigned int streamNumber, IDirect3DVertexBuffer9 *pStreamData,
  791. unsigned int nVertexOffsetInBytes, unsigned int stride )
  792. {
  793. Dx9Device()->SetStreamSource( streamNumber, pStreamData, nVertexOffsetInBytes, stride );
  794. }
  795. //-----------------------------------------------------------------------------
  796. // Tracks stream state and queued data
  797. //-----------------------------------------------------------------------------
  798. void Unbind( IDirect3DIndexBuffer9 *pIndexBuffer )
  799. {
  800. #ifdef _X360
  801. IDirect3DIndexBuffer9 *pBoundBuffer;
  802. Dx9Device()->GetIndices( &pBoundBuffer );
  803. if ( pBoundBuffer == pIndexBuffer )
  804. {
  805. // xboxissue - cannot lock indexes set in a d3d device, clear possibly set indices
  806. Dx9Device()->SetIndices( NULL );
  807. g_pLastIndex = NULL;
  808. g_pLastIndexBuffer = NULL;
  809. }
  810. if ( pBoundBuffer )
  811. {
  812. pBoundBuffer->Release();
  813. }
  814. #endif
  815. }
  816. void Unbind( IDirect3DVertexBuffer9 *pVertexBuffer )
  817. {
  818. #ifdef _X360
  819. UINT nOffset, nStride;
  820. IDirect3DVertexBuffer9 *pBoundBuffer;
  821. for ( int i = 0; i < MAX_DX8_STREAMS; ++i )
  822. {
  823. Dx9Device()->GetStreamSource( i, &pBoundBuffer, &nOffset, &nStride );
  824. if ( pBoundBuffer == pVertexBuffer )
  825. {
  826. // xboxissue - cannot lock indexes set in a d3d device, clear possibly set indices
  827. Dx9Device()->SetStreamSource( i, 0, 0, 0 );
  828. switch ( i )
  829. {
  830. case 0:
  831. g_pLastVertex = NULL;
  832. g_pLastVertexBuffer = NULL;
  833. break;
  834. case 1:
  835. g_pLastColorMesh = NULL;
  836. g_nLastColorMeshVertOffsetInBytes = 0;
  837. break;
  838. }
  839. }
  840. if ( pBoundBuffer )
  841. {
  842. pBoundBuffer->Release();
  843. }
  844. }
  845. #endif
  846. }
  847. //-----------------------------------------------------------------------------
  848. // Helpers to count texture coordinates
  849. //-----------------------------------------------------------------------------
  850. static int NumTextureCoordinates( VertexFormat_t vertexFormat )
  851. {
  852. int nTexCoordCount = 0;
  853. for ( int i = 0; i < VERTEX_MAX_TEXTURE_COORDINATES; ++i )
  854. {
  855. if ( TexCoordSize( i, vertexFormat ) == 0 )
  856. continue;
  857. ++nTexCoordCount;
  858. }
  859. return nTexCoordCount;
  860. }
  861. //-----------------------------------------------------------------------------
  862. // Makes sure that the render state is always set next time
  863. //-----------------------------------------------------------------------------
  864. static void ResetMeshRenderState()
  865. {
  866. SafeRelease( &g_pLastIndex );
  867. g_pLastIndexBuffer = 0;
  868. g_pLastVertex = 0;
  869. g_nLastVertOffsetInBytes = 0;
  870. g_pLastColorMesh = 0;
  871. g_nLastColorMeshVertOffsetInBytes = 0;
  872. g_LastVertexIdx = -1;
  873. g_bUsingVertexID = false;
  874. g_bFlexMeshStreamSet = false;
  875. g_LastVertexFormat = 0;
  876. }
  877. //-----------------------------------------------------------------------------
  878. // Makes sure that the render state is always set next time
  879. //-----------------------------------------------------------------------------
  880. static void ResetIndexBufferRenderState()
  881. {
  882. SafeRelease( &g_pLastIndex );
  883. g_pLastIndexBuffer = 0;
  884. g_LastVertexIdx = -1;
  885. }
  886. //-----------------------------------------------------------------------------
  887. //
  888. // Index Buffer implementations begin here
  889. //
  890. //-----------------------------------------------------------------------------
  891. //-----------------------------------------------------------------------------
  892. // Globals
  893. //-----------------------------------------------------------------------------
  894. #ifdef _DEBUG
  895. int CIndexBufferDx8::s_nBufferCount = 0;
  896. #endif
  897. //-----------------------------------------------------------------------------
  898. // Constructor, destructor
  899. //-----------------------------------------------------------------------------
  900. CIndexBufferDx8::CIndexBufferDx8( ShaderBufferType_t bufferType, MaterialIndexFormat_t fmt, int nIndexCount, const char *pBudgetGroupName ) :
  901. BaseClass( pBudgetGroupName )
  902. {
  903. // Debugger();
  904. Assert( nIndexCount != 0 );
  905. // NOTE: MATERIAL_INDEX_FORMAT_UNKNOWN can't be dealt with under dx9
  906. // because format is bound at buffer creation time. What we'll do
  907. // is just arbitrarily choose to use a 16-bit index buffer of the same size
  908. if ( fmt == MATERIAL_INDEX_FORMAT_UNKNOWN )
  909. {
  910. fmt = MATERIAL_INDEX_FORMAT_16BIT;
  911. nIndexCount /= 2;
  912. }
  913. m_pIndexBuffer = NULL;
  914. m_IndexFormat = fmt;
  915. m_nBufferSize = nIndexCount * IndexSize();
  916. m_nIndexCount = nIndexCount;
  917. m_nFirstUnwrittenOffset = 0;
  918. m_bIsLocked = false;
  919. m_bIsDynamic = IsDynamicBufferType( bufferType );
  920. m_bFlush = false;
  921. #ifdef CHECK_INDICES
  922. m_pShadowIndices = NULL;
  923. #endif
  924. #ifdef VPROF_ENABLED
  925. m_nVProfFrame = -1;
  926. #endif
  927. }
  928. CIndexBufferDx8::~CIndexBufferDx8()
  929. {
  930. Free();
  931. }
  932. //-----------------------------------------------------------------------------
  933. // Returns the index size
  934. //-----------------------------------------------------------------------------
  935. inline int CIndexBufferDx8::IndexSize() const
  936. {
  937. Assert( m_IndexFormat != MATERIAL_INDEX_FORMAT_UNKNOWN );
  938. return ( m_IndexFormat == MATERIAL_INDEX_FORMAT_16BIT ) ? 2 : 4;
  939. }
  940. //-----------------------------------------------------------------------------
  941. // Creates, destroys the index buffer
  942. //-----------------------------------------------------------------------------
  943. bool CIndexBufferDx8::Allocate()
  944. {
  945. #ifdef OSX
  946. Debugger();
  947. #endif
  948. Assert( !m_pIndexBuffer );
  949. m_nFirstUnwrittenOffset = 0;
  950. // FIXME: This doesn't really work for dynamic buffers; dynamic buffers
  951. // can't have mixed-type indices in them. Bleah.
  952. D3DFORMAT format = ( m_IndexFormat == MATERIAL_INDEX_FORMAT_32BIT ) ?
  953. D3DFMT_INDEX32 : D3DFMT_INDEX16;
  954. DWORD usage = D3DUSAGE_WRITEONLY;
  955. if ( m_bIsDynamic )
  956. {
  957. usage |= D3DUSAGE_DYNAMIC;
  958. }
  959. HRESULT hr = Dx9Device()->CreateIndexBuffer(
  960. m_nBufferSize, usage, format, D3DPOOL_DEFAULT, &m_pIndexBuffer, NULL );
  961. #if !defined( _X360 )
  962. if ( ( hr == D3DERR_OUTOFVIDEOMEMORY ) || ( hr == E_OUTOFMEMORY ) )
  963. {
  964. // Don't have the memory for this. Try flushing all managed resources
  965. // out of vid mem and try again.
  966. // FIXME: need to record this
  967. Dx9Device()->EvictManagedResources();
  968. hr = Dx9Device()->CreateIndexBuffer(
  969. m_nBufferSize, usage, format, D3DPOOL_DEFAULT, &m_pIndexBuffer, NULL );
  970. }
  971. #endif // !X360
  972. if ( FAILED(hr) || ( m_pIndexBuffer == NULL ) )
  973. {
  974. Warning( "CIndexBufferDx8::Allocate: CreateIndexBuffer failed!\n" );
  975. return false;
  976. }
  977. if ( !m_bIsDynamic )
  978. {
  979. VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_STATIC_INDEX_BUFFER,
  980. COUNTER_GROUP_TEXTURE_GLOBAL, m_nBufferSize );
  981. }
  982. else
  983. {
  984. VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_DYNAMIC_INDEX_BUFFER,
  985. COUNTER_GROUP_TEXTURE_GLOBAL, m_nBufferSize );
  986. }
  987. #ifdef CHECK_INDICES
  988. Assert ( !m_pShadowIndices );
  989. m_pShadowIndices = new unsigned char[ m_nBufferSize ];
  990. memset( m_pShadowIndices, 0xFF, m_nBufferSize );
  991. #endif // CHECK_INDICES
  992. #ifdef _DEBUG
  993. ++s_nBufferCount;
  994. #endif
  995. return true;
  996. }
  997. void CIndexBufferDx8::Free()
  998. {
  999. // FIXME: Unlock(0);
  1000. if ( m_pIndexBuffer )
  1001. {
  1002. #ifdef _DEBUG
  1003. --s_nBufferCount;
  1004. #endif
  1005. m_pIndexBuffer->Release();
  1006. m_pIndexBuffer = NULL;
  1007. if ( !m_bIsDynamic )
  1008. {
  1009. VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_STATIC_INDEX_BUFFER,
  1010. COUNTER_GROUP_TEXTURE_GLOBAL, - m_nBufferSize );
  1011. }
  1012. else
  1013. {
  1014. VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_global_" TEXTURE_GROUP_DYNAMIC_INDEX_BUFFER,
  1015. COUNTER_GROUP_TEXTURE_GLOBAL, - m_nBufferSize );
  1016. }
  1017. }
  1018. #ifdef CHECK_INDICES
  1019. if ( m_pShadowIndices )
  1020. {
  1021. delete[] m_pShadowIndices;
  1022. m_pShadowIndices = NULL;
  1023. }
  1024. #endif // CHECK_INDICES
  1025. }
  1026. //-----------------------------------------------------------------------------
  1027. // Index buffer information
  1028. //-----------------------------------------------------------------------------
  1029. int CIndexBufferDx8::IndexCount( ) const
  1030. {
  1031. Assert( !m_bIsDynamic );
  1032. return m_nIndexCount;
  1033. }
  1034. MaterialIndexFormat_t CIndexBufferDx8::IndexFormat() const
  1035. {
  1036. Assert( !m_bIsDynamic );
  1037. return m_IndexFormat;
  1038. }
  1039. //-----------------------------------------------------------------------------
  1040. // Returns true if the buffer is dynamic
  1041. //-----------------------------------------------------------------------------
  1042. bool CIndexBufferDx8::IsDynamic() const
  1043. {
  1044. return m_bIsDynamic;
  1045. }
  1046. //-----------------------------------------------------------------------------
  1047. // Only used by dynamic buffers, indicates the next lock should perform a discard.
  1048. //-----------------------------------------------------------------------------
  1049. void CIndexBufferDx8::Flush()
  1050. {
  1051. // This strange-looking line makes a flush only occur if the buffer is dynamic.
  1052. m_bFlush = m_bIsDynamic;
  1053. }
  1054. //-----------------------------------------------------------------------------
  1055. // Returns the D3D buffer
  1056. //-----------------------------------------------------------------------------
  1057. IDirect3DIndexBuffer9* CIndexBufferDx8::GetDx9Buffer()
  1058. {
  1059. return m_pIndexBuffer;
  1060. }
  1061. //-----------------------------------------------------------------------------
  1062. // Returns a shadowed index, for validation
  1063. //-----------------------------------------------------------------------------
  1064. #ifdef CHECK_INDICES
  1065. unsigned short CIndexBufferDx8::GetShadowIndex( int i ) const
  1066. {
  1067. Assert( i >= 0 && i < m_nIndexCount );
  1068. Assert( m_IndexFormat == MATERIAL_INDEX_FORMAT_16BIT );
  1069. return *(unsigned short*)( &m_pShadowIndices[ i * IndexSize() ] );
  1070. }
  1071. #endif // CHECK_INDICES
  1072. //-----------------------------------------------------------------------------
  1073. // Used to measure how much static buffer memory is touched each frame
  1074. //-----------------------------------------------------------------------------
  1075. void CIndexBufferDx8::HandlePerFrameTextureStats( int nFrame )
  1076. {
  1077. #ifdef VPROF_ENABLED
  1078. if ( m_nVProfFrame != nFrame && !m_bIsDynamic )
  1079. {
  1080. m_nVProfFrame = nFrame;
  1081. VPROF_INCREMENT_GROUP_COUNTER( "TexGroup_frame_" TEXTURE_GROUP_STATIC_INDEX_BUFFER,
  1082. COUNTER_GROUP_TEXTURE_PER_FRAME, m_nBufferSize );
  1083. }
  1084. #endif
  1085. }
  1086. //-----------------------------------------------------------------------------
  1087. // Casts a dynamic buffer to be a particular index type
  1088. //-----------------------------------------------------------------------------
  1089. void CIndexBufferDx8::BeginCastBuffer( MaterialIndexFormat_t format )
  1090. {
  1091. // NOTE: This should have no effect under Dx9, since we can't recast index buffers.
  1092. Assert( format != MATERIAL_INDEX_FORMAT_UNKNOWN );
  1093. Assert( m_bIsDynamic && ( m_IndexFormat == format ) );
  1094. }
  1095. void CIndexBufferDx8::EndCastBuffer( )
  1096. {
  1097. // NOTE: This should have no effect under Dx9, since we can't recast index buffers.
  1098. }
  1099. int CIndexBufferDx8::GetRoomRemaining() const
  1100. {
  1101. return ( m_nBufferSize - m_nFirstUnwrittenOffset ) / IndexSize();
  1102. }
  1103. //-----------------------------------------------------------------------------
  1104. // Locks/unlocks the index buffer
  1105. //-----------------------------------------------------------------------------
  1106. bool CIndexBufferDx8::Lock( int nMaxIndexCount, bool bAppend, IndexDesc_t &desc )
  1107. {
  1108. Assert( !m_bIsLocked && ( nMaxIndexCount != 0 ) && ( nMaxIndexCount <= m_nIndexCount ) );
  1109. Assert( m_IndexFormat != MATERIAL_INDEX_FORMAT_UNKNOWN );
  1110. // FIXME: Why do we need to sync matrices now?
  1111. ShaderUtil()->SyncMatrices();
  1112. g_ShaderMutex.Lock();
  1113. VPROF( "CIndexBufferX8::Lock" );
  1114. void *pLockedData = NULL;
  1115. HRESULT hr;
  1116. int nMemoryRequired;
  1117. bool bHasEnoughMemory;
  1118. UINT nLockFlags;
  1119. // This can happen if the buffer was locked but a type wasn't bound
  1120. if ( m_IndexFormat == MATERIAL_INDEX_FORMAT_UNKNOWN )
  1121. goto indexBufferLockFailed;
  1122. // Just give the app crap buffers to fill up while we're suppressed...
  1123. if ( g_pShaderDeviceDx8->IsDeactivated() || ( nMaxIndexCount == 0 ) )
  1124. goto indexBufferLockFailed;
  1125. // Did we ask for something too large?
  1126. if ( nMaxIndexCount > m_nIndexCount )
  1127. {
  1128. Warning( "Too many indices for index buffer. . tell a programmer (%d>%d)\n", nMaxIndexCount, m_nIndexCount );
  1129. goto indexBufferLockFailed;
  1130. }
  1131. // We might not have a buffer owing to alt-tab type stuff
  1132. if ( !m_pIndexBuffer )
  1133. {
  1134. if ( !Allocate() )
  1135. goto indexBufferLockFailed;
  1136. }
  1137. // Check to see if we have enough memory
  1138. nMemoryRequired = nMaxIndexCount * IndexSize();
  1139. bHasEnoughMemory = ( m_nFirstUnwrittenOffset + nMemoryRequired <= m_nBufferSize );
  1140. nLockFlags = D3DLOCK_NOSYSLOCK;
  1141. if ( bAppend )
  1142. {
  1143. // Can't have the first lock after a flush be an appending lock
  1144. Assert( !m_bFlush );
  1145. // If we're appending and we don't have enough room, then puke!
  1146. if ( !bHasEnoughMemory || m_bFlush )
  1147. goto indexBufferLockFailed;
  1148. nLockFlags |= ( m_nFirstUnwrittenOffset == 0 ) ? D3DLOCK_DISCARD : D3DLOCK_NOOVERWRITE;
  1149. }
  1150. else
  1151. {
  1152. // If we're not appending, no overwrite unless we don't have enough room
  1153. // If we're a static buffer, always discard if we're not appending
  1154. if ( !m_bFlush && bHasEnoughMemory && m_bIsDynamic )
  1155. {
  1156. nLockFlags |= ( m_nFirstUnwrittenOffset == 0 ) ? D3DLOCK_DISCARD : D3DLOCK_NOOVERWRITE;
  1157. }
  1158. else
  1159. {
  1160. if ( m_bIsDynamic )
  1161. {
  1162. nLockFlags |= D3DLOCK_DISCARD;
  1163. }
  1164. m_nFirstUnwrittenOffset = 0;
  1165. m_bFlush = false;
  1166. }
  1167. }
  1168. #if !defined( _X360 )
  1169. hr = m_pIndexBuffer->Lock( m_nFirstUnwrittenOffset, nMemoryRequired, &pLockedData, nLockFlags );
  1170. #else
  1171. hr = m_pIndexBuffer->Lock( 0, 0, &pLockedData, nLockFlags );
  1172. pLockedData = ( ( unsigned char * )pLockedData + m_nFirstUnwrittenOffset );
  1173. #endif
  1174. if ( FAILED( hr ) )
  1175. {
  1176. Warning( "Failed to lock index buffer in CIndexBufferDx8::LockIndexBuffer\n" );
  1177. goto indexBufferLockFailed;
  1178. }
  1179. desc.m_pIndices = (unsigned short*)( pLockedData );
  1180. desc.m_nIndexSize = IndexSize() >> 1;
  1181. if ( g_pHardwareConfig->SupportsStreamOffset() )
  1182. {
  1183. desc.m_nFirstIndex = 0;
  1184. desc.m_nOffset = m_nFirstUnwrittenOffset;
  1185. }
  1186. else
  1187. {
  1188. desc.m_nFirstIndex = m_nFirstUnwrittenOffset / IndexSize();
  1189. Assert( (int)( desc.m_nFirstIndex * IndexSize() ) == m_nFirstUnwrittenOffset );
  1190. desc.m_nOffset = 0;
  1191. }
  1192. m_bIsLocked = true;
  1193. #ifdef CHECK_INDICES
  1194. m_nLockIndexBufferSize = nMemoryRequired;
  1195. m_pLockIndexBuffer = desc.m_pIndices;
  1196. m_nLockIndexOffset = m_nFirstUnwrittenOffset;
  1197. #endif // CHECK_INDICES
  1198. return true;
  1199. indexBufferLockFailed:
  1200. g_ShaderMutex.Unlock();
  1201. // Set up a bogus index descriptor
  1202. desc.m_pIndices = g_nScratchIndexBuffer;
  1203. desc.m_nIndexSize = 0;
  1204. desc.m_nFirstIndex = 0;
  1205. desc.m_nOffset = 0;
  1206. return false;
  1207. }
  1208. void CIndexBufferDx8::Unlock( int nWrittenIndexCount, IndexDesc_t &desc )
  1209. {
  1210. Assert( nWrittenIndexCount <= m_nIndexCount );
  1211. // NOTE: This can happen if another application finishes
  1212. // initializing during the construction of a mesh
  1213. if ( !m_bIsLocked )
  1214. return;
  1215. #ifdef CHECK_INDICES
  1216. memcpy( (unsigned char*)m_pShadowIndices + m_nLockIndexOffset, m_pLockIndexBuffer, nWrittenIndexCount * IndexSize() );
  1217. #endif // CHECK_INDICES
  1218. if ( m_pIndexBuffer )
  1219. {
  1220. m_pIndexBuffer->Unlock();
  1221. }
  1222. m_nFirstUnwrittenOffset += nWrittenIndexCount * IndexSize();
  1223. m_bIsLocked = false;
  1224. g_ShaderMutex.Unlock();
  1225. }
  1226. //-----------------------------------------------------------------------------
  1227. //
  1228. // Vertex Buffer implementations begin here
  1229. //
  1230. //-----------------------------------------------------------------------------
  1231. //-----------------------------------------------------------------------------
  1232. // globals
  1233. //-----------------------------------------------------------------------------
  1234. #ifdef _DEBUG
  1235. int CVertexBufferDx8::s_nBufferCount = 0;
  1236. #endif
  1237. //-----------------------------------------------------------------------------
  1238. // constructor
  1239. //-----------------------------------------------------------------------------
  1240. CVertexBufferDx8::CVertexBufferDx8( ShaderBufferType_t type, VertexFormat_t fmt, int nVertexCount, const char *pBudgetGroupName ) :
  1241. BaseClass( pBudgetGroupName )
  1242. {
  1243. // Debugger();
  1244. Assert( nVertexCount != 0 );
  1245. m_pVertexBuffer = NULL;
  1246. m_VertexFormat = fmt;
  1247. m_nVertexCount = ( fmt == VERTEX_FORMAT_UNKNOWN ) ? 0 : nVertexCount;
  1248. m_nBufferSize = ( fmt == VERTEX_FORMAT_UNKNOWN ) ? nVertexCount : nVertexCount * VertexSize();
  1249. m_nFirstUnwrittenOffset = 0;
  1250. m_bIsLocked = false;
  1251. m_bIsDynamic = ( type == SHADER_BUFFER_TYPE_DYNAMIC ) || ( type == SHADER_BUFFER_TYPE_DYNAMIC_TEMP );
  1252. m_bFlush = false;
  1253. #ifdef VPROF_ENABLED
  1254. if ( !m_bIsDynamic )
  1255. {
  1256. char name[256];
  1257. V_strcpy_safe( name, "TexGroup_global_" );
  1258. V_strcat_safe( name, pBudgetGroupName, sizeof(name) );
  1259. m_pGlobalCounter = g_VProfCurrentProfile.FindOrCreateCounter( name, COUNTER_GROUP_TEXTURE_GLOBAL );
  1260. V_strcpy_safe( name, "TexGroup_frame_" );
  1261. V_strcat_safe( name, pBudgetGroupName, sizeof(name) );
  1262. m_pFrameCounter = g_VProfCurrentProfile.FindOrCreateCounter( name, COUNTER_GROUP_TEXTURE_PER_FRAME );
  1263. }
  1264. else
  1265. {
  1266. m_pGlobalCounter = g_VProfCurrentProfile.FindOrCreateCounter( "TexGroup_global_" TEXTURE_GROUP_DYNAMIC_VERTEX_BUFFER, COUNTER_GROUP_TEXTURE_GLOBAL );
  1267. m_pFrameCounter = NULL;
  1268. }
  1269. m_nVProfFrame = -1;
  1270. #endif
  1271. }
  1272. CVertexBufferDx8::~CVertexBufferDx8()
  1273. {
  1274. Free();
  1275. }
  1276. //-----------------------------------------------------------------------------
  1277. // Returns the vertex size
  1278. //-----------------------------------------------------------------------------
  1279. inline int CVertexBufferDx8::VertexSize() const
  1280. {
  1281. Assert( m_VertexFormat != VERTEX_FORMAT_UNKNOWN );
  1282. return VertexFormatSize( m_VertexFormat );
  1283. }
  1284. //-----------------------------------------------------------------------------
  1285. // Creates, destroys the vertex buffer
  1286. //-----------------------------------------------------------------------------
  1287. bool CVertexBufferDx8::Allocate()
  1288. {
  1289. Assert( !m_pVertexBuffer );
  1290. m_nFirstUnwrittenOffset = 0;
  1291. D3DPOOL pool = D3DPOOL_MANAGED;
  1292. #if defined(IS_WINDOWS_PC) && defined(SHADERAPIDX9)
  1293. extern bool g_ShaderDeviceUsingD3D9Ex;
  1294. if ( g_ShaderDeviceUsingD3D9Ex )
  1295. {
  1296. pool = D3DPOOL_DEFAULT;
  1297. }
  1298. #endif
  1299. DWORD usage = D3DUSAGE_WRITEONLY;
  1300. if ( m_bIsDynamic )
  1301. {
  1302. usage |= D3DUSAGE_DYNAMIC;
  1303. pool = D3DPOOL_DEFAULT;
  1304. // Dynamic meshes should never be compressed (slows down writing to them)
  1305. Assert( CompressionType( GetVertexFormat() ) == VERTEX_COMPRESSION_NONE );
  1306. }
  1307. HRESULT hr = Dx9Device()->CreateVertexBuffer(
  1308. m_nBufferSize, usage, 0, pool, &m_pVertexBuffer, NULL );
  1309. #if !defined( _X360 )
  1310. if ( ( hr == D3DERR_OUTOFVIDEOMEMORY ) || ( hr == E_OUTOFMEMORY ) )
  1311. {
  1312. // Don't have the memory for this. Try flushing all managed resources
  1313. // out of vid mem and try again.
  1314. // FIXME: need to record this
  1315. Dx9Device()->EvictManagedResources();
  1316. hr = Dx9Device()->CreateVertexBuffer(
  1317. m_nBufferSize, usage, 0, pool, &m_pVertexBuffer, NULL );
  1318. }
  1319. #endif // !X360
  1320. if ( FAILED(hr) || ( m_pVertexBuffer == NULL ) )
  1321. {
  1322. Warning( "CVertexBufferDx8::Allocate: CreateVertexBuffer failed!\n" );
  1323. return false;
  1324. }
  1325. // Track VB allocations
  1326. g_VBAllocTracker->CountVB( m_pVertexBuffer, m_bIsDynamic, m_nBufferSize, VertexSize(), GetVertexFormat() );
  1327. #ifdef VPROF_ENABLED
  1328. if ( IsX360() || !m_bIsDynamic )
  1329. {
  1330. Assert( m_pGlobalCounter );
  1331. *m_pGlobalCounter += m_nBufferSize;
  1332. }
  1333. #endif
  1334. #ifdef _DEBUG
  1335. ++s_nBufferCount;
  1336. #endif
  1337. return true;
  1338. }
  1339. void CVertexBufferDx8::Free()
  1340. {
  1341. // FIXME: Unlock(0);
  1342. if ( m_pVertexBuffer )
  1343. {
  1344. #ifdef _DEBUG
  1345. --s_nBufferCount;
  1346. #endif
  1347. // Track VB allocations
  1348. g_VBAllocTracker->UnCountVB( m_pVertexBuffer );
  1349. #ifdef VPROF_ENABLED
  1350. if ( IsX360() || !m_bIsDynamic )
  1351. {
  1352. Assert( m_pGlobalCounter );
  1353. *m_pGlobalCounter -= m_nBufferSize;
  1354. }
  1355. #endif
  1356. m_pVertexBuffer->Release();
  1357. m_pVertexBuffer = NULL;
  1358. }
  1359. }
  1360. //-----------------------------------------------------------------------------
  1361. // Vertex buffer information
  1362. //-----------------------------------------------------------------------------
  1363. int CVertexBufferDx8::VertexCount() const
  1364. {
  1365. Assert( !m_bIsDynamic );
  1366. return m_nVertexCount;
  1367. }
  1368. VertexFormat_t CVertexBufferDx8::GetVertexFormat() const
  1369. {
  1370. Assert( !m_bIsDynamic );
  1371. return m_VertexFormat;
  1372. }
  1373. //-----------------------------------------------------------------------------
  1374. // Returns true if the buffer is dynamic
  1375. //-----------------------------------------------------------------------------
  1376. bool CVertexBufferDx8::IsDynamic() const
  1377. {
  1378. return m_bIsDynamic;
  1379. }
  1380. //-----------------------------------------------------------------------------
  1381. // Only used by dynamic buffers, indicates the next lock should perform a discard.
  1382. //-----------------------------------------------------------------------------
  1383. void CVertexBufferDx8::Flush()
  1384. {
  1385. // This strange-looking line makes a flush only occur if the buffer is dynamic.
  1386. m_bFlush = m_bIsDynamic;
  1387. }
  1388. //-----------------------------------------------------------------------------
  1389. // Returns the D3D buffer
  1390. //-----------------------------------------------------------------------------
  1391. IDirect3DVertexBuffer9* CVertexBufferDx8::GetDx9Buffer()
  1392. {
  1393. return m_pVertexBuffer;
  1394. }
  1395. //-----------------------------------------------------------------------------
  1396. // Casts a dynamic buffer to be a particular vertex type
  1397. //-----------------------------------------------------------------------------
  1398. void CVertexBufferDx8::BeginCastBuffer( VertexFormat_t format )
  1399. {
  1400. Assert( format != MATERIAL_INDEX_FORMAT_UNKNOWN );
  1401. Assert( m_bIsDynamic && ( m_VertexFormat == 0 || m_VertexFormat == format ) );
  1402. if ( !m_bIsDynamic )
  1403. return;
  1404. m_VertexFormat = format;
  1405. int nVertexSize = VertexSize();
  1406. m_nVertexCount = m_nBufferSize / nVertexSize;
  1407. // snap current position up to the next position based on expected size
  1408. // so append can safely guarantee nooverwrite regardless of a format growth or shrinkage
  1409. if ( !g_pHardwareConfig->SupportsStreamOffset() )
  1410. {
  1411. m_nFirstUnwrittenOffset = ( m_nFirstUnwrittenOffset + nVertexSize - 1 ) / nVertexSize;
  1412. m_nFirstUnwrittenOffset *= nVertexSize;
  1413. if ( m_nFirstUnwrittenOffset > m_nBufferSize )
  1414. {
  1415. m_nFirstUnwrittenOffset = m_nBufferSize;
  1416. }
  1417. }
  1418. }
  1419. void CVertexBufferDx8::EndCastBuffer( )
  1420. {
  1421. Assert( m_bIsDynamic && m_VertexFormat != 0 );
  1422. if ( !m_bIsDynamic )
  1423. return;
  1424. m_VertexFormat = 0;
  1425. m_nVertexCount = 0;
  1426. }
  1427. //-----------------------------------------------------------------------------
  1428. // Returns the number of vertices we can still write into the buffer
  1429. //-----------------------------------------------------------------------------
  1430. int CVertexBufferDx8::GetRoomRemaining() const
  1431. {
  1432. return ( m_nBufferSize - m_nFirstUnwrittenOffset ) / VertexSize();
  1433. }
  1434. //-----------------------------------------------------------------------------
  1435. // Locks/unlocks the vertex buffer mesh
  1436. //-----------------------------------------------------------------------------
  1437. bool CVertexBufferDx8::Lock( int nMaxVertexCount, bool bAppend, VertexDesc_t &desc )
  1438. {
  1439. Assert( !m_bIsLocked && ( nMaxVertexCount != 0 ) && ( nMaxVertexCount <= m_nVertexCount ) );
  1440. Assert( m_VertexFormat != VERTEX_FORMAT_UNKNOWN );
  1441. // FIXME: Why do we need to sync matrices now?
  1442. ShaderUtil()->SyncMatrices();
  1443. g_ShaderMutex.Lock();
  1444. VPROF( "CVertexBufferDx8::Lock" );
  1445. void *pLockedData = NULL;
  1446. HRESULT hr;
  1447. int nMemoryRequired;
  1448. bool bHasEnoughMemory;
  1449. UINT nLockFlags;
  1450. // This can happen if the buffer was locked but a type wasn't bound
  1451. if ( m_VertexFormat == VERTEX_FORMAT_UNKNOWN )
  1452. goto vertexBufferLockFailed;
  1453. // Just give the app crap buffers to fill up while we're suppressed...
  1454. if ( g_pShaderDeviceDx8->IsDeactivated() || ( nMaxVertexCount == 0 ) )
  1455. goto vertexBufferLockFailed;
  1456. // Did we ask for something too large?
  1457. if ( nMaxVertexCount > m_nVertexCount )
  1458. {
  1459. Warning( "Too many vertices for vertex buffer. . tell a programmer (%d>%d)\n", nMaxVertexCount, m_nVertexCount );
  1460. goto vertexBufferLockFailed;
  1461. }
  1462. // We might not have a buffer owing to alt-tab type stuff
  1463. if ( !m_pVertexBuffer )
  1464. {
  1465. if ( !Allocate() )
  1466. goto vertexBufferLockFailed;
  1467. }
  1468. // Check to see if we have enough memory
  1469. nMemoryRequired = nMaxVertexCount * VertexSize();
  1470. bHasEnoughMemory = ( m_nFirstUnwrittenOffset + nMemoryRequired <= m_nBufferSize );
  1471. nLockFlags = D3DLOCK_NOSYSLOCK;
  1472. if ( bAppend )
  1473. {
  1474. // Can't have the first lock after a flush be an appending lock
  1475. Assert( !m_bFlush );
  1476. // If we're appending and we don't have enough room, then puke!
  1477. if ( !bHasEnoughMemory || m_bFlush )
  1478. goto vertexBufferLockFailed;
  1479. nLockFlags |= ( m_nFirstUnwrittenOffset == 0 ) ? D3DLOCK_DISCARD : D3DLOCK_NOOVERWRITE;
  1480. }
  1481. else
  1482. {
  1483. // If we're not appending, no overwrite unless we don't have enough room
  1484. // If we're a static buffer, always discard if we're not appending
  1485. if ( !m_bFlush && bHasEnoughMemory && m_bIsDynamic )
  1486. {
  1487. nLockFlags |= ( m_nFirstUnwrittenOffset == 0 ) ? D3DLOCK_DISCARD : D3DLOCK_NOOVERWRITE;
  1488. }
  1489. else
  1490. {
  1491. if ( m_bIsDynamic )
  1492. {
  1493. nLockFlags |= D3DLOCK_DISCARD;
  1494. }
  1495. m_nFirstUnwrittenOffset = 0;
  1496. m_bFlush = false;
  1497. }
  1498. }
  1499. #if !defined( _X360 )
  1500. hr = m_pVertexBuffer->Lock( m_nFirstUnwrittenOffset, nMemoryRequired, &pLockedData, nLockFlags );
  1501. #else
  1502. hr = m_pVertexBuffer->Lock( 0, 0, &pLockedData, nLockFlags );
  1503. pLockedData = (unsigned char*)pLockedData + m_nFirstUnwrittenOffset;
  1504. #endif
  1505. if ( FAILED( hr ) )
  1506. {
  1507. // Check if paged pool is in critical state ( < 5% free )
  1508. PAGED_POOL_INFO_t ppi;
  1509. if ( ( SYSCALL_SUCCESS == Plat_GetPagedPoolInfo( &ppi ) ) &&
  1510. ( ( ppi.numPagesFree * 20 ) < ( ppi.numPagesUsed + ppi.numPagesFree ) ) )
  1511. {
  1512. Error( "Out of OS Paged Pool Memory! For more information, please see\nhttp://support.steampowered.com/cgi-bin/steampowered.cfg/php/enduser/std_adp.php?p_faqid=150\n" );
  1513. }
  1514. else
  1515. {
  1516. Warning( "Failed to lock vertex buffer in CVertexBufferDx8::Lock\n" );
  1517. }
  1518. goto vertexBufferLockFailed;
  1519. }
  1520. ComputeVertexDescription( (unsigned char*)pLockedData, m_VertexFormat, desc );
  1521. if ( g_pHardwareConfig->SupportsStreamOffset() )
  1522. {
  1523. desc.m_nFirstVertex = 0;
  1524. desc.m_nOffset = m_nFirstUnwrittenOffset;
  1525. }
  1526. else
  1527. {
  1528. desc.m_nFirstVertex = m_nFirstUnwrittenOffset / VertexSize();
  1529. desc.m_nOffset = 0;
  1530. Assert( m_nFirstUnwrittenOffset == VertexSize() * desc.m_nFirstVertex );
  1531. }
  1532. m_bIsLocked = true;
  1533. return true;
  1534. vertexBufferLockFailed:
  1535. ComputeVertexDescription( 0, 0, desc );
  1536. desc.m_nFirstVertex = 0;
  1537. desc.m_nOffset = 0;
  1538. return false;
  1539. }
  1540. void CVertexBufferDx8::Unlock( int nWrittenVertexCount, VertexDesc_t &desc )
  1541. {
  1542. Assert( nWrittenVertexCount <= m_nVertexCount );
  1543. // NOTE: This can happen if another application finishes
  1544. // initializing during the construction of a mesh
  1545. if ( !m_bIsLocked )
  1546. return;
  1547. if ( m_pVertexBuffer )
  1548. {
  1549. m_pVertexBuffer->Unlock();
  1550. }
  1551. m_nFirstUnwrittenOffset += nWrittenVertexCount * VertexSize();
  1552. m_bIsLocked = false;
  1553. g_ShaderMutex.Unlock();
  1554. }
  1555. //-----------------------------------------------------------------------------
  1556. // Used to measure how much static buffer memory is touched each frame
  1557. //-----------------------------------------------------------------------------
  1558. void CVertexBufferDx8::HandlePerFrameTextureStats( int nFrame )
  1559. {
  1560. #ifdef VPROF_ENABLED
  1561. if ( m_nVProfFrame != nFrame && !m_bIsDynamic )
  1562. {
  1563. m_nVProfFrame = nFrame;
  1564. m_pFrameCounter += m_nBufferSize;
  1565. }
  1566. #endif
  1567. }
  1568. //-----------------------------------------------------------------------------
  1569. // Helpers with meshdescs...
  1570. //-----------------------------------------------------------------------------
  1571. // FIXME: add compression-agnostic read-accessors (which decompress and return by value, checking desc.m_CompressionType)
  1572. inline D3DXVECTOR3 &Position( MeshDesc_t const &desc, int vert )
  1573. {
  1574. return *(D3DXVECTOR3*)((unsigned char*)desc.m_pPosition + vert * desc.m_VertexSize_Position );
  1575. }
  1576. inline float Wrinkle( MeshDesc_t const &desc, int vert )
  1577. {
  1578. return *(float*)((unsigned char*)desc.m_pWrinkle + vert * desc.m_VertexSize_Wrinkle );
  1579. }
  1580. inline D3DXVECTOR3 &BoneWeight( MeshDesc_t const &desc, int vert )
  1581. {
  1582. Assert( desc.m_CompressionType == VERTEX_COMPRESSION_NONE );
  1583. return *(D3DXVECTOR3*)((unsigned char*)desc.m_pBoneWeight + vert * desc.m_VertexSize_BoneWeight );
  1584. }
  1585. inline unsigned char *BoneIndex( MeshDesc_t const &desc, int vert )
  1586. {
  1587. return desc.m_pBoneMatrixIndex + vert * desc.m_VertexSize_BoneMatrixIndex;
  1588. }
  1589. inline D3DXVECTOR3 &Normal( MeshDesc_t const &desc, int vert )
  1590. {
  1591. Assert( desc.m_CompressionType == VERTEX_COMPRESSION_NONE );
  1592. return *(D3DXVECTOR3*)((unsigned char*)desc.m_pNormal + vert * desc.m_VertexSize_Normal );
  1593. }
  1594. inline unsigned char *Color( MeshDesc_t const &desc, int vert )
  1595. {
  1596. return desc.m_pColor + vert * desc.m_VertexSize_Color;
  1597. }
  1598. inline D3DXVECTOR2 &TexCoord( MeshDesc_t const &desc, int vert, int stage )
  1599. {
  1600. return *(D3DXVECTOR2*)((unsigned char*)desc.m_pTexCoord[stage] + vert * desc.m_VertexSize_TexCoord[stage] );
  1601. }
  1602. inline D3DXVECTOR3 &TangentS( MeshDesc_t const &desc, int vert )
  1603. {
  1604. return *(D3DXVECTOR3*)((unsigned char*)desc.m_pTangentS + vert * desc.m_VertexSize_TangentS );
  1605. }
  1606. inline D3DXVECTOR3 &TangentT( MeshDesc_t const &desc, int vert )
  1607. {
  1608. return *(D3DXVECTOR3*)((unsigned char*)desc.m_pTangentT + vert * desc.m_VertexSize_TangentT );
  1609. }
  1610. //-----------------------------------------------------------------------------
  1611. //
  1612. // Base mesh
  1613. //
  1614. //-----------------------------------------------------------------------------
  1615. //-----------------------------------------------------------------------------
  1616. // constructor, destructor
  1617. //-----------------------------------------------------------------------------
  1618. CBaseMeshDX8::CBaseMeshDX8() : m_VertexFormat(0)
  1619. {
  1620. m_bMeshLocked = false;
  1621. #ifdef DBGFLAG_ASSERT
  1622. m_IsDrawing = false;
  1623. m_pMaterial = 0;
  1624. #endif
  1625. }
  1626. CBaseMeshDX8::~CBaseMeshDX8()
  1627. {
  1628. }
  1629. //-----------------------------------------------------------------------------
  1630. // For debugging...
  1631. //-----------------------------------------------------------------------------
  1632. bool CBaseMeshDX8::DebugTrace() const
  1633. {
  1634. #ifdef _DEBUG
  1635. if (m_pMaterial)
  1636. return m_pMaterial->PerformDebugTrace();
  1637. #endif
  1638. return false;
  1639. }
  1640. void CBaseMeshDX8::SetMaterial( IMaterial *pMaterial )
  1641. {
  1642. #ifdef DBGFLAG_ASSERT
  1643. m_pMaterial = static_cast<IMaterialInternal *>(pMaterial);
  1644. #endif
  1645. }
  1646. //-----------------------------------------------------------------------------
  1647. // Sets, gets the vertex format
  1648. //-----------------------------------------------------------------------------
  1649. void CBaseMeshDX8::SetVertexFormat( VertexFormat_t format )
  1650. {
  1651. m_VertexFormat = format;
  1652. }
  1653. VertexFormat_t CBaseMeshDX8::GetVertexFormat() const
  1654. {
  1655. return m_VertexFormat;
  1656. }
  1657. //-----------------------------------------------------------------------------
  1658. // Sets/gets the morph format
  1659. //-----------------------------------------------------------------------------
  1660. void CBaseMeshDX8::SetMorphFormat( MorphFormat_t format )
  1661. {
  1662. m_MorphFormat = format;
  1663. }
  1664. MorphFormat_t CBaseMeshDX8::GetMorphFormat() const
  1665. {
  1666. return m_MorphFormat;
  1667. }
  1668. //-----------------------------------------------------------------------------
  1669. // Am I using morph data?
  1670. //-----------------------------------------------------------------------------
  1671. bool CBaseMeshDX8::IsUsingMorphData() const
  1672. {
  1673. LOCK_SHADERAPI();
  1674. // We're not using a morph unless the bound morph is a superset of what the rendermesh needs
  1675. MorphFormat_t morphFormat = GetMorphFormat();
  1676. if ( !morphFormat )
  1677. return false;
  1678. return ( ( morphFormat & ShaderUtil()->GetBoundMorphFormat() ) == morphFormat );
  1679. }
  1680. //-----------------------------------------------------------------------------
  1681. // Do I need to reset the vertex format?
  1682. //-----------------------------------------------------------------------------
  1683. bool CBaseMeshDX8::NeedsVertexFormatReset( VertexFormat_t fmt ) const
  1684. {
  1685. return m_VertexFormat != fmt;
  1686. }
  1687. //-----------------------------------------------------------------------------
  1688. // Do I have enough room?
  1689. //-----------------------------------------------------------------------------
  1690. bool CBaseMeshDX8::HasEnoughRoom( int nVertexCount, int nIndexCount ) const
  1691. {
  1692. // by default, we do
  1693. return true;
  1694. }
  1695. //-----------------------------------------------------------------------------
  1696. // Estimate the memory used
  1697. //-----------------------------------------------------------------------------
  1698. unsigned CBaseMeshDX8::ComputeMemoryUsed()
  1699. {
  1700. unsigned size = 0;
  1701. if ( GetVertexBuffer() )
  1702. {
  1703. size += GetVertexBuffer()->VertexCount() * GetVertexBuffer()->VertexSize();
  1704. }
  1705. if ( GetIndexBuffer() )
  1706. {
  1707. size += GetIndexBuffer()->IndexCount() * GetIndexBuffer()->IndexSize();
  1708. }
  1709. return size;
  1710. }
  1711. //-----------------------------------------------------------------------------
  1712. // Locks mesh for modifying
  1713. //-----------------------------------------------------------------------------
  1714. void CBaseMeshDX8::ModifyBeginEx( bool bReadOnly, int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc )
  1715. {
  1716. LOCK_SHADERAPI();
  1717. // for the time being, disallow for most cases
  1718. Assert(0);
  1719. }
  1720. void CBaseMeshDX8::ModifyBegin( int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc )
  1721. {
  1722. LOCK_SHADERAPI();
  1723. // for the time being, disallow for most cases
  1724. Assert(0);
  1725. }
  1726. void CBaseMeshDX8::ModifyEnd( MeshDesc_t& desc )
  1727. {
  1728. LOCK_SHADERAPI();
  1729. // for the time being, disallow for most cases
  1730. Assert(0);
  1731. }
  1732. //-----------------------------------------------------------------------------
  1733. // Begins a pass
  1734. //-----------------------------------------------------------------------------
  1735. void CBaseMeshDX8::BeginPass( )
  1736. {
  1737. LOCK_SHADERAPI();
  1738. }
  1739. //-----------------------------------------------------------------------------
  1740. // Sets the render state and gets the drawing going
  1741. //-----------------------------------------------------------------------------
  1742. inline void CBaseMeshDX8::DrawMesh( )
  1743. {
  1744. #ifdef DBGFLAG_ASSERT
  1745. // Make sure we're not drawing...
  1746. Assert( !m_IsDrawing );
  1747. m_IsDrawing = true;
  1748. #endif
  1749. // This is going to cause RenderPass to get called a bunch
  1750. ShaderAPI()->DrawMesh( this );
  1751. #ifdef DBGFLAG_ASSERT
  1752. m_IsDrawing = false;
  1753. #endif
  1754. }
  1755. //-----------------------------------------------------------------------------
  1756. // Spews the mesh data
  1757. //-----------------------------------------------------------------------------
  1758. void CBaseMeshDX8::Spew( int nVertexCount, int nIndexCount, const MeshDesc_t &spewDesc )
  1759. {
  1760. LOCK_SHADERAPI();
  1761. // This has regressed.
  1762. int i;
  1763. // FIXME: just fall back to the base class (CVertexBufferBase) version of this function!
  1764. #ifdef _DEBUG
  1765. if( m_pMaterial )
  1766. {
  1767. Plat_DebugString( ( const char * )m_pMaterial->GetName() );
  1768. Plat_DebugString( "\n" );
  1769. }
  1770. #endif // _DEBUG
  1771. // This is needed so buffering can just use this
  1772. VertexFormat_t fmt = m_VertexFormat;
  1773. // Set up the vertex descriptor
  1774. MeshDesc_t desc = spewDesc;
  1775. char tempbuf[256];
  1776. char* temp = tempbuf;
  1777. sprintf( tempbuf,"\nVerts: (Vertex Format %llx)\n", fmt);
  1778. Plat_DebugString(tempbuf);
  1779. CVertexBufferBase::PrintVertexFormat( fmt );
  1780. int numBoneWeights = NumBoneWeights( fmt );
  1781. for ( i = 0; i < nVertexCount; ++i )
  1782. {
  1783. temp += sprintf( temp, "[%4d] ", i + desc.m_nFirstVertex );
  1784. if( fmt & VERTEX_POSITION )
  1785. {
  1786. D3DXVECTOR3& pos = Position( desc, i );
  1787. temp += sprintf(temp, "P %8.2f %8.2f %8.2f ",
  1788. pos[0], pos[1], pos[2]);
  1789. }
  1790. if ( fmt & VERTEX_WRINKLE )
  1791. {
  1792. float flWrinkle = Wrinkle( desc, i );
  1793. temp += sprintf(temp, "Wr %8.2f ",flWrinkle );
  1794. }
  1795. if (numBoneWeights > 0)
  1796. {
  1797. temp += sprintf(temp, "BW ");
  1798. float* pWeight = BoneWeight( desc, i );
  1799. for (int j = 0; j < numBoneWeights; ++j)
  1800. {
  1801. temp += sprintf(temp, "%1.2f ", pWeight[j]);
  1802. }
  1803. }
  1804. if ( fmt & VERTEX_BONE_INDEX )
  1805. {
  1806. unsigned char *pIndex = BoneIndex( desc, i );
  1807. temp += sprintf( temp, "BI %d %d %d %d ", ( int )pIndex[0], ( int )pIndex[1], ( int )pIndex[2], ( int )pIndex[3] );
  1808. Assert( pIndex[0] < 16 );
  1809. Assert( pIndex[1] < 16 );
  1810. Assert( pIndex[2] < 16 );
  1811. Assert( pIndex[3] < 16 );
  1812. }
  1813. if ( fmt & VERTEX_NORMAL )
  1814. {
  1815. D3DXVECTOR3& normal = Normal( desc, i );
  1816. temp += sprintf(temp, "N %1.2f %1.2f %1.2f ",
  1817. normal[0], normal[1], normal[2]);
  1818. }
  1819. if (fmt & VERTEX_COLOR)
  1820. {
  1821. unsigned char* pColor = Color( desc, i );
  1822. temp += sprintf(temp, "C b %3d g %3d r %3d a %3d ",
  1823. pColor[0], pColor[1], pColor[2], pColor[3]);
  1824. }
  1825. for (int j = 0; j < VERTEX_MAX_TEXTURE_COORDINATES; ++j)
  1826. {
  1827. if( TexCoordSize( j, fmt ) > 0)
  1828. {
  1829. D3DXVECTOR2& texcoord = TexCoord( desc, i, j );
  1830. temp += sprintf(temp, "T%d %.2f %.2f ", j,texcoord[0], texcoord[1]);
  1831. }
  1832. }
  1833. if (fmt & VERTEX_TANGENT_S)
  1834. {
  1835. D3DXVECTOR3& tangentS = TangentS( desc, i );
  1836. temp += sprintf(temp, "S %1.2f %1.2f %1.2f ",
  1837. tangentS[0], tangentS[1], tangentS[2]);
  1838. }
  1839. if (fmt & VERTEX_TANGENT_T)
  1840. {
  1841. D3DXVECTOR3& tangentT = TangentT( desc, i );
  1842. temp += sprintf(temp, "T %1.2f %1.2f %1.2f ",
  1843. tangentT[0], tangentT[1], tangentT[2]);
  1844. }
  1845. sprintf(temp,"\n");
  1846. Plat_DebugString(tempbuf);
  1847. temp = tempbuf;
  1848. }
  1849. sprintf( tempbuf,"\nIndices: %d\n", nIndexCount );
  1850. Plat_DebugString(tempbuf);
  1851. for ( i = 0; i < nIndexCount; ++i )
  1852. {
  1853. temp += sprintf( temp, "%d ", ( int )desc.m_pIndices[i] );
  1854. if ((i & 0x0F) == 0x0F)
  1855. {
  1856. sprintf( temp, "\n" );
  1857. Plat_DebugString(tempbuf);
  1858. tempbuf[0] = '\0';
  1859. temp = tempbuf;
  1860. }
  1861. }
  1862. sprintf(temp,"\n");
  1863. Plat_DebugString( tempbuf );
  1864. }
  1865. void CBaseMeshDX8::ValidateData( int nVertexCount, int nIndexCount, const MeshDesc_t &spewDesc )
  1866. {
  1867. LOCK_SHADERAPI();
  1868. #ifdef VALIDATE_DEBUG
  1869. int i;
  1870. // FIXME: just fall back to the base class (CVertexBufferBase) version of this function!
  1871. // This is needed so buffering can just use this
  1872. VertexFormat_t fmt = m_pMaterial->GetVertexUsage();
  1873. // Set up the vertex descriptor
  1874. MeshDesc_t desc = spewDesc;
  1875. int numBoneWeights = NumBoneWeights( fmt );
  1876. for ( i = 0; i < nVertexCount; ++i )
  1877. {
  1878. if( fmt & VERTEX_POSITION )
  1879. {
  1880. D3DXVECTOR3& pos = Position( desc, i );
  1881. Assert( IsFinite( pos[0] ) && IsFinite( pos[1] ) && IsFinite( pos[2] ) );
  1882. }
  1883. if( fmt & VERTEX_WRINKLE )
  1884. {
  1885. float flWrinkle = Wrinkle( desc, i );
  1886. Assert( IsFinite( flWrinkle ) );
  1887. }
  1888. if (numBoneWeights > 0)
  1889. {
  1890. float* pWeight = BoneWeight( desc, i );
  1891. for (int j = 0; j < numBoneWeights; ++j)
  1892. {
  1893. Assert( pWeight[j] >= 0.0f && pWeight[j] <= 1.0f );
  1894. }
  1895. }
  1896. if( fmt & VERTEX_BONE_INDEX )
  1897. {
  1898. unsigned char *pIndex = BoneIndex( desc, i );
  1899. Assert( pIndex[0] >= 0 && pIndex[0] < 16 );
  1900. Assert( pIndex[1] >= 0 && pIndex[1] < 16 );
  1901. Assert( pIndex[2] >= 0 && pIndex[2] < 16 );
  1902. Assert( pIndex[3] >= 0 && pIndex[3] < 16 );
  1903. }
  1904. if( fmt & VERTEX_NORMAL )
  1905. {
  1906. D3DXVECTOR3& normal = Normal( desc, i );
  1907. Assert( normal[0] >= -1.05f && normal[0] <= 1.05f );
  1908. Assert( normal[1] >= -1.05f && normal[1] <= 1.05f );
  1909. Assert( normal[2] >= -1.05f && normal[2] <= 1.05f );
  1910. }
  1911. if (fmt & VERTEX_COLOR)
  1912. {
  1913. int* pColor = (int*)Color( desc, i );
  1914. Assert( *pColor != FLOAT32_NAN_BITS );
  1915. }
  1916. for (int j = 0; j < VERTEX_MAX_TEXTURE_COORDINATES; ++j)
  1917. {
  1918. if( TexCoordSize( j, fmt ) > 0)
  1919. {
  1920. D3DXVECTOR2& texcoord = TexCoord( desc, i, j );
  1921. Assert( IsFinite( texcoord[0] ) && IsFinite( texcoord[1] ) );
  1922. }
  1923. }
  1924. if (fmt & VERTEX_TANGENT_S)
  1925. {
  1926. D3DXVECTOR3& tangentS = TangentS( desc, i );
  1927. Assert( IsFinite( tangentS[0] ) && IsFinite( tangentS[1] ) && IsFinite( tangentS[2] ) );
  1928. }
  1929. if (fmt & VERTEX_TANGENT_T)
  1930. {
  1931. D3DXVECTOR3& tangentT = TangentT( desc, i );
  1932. Assert( IsFinite( tangentT[0] ) && IsFinite( tangentT[1] ) && IsFinite( tangentT[2] ) );
  1933. }
  1934. }
  1935. #endif // _DEBUG
  1936. }
  1937. void CBaseMeshDX8::Draw( CPrimList *pLists, int nLists )
  1938. {
  1939. LOCK_SHADERAPI();
  1940. Assert( !"CBaseMeshDX8::Draw(CPrimList, int): should never get here." );
  1941. }
  1942. // Copy verts and/or indices to a mesh builder. This only works for temp meshes!
  1943. void CBaseMeshDX8::CopyToMeshBuilder(
  1944. int iStartVert, // Which vertices to copy.
  1945. int nVerts,
  1946. int iStartIndex, // Which indices to copy.
  1947. int nIndices,
  1948. int indexOffset, // This is added to each index.
  1949. CMeshBuilder &builder )
  1950. {
  1951. LOCK_SHADERAPI();
  1952. Assert( false );
  1953. Warning( "CopyToMeshBuilder called on something other than a temp mesh.\n" );
  1954. }
  1955. //-----------------------------------------------------------------------------
  1956. //
  1957. // static mesh
  1958. //
  1959. //-----------------------------------------------------------------------------
  1960. CPrimList *CMeshDX8::s_pPrims;
  1961. int CMeshDX8::s_nPrims;
  1962. unsigned int CMeshDX8::s_FirstVertex;
  1963. unsigned int CMeshDX8::s_NumVertices;
  1964. //-----------------------------------------------------------------------------
  1965. // Computes the mode
  1966. //-----------------------------------------------------------------------------
  1967. inline D3DPRIMITIVETYPE ComputeMode( MaterialPrimitiveType_t type )
  1968. {
  1969. switch(type)
  1970. {
  1971. #ifdef _X360
  1972. case MATERIAL_INSTANCED_QUADS:
  1973. return D3DPT_QUADLIST;
  1974. #endif
  1975. case MATERIAL_POINTS:
  1976. return D3DPT_POINTLIST;
  1977. case MATERIAL_LINES:
  1978. return D3DPT_LINELIST;
  1979. case MATERIAL_TRIANGLES:
  1980. return D3DPT_TRIANGLELIST;
  1981. case MATERIAL_TRIANGLE_STRIP:
  1982. return D3DPT_TRIANGLESTRIP;
  1983. // Here, we expect to have the type set later. only works for static meshes
  1984. case MATERIAL_HETEROGENOUS:
  1985. return (D3DPRIMITIVETYPE)-1;
  1986. default:
  1987. Assert(0);
  1988. return (D3DPRIMITIVETYPE)-1;
  1989. }
  1990. }
  1991. //-----------------------------------------------------------------------------
  1992. // constructor
  1993. //-----------------------------------------------------------------------------
  1994. CMeshDX8::CMeshDX8( const char *pTextureGroupName ) : m_NumVertices(0), m_NumIndices(0), m_pVertexBuffer(0),
  1995. m_pColorMesh( 0 ), m_nColorMeshVertOffsetInBytes( 0 ),
  1996. m_pIndexBuffer(0), m_Type(MATERIAL_TRIANGLES), m_IsVBLocked(false),
  1997. m_IsIBLocked(false)
  1998. {
  1999. m_pTextureGroupName = pTextureGroupName;
  2000. m_Mode = ComputeMode(m_Type);
  2001. m_bHasFlexVerts = false;
  2002. m_pFlexVertexBuffer = NULL;
  2003. m_nFlexVertOffsetInBytes = 0;
  2004. }
  2005. CMeshDX8::~CMeshDX8()
  2006. {
  2007. // Don't release the vertex buffer
  2008. if (!g_MeshMgr.IsDynamicMesh(this))
  2009. {
  2010. if (m_pVertexBuffer)
  2011. {
  2012. delete m_pVertexBuffer;
  2013. }
  2014. if (m_pIndexBuffer)
  2015. {
  2016. SafeRelease( &m_pIndexBuffer );
  2017. }
  2018. }
  2019. }
  2020. void CMeshDX8::SetFlexMesh( IMesh *pMesh, int nVertexOffsetInBytes )
  2021. {
  2022. if ( !ShaderUtil()->OnSetFlexMesh( this, pMesh, nVertexOffsetInBytes ) )
  2023. return;
  2024. LOCK_SHADERAPI();
  2025. m_nFlexVertOffsetInBytes = nVertexOffsetInBytes; // Offset into dynamic mesh (in bytes)
  2026. if ( pMesh )
  2027. {
  2028. m_flexVertCount = pMesh->VertexCount();
  2029. pMesh->MarkAsDrawn();
  2030. CBaseMeshDX8 *pBaseMesh = static_cast<CBaseMeshDX8 *>(pMesh);
  2031. m_pFlexVertexBuffer = pBaseMesh->GetVertexBuffer();
  2032. m_bHasFlexVerts = true;
  2033. }
  2034. else
  2035. {
  2036. m_flexVertCount = 0;
  2037. m_pFlexVertexBuffer = NULL;
  2038. m_bHasFlexVerts = false;
  2039. }
  2040. }
  2041. void CMeshDX8::DisableFlexMesh( )
  2042. {
  2043. CMeshDX8::SetFlexMesh( NULL, 0 );
  2044. }
  2045. bool CMeshDX8::HasFlexMesh( ) const
  2046. {
  2047. LOCK_SHADERAPI();
  2048. return m_bHasFlexVerts;
  2049. }
  2050. void CMeshDX8::SetColorMesh( IMesh *pColorMesh, int nVertexOffsetInBytes )
  2051. {
  2052. if ( !ShaderUtil()->OnSetColorMesh( this, pColorMesh, nVertexOffsetInBytes ) )
  2053. return;
  2054. LOCK_SHADERAPI();
  2055. m_pColorMesh = ( CMeshDX8 * )pColorMesh; // dangerous conversion! garymcthack
  2056. m_nColorMeshVertOffsetInBytes = nVertexOffsetInBytes;
  2057. Assert( m_pColorMesh || ( nVertexOffsetInBytes == 0 ) );
  2058. #ifdef _DEBUG
  2059. if ( pColorMesh )
  2060. {
  2061. int nVertexCount = VertexCount();
  2062. int numVertsColorMesh = m_pColorMesh->VertexCount();
  2063. Assert( numVertsColorMesh >= nVertexCount );
  2064. }
  2065. #endif
  2066. }
  2067. void CMeshDX8::HandleLateCreation( )
  2068. {
  2069. if ( m_pVertexBuffer )
  2070. {
  2071. m_pVertexBuffer->HandleLateCreation();
  2072. }
  2073. if ( m_pIndexBuffer )
  2074. {
  2075. m_pIndexBuffer->HandleLateCreation();
  2076. }
  2077. if ( m_pFlexVertexBuffer )
  2078. {
  2079. m_pFlexVertexBuffer->HandleLateCreation();
  2080. }
  2081. if ( m_pColorMesh )
  2082. {
  2083. m_pColorMesh->HandleLateCreation();
  2084. }
  2085. }
  2086. bool CMeshDX8::HasColorMesh( ) const
  2087. {
  2088. LOCK_SHADERAPI();
  2089. return (m_pColorMesh != NULL);
  2090. }
  2091. //-----------------------------------------------------------------------------
  2092. // Locks/ unlocks the vertex buffer
  2093. //-----------------------------------------------------------------------------
  2094. bool CMeshDX8::Lock( int nVertexCount, bool bAppend, VertexDesc_t &desc )
  2095. {
  2096. Assert( !m_IsVBLocked );
  2097. // Just give the app crap buffers to fill up while we're suppressed...
  2098. if ( g_pShaderDeviceDx8->IsDeactivated() || (nVertexCount == 0))
  2099. {
  2100. // Set up the vertex descriptor
  2101. CVertexBufferBase::ComputeVertexDescription( 0, 0, desc );
  2102. desc.m_nFirstVertex = 0;
  2103. return false;
  2104. }
  2105. // Static vertex buffer case
  2106. if (!m_pVertexBuffer)
  2107. {
  2108. int size = g_MeshMgr.VertexFormatSize( m_VertexFormat );
  2109. m_pVertexBuffer = new CVertexBuffer( Dx9Device(), m_VertexFormat, 0, size, nVertexCount, m_pTextureGroupName, ShaderAPI()->UsingSoftwareVertexProcessing() );
  2110. }
  2111. // Lock it baby
  2112. int nMaxVerts, nMaxIndices;
  2113. g_MeshMgr.GetMaxToRender( this, false, &nMaxVerts, &nMaxIndices );
  2114. if ( !g_pHardwareConfig->SupportsStreamOffset() )
  2115. {
  2116. // Without stream offset, we can't use VBs greater than 65535 verts (due to our using 16-bit indices)
  2117. Assert( nVertexCount <= nMaxVerts );
  2118. }
  2119. unsigned char *pVertexMemory = m_pVertexBuffer->Lock( nVertexCount, desc.m_nFirstVertex );
  2120. if ( !pVertexMemory )
  2121. {
  2122. if ( nVertexCount > nMaxVerts )
  2123. {
  2124. Assert( 0 );
  2125. Error( "Too many verts for a dynamic vertex buffer (%d>%d) Tell a programmer to up VERTEX_BUFFER_SIZE.\n",
  2126. ( int )nVertexCount, ( int )nMaxVerts );
  2127. }
  2128. else
  2129. {
  2130. // Check if paged pool is in critical state ( < 5% free )
  2131. PAGED_POOL_INFO_t ppi;
  2132. if ( ( SYSCALL_SUCCESS == Plat_GetPagedPoolInfo( &ppi ) ) &&
  2133. ( ( ppi.numPagesFree * 20 ) < ( ppi.numPagesUsed + ppi.numPagesFree ) ) )
  2134. {
  2135. Error( "Out of OS Paged Pool Memory! For more information, please see\nhttp://support.steampowered.com/cgi-bin/steampowered.cfg/php/enduser/std_adp.php?p_faqid=150\n" );
  2136. }
  2137. else
  2138. {
  2139. Assert( 0 );
  2140. Error( "failed to lock vertex buffer in CMeshDX8::LockVertexBuffer: nVertexCount=%d, nFirstVertex=%d\n", nVertexCount, desc.m_nFirstVertex );
  2141. }
  2142. }
  2143. CVertexBufferBase::ComputeVertexDescription( 0, 0, desc );
  2144. return false;
  2145. }
  2146. // Set up the vertex descriptor
  2147. CVertexBufferBase::ComputeVertexDescription( pVertexMemory, m_VertexFormat, desc );
  2148. m_IsVBLocked = true;
  2149. #ifdef RECORDING
  2150. m_LockVertexBufferSize = nVertexCount * desc.m_ActualVertexSize;
  2151. m_LockVertexBuffer = pVertexMemory;
  2152. #endif
  2153. return true;
  2154. }
  2155. void CMeshDX8::Unlock( int nVertexCount, VertexDesc_t& desc )
  2156. {
  2157. // NOTE: This can happen if another application finishes
  2158. // initializing during the construction of a mesh
  2159. if (!m_IsVBLocked)
  2160. return;
  2161. // This is recorded for debugging. . not sent to dx.
  2162. RECORD_COMMAND( DX8_SET_VERTEX_BUFFER_FORMAT, 2 );
  2163. RECORD_INT( m_pVertexBuffer->UID() );
  2164. RECORD_INT( m_VertexFormat );
  2165. RECORD_COMMAND( DX8_VERTEX_DATA, 3 );
  2166. RECORD_INT( m_pVertexBuffer->UID() );
  2167. RECORD_INT( m_LockVertexBufferSize );
  2168. RECORD_STRUCT( m_LockVertexBuffer, m_LockVertexBufferSize );
  2169. Assert(m_pVertexBuffer);
  2170. m_pVertexBuffer->Unlock(nVertexCount);
  2171. m_IsVBLocked = false;
  2172. }
  2173. //-----------------------------------------------------------------------------
  2174. // Locks/unlocks the index buffer
  2175. //-----------------------------------------------------------------------------
  2176. int CMeshDX8::Lock( bool bReadOnly, int nFirstIndex, int nIndexCount, IndexDesc_t &desc )
  2177. {
  2178. Assert( !m_IsIBLocked );
  2179. // Just give the app crap buffers to fill up while we're suppressed...
  2180. if ( g_pShaderDeviceDx8->IsDeactivated() || (nIndexCount == 0))
  2181. {
  2182. // Set up a bogus index descriptor
  2183. desc.m_pIndices = g_nScratchIndexBuffer;
  2184. desc.m_nIndexSize = 0;
  2185. return 0;
  2186. }
  2187. // Static vertex buffer case
  2188. if (!m_pIndexBuffer)
  2189. {
  2190. SafeAssign( &m_pIndexBuffer, new CIndexBuffer( Dx9Device(), nIndexCount, ShaderAPI()->UsingSoftwareVertexProcessing() ) );
  2191. }
  2192. int startIndex;
  2193. desc.m_pIndices = m_pIndexBuffer->Lock( bReadOnly, nIndexCount, startIndex, nFirstIndex );
  2194. if( !desc.m_pIndices )
  2195. {
  2196. desc.m_pIndices = g_nScratchIndexBuffer;
  2197. desc.m_nIndexSize = 0;
  2198. // Check if paged pool is in critical state ( < 5% free )
  2199. PAGED_POOL_INFO_t ppi;
  2200. if ( ( SYSCALL_SUCCESS == Plat_GetPagedPoolInfo( &ppi ) ) &&
  2201. ( ( ppi.numPagesFree * 20 ) < ( ppi.numPagesUsed + ppi.numPagesFree ) ) )
  2202. {
  2203. Error( "Out of OS Paged Pool Memory! For more information, please see\nhttp://support.steampowered.com/cgi-bin/steampowered.cfg/php/enduser/std_adp.php?p_faqid=150\n" );
  2204. }
  2205. else
  2206. {
  2207. Assert( 0 );
  2208. Error( "failed to lock index buffer in CMeshDX8::LockIndexBuffer\n" );
  2209. }
  2210. return 0;
  2211. }
  2212. desc.m_nIndexSize = 1;
  2213. m_IsIBLocked = true;
  2214. #if defined( RECORDING ) || defined( CHECK_INDICES )
  2215. m_LockIndexBufferSize = nIndexCount * 2;
  2216. m_LockIndexBuffer = desc.m_pIndices;
  2217. #endif
  2218. return startIndex;
  2219. }
  2220. void CMeshDX8::Unlock( int nIndexCount, IndexDesc_t &desc )
  2221. {
  2222. // NOTE: This can happen if another application finishes
  2223. // initializing during the construction of a mesh
  2224. if (!m_IsIBLocked)
  2225. return;
  2226. RECORD_COMMAND( DX8_INDEX_DATA, 3 );
  2227. RECORD_INT( m_pIndexBuffer->UID() );
  2228. RECORD_INT( m_LockIndexBufferSize );
  2229. RECORD_STRUCT( m_LockIndexBuffer, m_LockIndexBufferSize );
  2230. Assert(m_pIndexBuffer);
  2231. #ifdef CHECK_INDICES
  2232. m_pIndexBuffer->UpdateShadowIndices( ( unsigned short * )m_LockIndexBuffer );
  2233. #endif // CHECK_INDICES
  2234. // Unlock, and indicate how many vertices we actually used
  2235. m_pIndexBuffer->Unlock(nIndexCount);
  2236. m_IsIBLocked = false;
  2237. }
  2238. //-----------------------------------------------------------------------------
  2239. // Locks/unlocks the entire mesh
  2240. //-----------------------------------------------------------------------------
  2241. void CMeshDX8::LockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc )
  2242. {
  2243. ShaderUtil()->SyncMatrices();
  2244. g_ShaderMutex.Lock();
  2245. VPROF( "CMeshDX8::LockMesh" );
  2246. Lock( nVertexCount, false, *static_cast<VertexDesc_t*>( &desc ) );
  2247. if ( m_Type != MATERIAL_POINTS )
  2248. {
  2249. Lock( false, -1, nIndexCount, *static_cast<IndexDesc_t*>( &desc ) );
  2250. }
  2251. else
  2252. {
  2253. desc.m_pIndices = g_nScratchIndexBuffer;
  2254. desc.m_nIndexSize = 0;
  2255. }
  2256. CBaseMeshDX8::m_bMeshLocked = true;
  2257. }
  2258. void CMeshDX8::UnlockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc )
  2259. {
  2260. VPROF( "CMeshDX8::UnlockMesh" );
  2261. Assert( CBaseMeshDX8::m_bMeshLocked );
  2262. Unlock( nVertexCount, *static_cast<VertexDesc_t*>( &desc ) );
  2263. if ( m_Type != MATERIAL_POINTS )
  2264. {
  2265. Unlock( nIndexCount, *static_cast<IndexDesc_t*>( &desc ) );
  2266. }
  2267. // The actual # we wrote
  2268. m_NumVertices = nVertexCount;
  2269. m_NumIndices = nIndexCount;
  2270. CBaseMeshDX8::m_bMeshLocked = false;
  2271. g_ShaderMutex.Unlock();
  2272. }
  2273. //-----------------------------------------------------------------------------
  2274. // Locks mesh for modifying
  2275. //-----------------------------------------------------------------------------
  2276. void CMeshDX8::ModifyBeginEx( bool bReadOnly, int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc )
  2277. {
  2278. VPROF( "CMeshDX8::ModifyBegin" );
  2279. // Just give the app crap buffers to fill up while we're suppressed...
  2280. if ( g_pShaderDeviceDx8->IsDeactivated())
  2281. {
  2282. // Set up a bogus descriptor
  2283. g_MeshMgr.ComputeVertexDescription( 0, 0, desc );
  2284. desc.m_pIndices = g_nScratchIndexBuffer;
  2285. desc.m_nIndexSize = 0;
  2286. return;
  2287. }
  2288. Assert( m_pVertexBuffer );
  2289. // Lock it baby
  2290. unsigned char* pVertexMemory = m_pVertexBuffer->Modify( bReadOnly, nFirstVertex, nVertexCount );
  2291. if ( pVertexMemory )
  2292. {
  2293. m_IsVBLocked = true;
  2294. g_MeshMgr.ComputeVertexDescription( pVertexMemory, m_VertexFormat, desc );
  2295. #ifdef RECORDING
  2296. m_LockVertexBufferSize = nVertexCount * desc.m_ActualVertexSize;
  2297. m_LockVertexBuffer = pVertexMemory;
  2298. #endif
  2299. }
  2300. desc.m_nFirstVertex = nFirstVertex;
  2301. Lock( bReadOnly, nFirstIndex, nIndexCount, *static_cast<IndexDesc_t*>( &desc ) );
  2302. }
  2303. void CMeshDX8::ModifyBegin( int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc )
  2304. {
  2305. ModifyBeginEx( false, nFirstVertex, nVertexCount, nFirstIndex, nIndexCount, desc );
  2306. }
  2307. void CMeshDX8::ModifyEnd( MeshDesc_t& desc )
  2308. {
  2309. VPROF( "CMeshDX8::ModifyEnd" );
  2310. Unlock( 0, *static_cast<IndexDesc_t*>( &desc ) );
  2311. Unlock( 0, *static_cast<VertexDesc_t*>( &desc ) );
  2312. }
  2313. //-----------------------------------------------------------------------------
  2314. // returns the # of vertices (static meshes only)
  2315. //-----------------------------------------------------------------------------
  2316. int CMeshDX8::VertexCount() const
  2317. {
  2318. return m_pVertexBuffer ? m_pVertexBuffer->VertexCount() : 0;
  2319. }
  2320. //-----------------------------------------------------------------------------
  2321. // returns the # of indices
  2322. //-----------------------------------------------------------------------------
  2323. int CMeshDX8::IndexCount( ) const
  2324. {
  2325. return m_pIndexBuffer ? m_pIndexBuffer->IndexCount() : 0;
  2326. }
  2327. //-----------------------------------------------------------------------------
  2328. // Sets up the vertex and index buffers
  2329. //-----------------------------------------------------------------------------
  2330. void CMeshDX8::UseIndexBuffer( CIndexBuffer* pBuffer )
  2331. {
  2332. SafeAssign( &m_pIndexBuffer, pBuffer );
  2333. }
  2334. void CMeshDX8::UseVertexBuffer( CVertexBuffer* pBuffer )
  2335. {
  2336. m_pVertexBuffer = pBuffer;
  2337. }
  2338. //-----------------------------------------------------------------------------
  2339. // Sets the primitive type
  2340. //-----------------------------------------------------------------------------
  2341. void CMeshDX8::SetPrimitiveType( MaterialPrimitiveType_t type )
  2342. {
  2343. Assert( IsX360() || ( type != MATERIAL_INSTANCED_QUADS ) );
  2344. if ( !ShaderUtil()->OnSetPrimitiveType( this, type ) )
  2345. {
  2346. return;
  2347. }
  2348. LOCK_SHADERAPI();
  2349. m_Type = type;
  2350. m_Mode = ComputeMode( type );
  2351. }
  2352. MaterialPrimitiveType_t CMeshDX8::GetPrimitiveType( ) const
  2353. {
  2354. return m_Type;
  2355. }
  2356. //-----------------------------------------------------------------------------
  2357. // Computes the number of primitives we're gonna draw
  2358. //-----------------------------------------------------------------------------
  2359. int CMeshDX8::NumPrimitives( int nVertexCount, int nIndexCount ) const
  2360. {
  2361. switch(m_Mode)
  2362. {
  2363. case D3DPT_POINTLIST:
  2364. return nVertexCount;
  2365. case D3DPT_LINELIST:
  2366. return nIndexCount / 2;
  2367. case D3DPT_TRIANGLELIST:
  2368. return nIndexCount / 3;
  2369. case D3DPT_TRIANGLESTRIP:
  2370. return nIndexCount - 2;
  2371. default:
  2372. // invalid, baby!
  2373. Assert(0);
  2374. }
  2375. return 0;
  2376. }
  2377. //-----------------------------------------------------------------------------
  2378. // Checks if it's a valid format
  2379. //-----------------------------------------------------------------------------
  2380. #ifdef _DEBUG
  2381. static void OutputVertexFormat( VertexFormat_t format )
  2382. {
  2383. // FIXME: this is a duplicate of the function in meshdx8.cpp
  2384. VertexCompressionType_t compressionType = CompressionType( format );
  2385. if ( format & VERTEX_POSITION )
  2386. {
  2387. Warning( "VERTEX_POSITION|" );
  2388. }
  2389. if ( format & VERTEX_NORMAL )
  2390. {
  2391. if ( compressionType == VERTEX_COMPRESSION_ON )
  2392. Warning( "VERTEX_NORMAL[COMPRESSED]|" );
  2393. else
  2394. Warning( "VERTEX_NORMAL|" );
  2395. }
  2396. if ( format & VERTEX_COLOR )
  2397. {
  2398. Warning( "VERTEX_COLOR|" );
  2399. }
  2400. if ( format & VERTEX_SPECULAR )
  2401. {
  2402. Warning( "VERTEX_SPECULAR|" );
  2403. }
  2404. if ( format & VERTEX_TANGENT_S )
  2405. {
  2406. Warning( "VERTEX_TANGENT_S|" );
  2407. }
  2408. if ( format & VERTEX_TANGENT_T )
  2409. {
  2410. Warning( "VERTEX_TANGENT_T|" );
  2411. }
  2412. if ( format & VERTEX_BONE_INDEX )
  2413. {
  2414. Warning( "VERTEX_BONE_INDEX|" );
  2415. }
  2416. if ( format & VERTEX_FORMAT_VERTEX_SHADER )
  2417. {
  2418. Warning( "VERTEX_FORMAT_VERTEX_SHADER|" );
  2419. }
  2420. Warning( "\nBone weights: %d (%s)\n", NumBoneWeights( format ),
  2421. ( CompressionType( format ) == VERTEX_COMPRESSION_ON ? "compressed" : "uncompressed" ) );
  2422. Warning( "user data size: %d (%s)\n", UserDataSize( format ),
  2423. ( CompressionType( format ) == VERTEX_COMPRESSION_ON ? "compressed" : "uncompressed" ) );
  2424. Warning( "num tex coords: %d\n", NumTextureCoordinates( format ) );
  2425. // NOTE: This doesn't print texcoord sizes.
  2426. }
  2427. #endif
  2428. bool CMeshDX8::IsValidVertexFormat( VertexFormat_t vertexFormat )
  2429. {
  2430. // FIXME: Make this a debug-only check on say 6th July 2007 (after a week or so's testing)
  2431. // (i.e. avoid the 360 release build perf. hit for when we ship)
  2432. bool bCheckCompression = ( m_VertexFormat & VERTEX_FORMAT_COMPRESSED ) &&
  2433. ( ( vertexFormat == VERTEX_FORMAT_INVALID ) || ( ( vertexFormat & VERTEX_FORMAT_COMPRESSED ) == 0 ) );
  2434. if ( bCheckCompression || IsPC() || IsDebug() )
  2435. {
  2436. IMaterialInternal* pMaterial = ShaderAPI()->GetBoundMaterial();
  2437. Assert( pMaterial );
  2438. // the material format should match the vertex usage, unless another format is passed in
  2439. if ( vertexFormat == VERTEX_FORMAT_INVALID )
  2440. {
  2441. vertexFormat = pMaterial->GetVertexUsage() & ~( VERTEX_FORMAT_VERTEX_SHADER | VERTEX_FORMAT_USE_EXACT_FORMAT );
  2442. // Blat out unused fields
  2443. vertexFormat &= ~g_MeshMgr.UnusedVertexFields();
  2444. int nUnusedTextureCoords = g_MeshMgr.UnusedTextureCoords();
  2445. for ( int i = 0; i < VERTEX_MAX_TEXTURE_COORDINATES; ++i )
  2446. {
  2447. if ( nUnusedTextureCoords & ( 1 << i ) )
  2448. {
  2449. vertexFormat &= ~VERTEX_TEXCOORD_MASK( i );
  2450. }
  2451. }
  2452. }
  2453. else
  2454. {
  2455. vertexFormat &= ~( VERTEX_FORMAT_VERTEX_SHADER | VERTEX_FORMAT_USE_EXACT_FORMAT );
  2456. }
  2457. bool bIsValid = (( VERTEX_FORMAT_FIELD_MASK & vertexFormat ) & ( VERTEX_FORMAT_FIELD_MASK & ~m_VertexFormat )) == 0;
  2458. if ( m_VertexFormat & VERTEX_FORMAT_COMPRESSED )
  2459. {
  2460. // We shouldn't get compressed verts if this material doesn't support them!
  2461. if ( ( vertexFormat & VERTEX_FORMAT_COMPRESSED ) == 0 )
  2462. {
  2463. static int numWarnings = 0;
  2464. if ( numWarnings++ == 0 )
  2465. {
  2466. // NOTE: ComputeVertexFormat() will make sure no materials support VERTEX_FORMAT_COMPRESSED
  2467. // if vertex compression is disabled in the config
  2468. if ( g_pHardwareConfig->SupportsCompressedVertices() == VERTEX_COMPRESSION_NONE )
  2469. Warning( "ERROR: Compressed vertices in use but vertex compression is disabled (or not supported on this hardware)!\n" );
  2470. else
  2471. Warning( "ERROR: Compressed vertices in use but material does not support them!\n" );
  2472. }
  2473. Assert( 0 );
  2474. bIsValid = false;
  2475. }
  2476. }
  2477. bIsValid = bIsValid && UserDataSize( m_VertexFormat ) >= UserDataSize( vertexFormat );
  2478. for ( int i=0; i < VERTEX_MAX_TEXTURE_COORDINATES; i++ )
  2479. {
  2480. if ( TexCoordSize( i, m_VertexFormat ) < TexCoordSize( i, vertexFormat ) )
  2481. {
  2482. bIsValid = false;
  2483. }
  2484. }
  2485. // NOTE: It can totally be valid to have more weights than the current number of bones.
  2486. // The -1 here is because if we have N bones, we can have only (N-1) weights,
  2487. // since the Nth is implied (the weights sum to 1).
  2488. int nWeightCount = NumBoneWeights( m_VertexFormat );
  2489. bIsValid = bIsValid && ( nWeightCount >= ( g_pShaderAPI->GetCurrentNumBones() - 1 ) );
  2490. #ifdef _DEBUG
  2491. if ( !bIsValid )
  2492. {
  2493. Warning( "Material Format:" );
  2494. if ( g_pShaderAPI->GetCurrentNumBones() > 0 )
  2495. {
  2496. vertexFormat |= VERTEX_BONE_INDEX;
  2497. vertexFormat &= ~VERTEX_BONE_WEIGHT_MASK;
  2498. vertexFormat |= VERTEX_BONEWEIGHT( 2 );
  2499. }
  2500. OutputVertexFormat( vertexFormat );
  2501. Warning( "Mesh Format:" );
  2502. OutputVertexFormat( m_VertexFormat );
  2503. }
  2504. #endif
  2505. return bIsValid;
  2506. }
  2507. return true;
  2508. }
  2509. //-----------------------------------------------------------------------------
  2510. // Stream source setting methods
  2511. //-----------------------------------------------------------------------------
  2512. void CMeshDX8::SetVertexIDStreamState()
  2513. {
  2514. // FIXME: this method duplicates the code in CMeshMgr::SetVertexIDStreamState
  2515. if ( IsX360() )
  2516. return;
  2517. bool bUsingVertexID = IsUsingVertexID();
  2518. if ( bUsingVertexID != g_bUsingVertexID )
  2519. {
  2520. if ( bUsingVertexID )
  2521. {
  2522. // NOTE: Morphing doesn't work with dynamic buffers!!! BLEAH
  2523. // It's because the indices (which are not 0 based for dynamic buffers)
  2524. // are accessing both the vertexID buffer + the regular vertex buffer.
  2525. // This *might* be fixable with baseVertexIndex?
  2526. // NOTE: At the moment, vertex id is only used for hw morphing. I've got it
  2527. // set up so that a shader that supports hw morphing always says it uses vertex id.
  2528. // If we ever use vertex id for something other than hw morphing, we're going
  2529. // to have to revisit how those shaders say they want to use vertex id
  2530. // or fix this some other way
  2531. Assert( !g_pShaderAPI->IsHWMorphingEnabled() || !m_pVertexBuffer->IsDynamic() );
  2532. CVertexBuffer *pVertexIDBuffer = g_MeshMgr.GetVertexIDBuffer( );
  2533. RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
  2534. RECORD_INT( pVertexIDBuffer->UID() );
  2535. RECORD_INT( 3 );
  2536. RECORD_INT( 0 );
  2537. RECORD_INT( pVertexIDBuffer->VertexSize() );
  2538. D3DSetStreamSource( 3, pVertexIDBuffer->GetInterface(), 0, pVertexIDBuffer->VertexSize() );
  2539. pVertexIDBuffer->HandlePerFrameTextureStats( ShaderAPI()->GetCurrentFrameCounter() );
  2540. }
  2541. else
  2542. {
  2543. RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
  2544. RECORD_INT( -1 ); // vertex buffer id
  2545. RECORD_INT( 3 ); // stream
  2546. RECORD_INT( 0 ); // vertex offset
  2547. RECORD_INT( 0 ); // vertex size
  2548. D3DSetStreamSource( 3, 0, 0, 0 );
  2549. }
  2550. g_bUsingVertexID = bUsingVertexID;
  2551. }
  2552. }
  2553. void CMeshDX8::SetColorStreamState()
  2554. {
  2555. if ( ( m_pColorMesh != g_pLastColorMesh ) || ( m_nColorMeshVertOffsetInBytes != g_nLastColorMeshVertOffsetInBytes ) )
  2556. {
  2557. if ( m_pColorMesh )
  2558. {
  2559. RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
  2560. RECORD_INT( m_pColorMesh->GetVertexBuffer()->UID() );
  2561. RECORD_INT( 1 );
  2562. RECORD_INT( m_nColorMeshVertOffsetInBytes );
  2563. RECORD_INT( m_pColorMesh->GetVertexBuffer()->VertexSize() );
  2564. D3DSetStreamSource( 1, m_pColorMesh->GetVertexBuffer()->GetInterface(),
  2565. m_nColorMeshVertOffsetInBytes, m_pColorMesh->GetVertexBuffer()->VertexSize() );
  2566. m_pColorMesh->GetVertexBuffer()->HandlePerFrameTextureStats( ShaderAPI()->GetCurrentFrameCounter() );
  2567. }
  2568. else
  2569. {
  2570. RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
  2571. RECORD_INT( -1 ); // vertex buffer id
  2572. RECORD_INT( 1 ); // stream
  2573. RECORD_INT( 0 ); // vertex offset
  2574. RECORD_INT( 0 ); // vertex size
  2575. D3DSetStreamSource( 1, 0, 0, 0 );
  2576. }
  2577. g_pLastColorMesh = m_pColorMesh;
  2578. g_nLastColorMeshVertOffsetInBytes = m_nColorMeshVertOffsetInBytes;
  2579. }
  2580. }
  2581. void CMeshDX8::SetVertexStreamState( int nVertOffsetInBytes )
  2582. {
  2583. // Calls in here assume shader support...
  2584. if ( HardwareConfig()->SupportsVertexAndPixelShaders() )
  2585. {
  2586. if ( HasFlexMesh() )
  2587. {
  2588. // m_pFlexVertexBuffer is the flex buffer down inside the CMeshMgr singleton
  2589. D3DSetStreamSource( 2, m_pFlexVertexBuffer->GetInterface(), m_nFlexVertOffsetInBytes, m_pFlexVertexBuffer->VertexSize() );
  2590. if ( g_pHardwareConfig->Caps().m_SupportsVertexShaders_2_0 )
  2591. {
  2592. float c[4] = { 1.0f, g_pMaterialSystemHardwareConfig->SupportsPixelShaders_2_b() ? 1.0f : 0.0f, 0.0f, 0.0f };
  2593. ShaderAPI()->SetVertexShaderConstant( VERTEX_SHADER_FLEXSCALE, c, 1 );
  2594. }
  2595. g_bFlexMeshStreamSet = true;
  2596. }
  2597. else
  2598. {
  2599. Assert( nVertOffsetInBytes == 0 );
  2600. Assert( m_pVertexBuffer );
  2601. // HACK...point stream 2 at the same VB which is bound to stream 0...
  2602. // NOTE: D3D debug DLLs will RIP if stream 0 has a smaller stride than the largest
  2603. // offset in the stream 2 vertex decl elements (which are position(12)+wrinkle(4)+normal(12))
  2604. // If this fires, go find the material/shader which is requesting a really 'thin'
  2605. // stream 0 vertex, and fatten it up slightly (e.g. add a D3DCOLOR element)
  2606. int minimumStreamZeroStride = 4 * sizeof( float );
  2607. Assert( m_pVertexBuffer->VertexSize() >= minimumStreamZeroStride );
  2608. if ( m_pVertexBuffer->VertexSize() < minimumStreamZeroStride )
  2609. {
  2610. static bool bWarned = false;
  2611. if( !bWarned )
  2612. {
  2613. Warning( "Shader specifying too-thin vertex format, should be at least %d bytes! (Suppressing furthur warnings)\n", minimumStreamZeroStride );
  2614. bWarned = true;
  2615. }
  2616. }
  2617. // Set a 4kb all-zero static VB into the flex/wrinkle stream with a stride of 1 bytes, so the vertex shader always reads valid floating point values (otherwise it can get NaN's/Inf's, and under OpenGL this is bad on NVidia)
  2618. // togl requires non-zero strides, but on D3D9 we can set a stride of 0 for a little more efficiency.
  2619. D3DSetStreamSource( 2, g_MeshMgr.GetZeroVertexBuffer(), 0, IsOpenGL() ? 4 : 0 );
  2620. if ( g_pHardwareConfig->Caps().m_SupportsVertexShaders_2_0 )
  2621. {
  2622. float c[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
  2623. ShaderAPI()->SetVertexShaderConstant( VERTEX_SHADER_FLEXSCALE, c, 1 );
  2624. }
  2625. g_bFlexMeshStreamSet = false;
  2626. }
  2627. }
  2628. // MESHFIXME: Make sure this jives between the mesh/ib/vb version.
  2629. #ifdef _X360
  2630. if ( ( g_pLastVertex != m_pVertexBuffer ) || ( m_pVertexBuffer->IsDynamic() ) || ( g_nLastVertOffsetInBytes != nVertOffsetInBytes ) )
  2631. #else
  2632. if ( ( g_pLastVertex != m_pVertexBuffer ) || ( g_nLastVertOffsetInBytes != nVertOffsetInBytes ) )
  2633. #endif
  2634. {
  2635. Assert( m_pVertexBuffer );
  2636. RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
  2637. RECORD_INT( m_pVertexBuffer->UID() );
  2638. RECORD_INT( 0 );
  2639. RECORD_INT( nVertOffsetInBytes );
  2640. RECORD_INT( m_pVertexBuffer->VertexSize() );
  2641. D3DSetStreamSource( 0, m_pVertexBuffer->GetInterface(), nVertOffsetInBytes, m_pVertexBuffer->VertexSize() );
  2642. m_pVertexBuffer->HandlePerFrameTextureStats( ShaderAPI()->GetCurrentFrameCounter() );
  2643. g_pLastVertex = m_pVertexBuffer;
  2644. g_nLastVertOffsetInBytes = nVertOffsetInBytes;
  2645. }
  2646. }
  2647. void CMeshDX8::SetIndexStreamState( int firstVertexIdx )
  2648. {
  2649. #ifdef _X360
  2650. if ( ( g_pLastIndexBuffer != NULL ) || (g_pLastIndex != m_pIndexBuffer) || ( m_pIndexBuffer->IsDynamic() ) || ( firstVertexIdx != g_LastVertexIdx ) )
  2651. #else
  2652. if ( ( g_pLastIndexBuffer != NULL ) || (g_pLastIndex != m_pIndexBuffer) || ( firstVertexIdx != g_LastVertexIdx ) )
  2653. #endif
  2654. {
  2655. Assert( m_pIndexBuffer );
  2656. RECORD_COMMAND( DX8_SET_INDICES, 2 );
  2657. RECORD_INT( m_pIndexBuffer->UID() );
  2658. RECORD_INT( firstVertexIdx );
  2659. Dx9Device()->SetIndices( m_pIndexBuffer->GetInterface() );
  2660. m_pIndexBuffer->HandlePerFrameTextureStats( ShaderAPI()->GetCurrentFrameCounter() );
  2661. m_FirstIndex = firstVertexIdx;
  2662. SafeAssign( &g_pLastIndex, m_pIndexBuffer );
  2663. g_pLastIndexBuffer = NULL;
  2664. g_LastVertexIdx = firstVertexIdx;
  2665. }
  2666. }
  2667. bool CMeshDX8::SetRenderState( int nVertexOffsetInBytes, int nFirstVertexIdx, VertexFormat_t vertexFormat )
  2668. {
  2669. // Can't set the state if we're deactivated
  2670. if ( g_pShaderDeviceDx8->IsDeactivated() )
  2671. {
  2672. ResetMeshRenderState();
  2673. return false;
  2674. }
  2675. g_LastVertexFormat = vertexFormat;
  2676. SetVertexIDStreamState();
  2677. SetColorStreamState();
  2678. SetVertexStreamState( nVertexOffsetInBytes );
  2679. SetIndexStreamState( nFirstVertexIdx );
  2680. return true;
  2681. }
  2682. //-----------------------------------------------------------------------------
  2683. // Draws the static mesh
  2684. //-----------------------------------------------------------------------------
  2685. void CMeshDX8::Draw( int nFirstIndex, int nIndexCount )
  2686. {
  2687. Assert( m_pVertexBuffer );
  2688. if ( !m_pVertexBuffer )
  2689. {
  2690. return;
  2691. }
  2692. if ( !ShaderUtil()->OnDrawMesh( this, nFirstIndex, nIndexCount ) )
  2693. {
  2694. MarkAsDrawn();
  2695. return;
  2696. }
  2697. CPrimList primList;
  2698. if( nFirstIndex == -1 || nIndexCount == 0 )
  2699. {
  2700. primList.m_FirstIndex = 0;
  2701. primList.m_NumIndices = m_NumIndices;
  2702. }
  2703. else
  2704. {
  2705. primList.m_FirstIndex = nFirstIndex;
  2706. primList.m_NumIndices = nIndexCount;
  2707. }
  2708. DrawInternal( &primList, 1 );
  2709. }
  2710. void CMeshDX8::Draw( CPrimList *pLists, int nLists )
  2711. {
  2712. Assert( m_pVertexBuffer );
  2713. if ( !m_pVertexBuffer )
  2714. {
  2715. return;
  2716. }
  2717. if ( !ShaderUtil()->OnDrawMesh( this, pLists, nLists ) )
  2718. {
  2719. MarkAsDrawn();
  2720. return;
  2721. }
  2722. DrawInternal( pLists, nLists );
  2723. }
  2724. void CMeshDX8::DrawInternal( CPrimList *pLists, int nLists )
  2725. {
  2726. HandleLateCreation();
  2727. // Make sure there's something to draw..
  2728. int i;
  2729. for ( i=0; i < nLists; i++ )
  2730. {
  2731. if ( pLists[i].m_NumIndices > 0 )
  2732. break;
  2733. }
  2734. if ( i == nLists )
  2735. return;
  2736. // can't do these in selection mode!
  2737. Assert( !ShaderAPI()->IsInSelectionMode() );
  2738. if ( !SetRenderState( 0, 0 ) )
  2739. return;
  2740. s_pPrims = pLists;
  2741. s_nPrims = nLists;
  2742. #ifdef _DEBUG
  2743. for ( i = 0; i < nLists; ++i)
  2744. {
  2745. Assert( pLists[i].m_NumIndices > 0 );
  2746. }
  2747. #endif
  2748. s_FirstVertex = 0;
  2749. s_NumVertices = m_pVertexBuffer->VertexCount();
  2750. DrawMesh();
  2751. }
  2752. #ifdef CHECK_INDICES
  2753. void CMeshDX8::CheckIndices( CPrimList *pPrim, int numPrimitives )
  2754. {
  2755. // g_pLastVertex - this is the current vertex buffer
  2756. // g_pLastColorMesh - this is the current color mesh, if there is one.
  2757. // g_pLastIndex - this is the current index buffer.
  2758. // vertoffset : m_FirstIndex
  2759. if( m_Mode == D3DPT_TRIANGLELIST || m_Mode == D3DPT_TRIANGLESTRIP )
  2760. {
  2761. Assert( pPrim->m_FirstIndex >= 0 && pPrim->m_FirstIndex < g_pLastIndex->IndexCount() );
  2762. int i;
  2763. for( i = 0; i < 2; i++ )
  2764. {
  2765. CVertexBuffer *pMesh;
  2766. if( i == 0 )
  2767. {
  2768. pMesh = g_pLastVertex;
  2769. Assert( pMesh );
  2770. }
  2771. else
  2772. {
  2773. if( !g_pLastColorMesh )
  2774. {
  2775. continue;
  2776. }
  2777. pMesh = g_pLastColorMesh->m_pVertexBuffer;
  2778. if( !pMesh )
  2779. {
  2780. continue;
  2781. }
  2782. }
  2783. Assert( s_FirstVertex >= 0 &&
  2784. (int)( s_FirstVertex + m_FirstIndex ) < pMesh->VertexCount() );
  2785. int nIndexCount = 0;
  2786. if( m_Mode == D3DPT_TRIANGLELIST )
  2787. {
  2788. nIndexCount = numPrimitives * 3;
  2789. }
  2790. else if( m_Mode == D3DPT_TRIANGLESTRIP )
  2791. {
  2792. nIndexCount = numPrimitives + 2;
  2793. }
  2794. else
  2795. {
  2796. Assert( 0 );
  2797. }
  2798. int j;
  2799. for( j = 0; j < nIndexCount; j++ )
  2800. {
  2801. int index = g_pLastIndex->GetShadowIndex( j + pPrim->m_FirstIndex );
  2802. if ( ( index < (int)s_FirstVertex ) || ( index >= (int)( s_FirstVertex + s_NumVertices ) ) )
  2803. Warning("%s invalid index: %d [%u..%u]\n", __FUNCTION__, index, s_FirstVertex, s_FirstVertex + s_NumVertices - 1 );
  2804. Assert( index >= (int)s_FirstVertex );
  2805. Assert( index < (int)(s_FirstVertex + s_NumVertices) );
  2806. }
  2807. }
  2808. }
  2809. }
  2810. #endif // CHECK_INDICES
  2811. //-----------------------------------------------------------------------------
  2812. // Actually does the dirty deed of rendering
  2813. //-----------------------------------------------------------------------------
  2814. void CMeshDX8::RenderPass()
  2815. {
  2816. LOCK_SHADERAPI();
  2817. VPROF( "CMeshDX8::RenderPass" );
  2818. HandleLateCreation();
  2819. Assert( m_Type != MATERIAL_HETEROGENOUS );
  2820. // make sure the vertex format is a superset of the current material's
  2821. // vertex format...
  2822. if ( !IsValidVertexFormat( g_LastVertexFormat ) )
  2823. {
  2824. Warning( "Material %s does not support vertex format used by the mesh (maybe missing fields or mismatched vertex compression?), mesh will not be rendered. Grab a programmer!\n",
  2825. ShaderAPI()->GetBoundMaterial()->GetName() );
  2826. return;
  2827. }
  2828. for ( int iPrim=0; iPrim < s_nPrims; iPrim++ )
  2829. {
  2830. CPrimList *pPrim = &s_pPrims[iPrim];
  2831. if ( pPrim->m_NumIndices == 0 )
  2832. continue;
  2833. if ( ( m_Type == MATERIAL_POINTS ) || ( m_Type == MATERIAL_INSTANCED_QUADS ) )
  2834. {
  2835. tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "Dx9Device_DrawPrimitive" );
  2836. // (For point/instanced-quad lists, we don't actually fill in indices, but we treat it as
  2837. // though there are indices for the list up until here).
  2838. Dx9Device()->DrawPrimitive( m_Mode, s_FirstVertex, pPrim->m_NumIndices );
  2839. }
  2840. else
  2841. {
  2842. int numPrimitives = NumPrimitives( s_NumVertices, pPrim->m_NumIndices );
  2843. #ifdef CHECK_INDICES
  2844. CheckIndices( pPrim, numPrimitives );
  2845. #endif // CHECK_INDICES
  2846. {
  2847. VPROF( "Dx9Device()->DrawIndexedPrimitive" );
  2848. VPROF_INCREMENT_COUNTER( "DrawIndexedPrimitive", 1 );
  2849. VPROF_INCREMENT_COUNTER( "numPrimitives", numPrimitives );
  2850. VPROF_INCREMENT_GROUP_COUNTER( "render/DrawIndexedPrimitive", COUNTER_GROUP_TELEMETRY, 1 );
  2851. VPROF_INCREMENT_GROUP_COUNTER( "render/numPrimitives", COUNTER_GROUP_TELEMETRY, 1 );
  2852. Dx9Device()->DrawIndexedPrimitive(
  2853. m_Mode, // Member of the D3DPRIMITIVETYPE enumerated type, describing the type of primitive to render. D3DPT_POINTLIST is not supported with this method.
  2854. m_FirstIndex, // Offset from the start of the vertex buffer to the first vertex index. An index of 0 in the index buffer refers to this location in the vertex buffer.
  2855. s_FirstVertex, // Minimum vertex index for vertices used during this call. This is a zero based index relative to BaseVertexIndex.
  2856. // The first Vertex in the vertexbuffer that we are currently using for the current batch.
  2857. s_NumVertices, // Number of vertices used during this call. The first vertex is located at index: BaseVertexIndex + MinIndex.
  2858. pPrim->m_FirstIndex, // Index of the first index to use when accesssing the vertex buffer. Beginning at StartIndex to index vertices from the vertex buffer.
  2859. numPrimitives );// Number of primitives to render. The number of vertices used is a function of the primitive count and the primitive type.
  2860. }
  2861. }
  2862. }
  2863. if ( g_pLastVertex )
  2864. {
  2865. g_pLastVertex->MarkUsedInRendering();
  2866. }
  2867. if( g_pLastIndex )
  2868. {
  2869. g_pLastIndex->MarkUsedInRendering();
  2870. }
  2871. }
  2872. //-----------------------------------------------------------------------------
  2873. //
  2874. // Dynamic mesh implementation
  2875. //
  2876. //-----------------------------------------------------------------------------
  2877. //-----------------------------------------------------------------------------
  2878. // constructor, destructor
  2879. //-----------------------------------------------------------------------------
  2880. CDynamicMeshDX8::CDynamicMeshDX8() : CMeshDX8( "CDynamicMeshDX8" )
  2881. {
  2882. m_nBufferId = 0;
  2883. ResetVertexAndIndexCounts();
  2884. }
  2885. CDynamicMeshDX8::~CDynamicMeshDX8()
  2886. {
  2887. }
  2888. //-----------------------------------------------------------------------------
  2889. // Initializes the dynamic mesh
  2890. //-----------------------------------------------------------------------------
  2891. void CDynamicMeshDX8::Init( int nBufferId )
  2892. {
  2893. m_nBufferId = nBufferId;
  2894. }
  2895. //-----------------------------------------------------------------------------
  2896. // Resets buffering state
  2897. //-----------------------------------------------------------------------------
  2898. void CDynamicMeshDX8::ResetVertexAndIndexCounts()
  2899. {
  2900. m_TotalVertices = m_TotalIndices = 0;
  2901. m_FirstIndex = m_nFirstVertex = -1;
  2902. m_HasDrawn = false;
  2903. }
  2904. //-----------------------------------------------------------------------------
  2905. // Resets the state in case of a task switch
  2906. //-----------------------------------------------------------------------------
  2907. void CDynamicMeshDX8::Reset()
  2908. {
  2909. m_VertexFormat = 0;
  2910. m_pVertexBuffer = 0;
  2911. SafeRelease( &m_pIndexBuffer );
  2912. ResetVertexAndIndexCounts();
  2913. // Force the render state to be updated next time
  2914. ResetMeshRenderState();
  2915. }
  2916. //-----------------------------------------------------------------------------
  2917. // Sets the vertex format associated with the dynamic mesh
  2918. //-----------------------------------------------------------------------------
  2919. void CDynamicMeshDX8::SetVertexFormat( VertexFormat_t format )
  2920. {
  2921. if ( g_pShaderDeviceDx8->IsDeactivated())
  2922. return;
  2923. if ( CompressionType( format ) != VERTEX_COMPRESSION_NONE )
  2924. {
  2925. // UNDONE: support compressed dynamic meshes if needed (pro: less VB memory, con: CMeshBuilder gets slower)
  2926. Warning( "ERROR: dynamic meshes cannot use compressed vertices!\n" );
  2927. Assert( 0 );
  2928. format &= ~VERTEX_FORMAT_COMPRESSED;
  2929. }
  2930. if ((format != m_VertexFormat) || m_VertexOverride || m_IndexOverride)
  2931. {
  2932. m_VertexFormat = format;
  2933. UseVertexBuffer( g_MeshMgr.FindOrCreateVertexBuffer( m_nBufferId, format ) );
  2934. if ( m_nBufferId == 0 )
  2935. {
  2936. UseIndexBuffer( g_MeshMgr.GetDynamicIndexBuffer() );
  2937. }
  2938. m_VertexOverride = m_IndexOverride = false;
  2939. }
  2940. }
  2941. void CDynamicMeshDX8::OverrideVertexBuffer( CVertexBuffer* pVertexBuffer )
  2942. {
  2943. UseVertexBuffer( pVertexBuffer );
  2944. m_VertexOverride = true;
  2945. }
  2946. void CDynamicMeshDX8::OverrideIndexBuffer( CIndexBuffer* pIndexBuffer )
  2947. {
  2948. UseIndexBuffer( pIndexBuffer );
  2949. m_IndexOverride = true;
  2950. }
  2951. //-----------------------------------------------------------------------------
  2952. // Do I need to reset the vertex format?
  2953. //-----------------------------------------------------------------------------
  2954. bool CDynamicMeshDX8::NeedsVertexFormatReset( VertexFormat_t fmt ) const
  2955. {
  2956. return m_VertexOverride || m_IndexOverride || (m_VertexFormat != fmt);
  2957. }
  2958. //-----------------------------------------------------------------------------
  2959. // Locks/unlocks the entire mesh
  2960. //-----------------------------------------------------------------------------
  2961. bool CDynamicMeshDX8::HasEnoughRoom( int nVertexCount, int nIndexCount ) const
  2962. {
  2963. if ( g_pShaderDeviceDx8->IsDeactivated() )
  2964. return false;
  2965. Assert( m_pVertexBuffer != NULL );
  2966. // We need space in both the vertex and index buffer
  2967. return m_pVertexBuffer->HasEnoughRoom( nVertexCount ) &&
  2968. m_pIndexBuffer->HasEnoughRoom( nIndexCount );
  2969. }
  2970. //-----------------------------------------------------------------------------
  2971. // returns the number of indices in the mesh
  2972. //-----------------------------------------------------------------------------
  2973. int CDynamicMeshDX8::IndexCount( ) const
  2974. {
  2975. return m_TotalIndices;
  2976. }
  2977. //-----------------------------------------------------------------------------
  2978. // Operation to do pre-lock (only called for buffered meshes)
  2979. //-----------------------------------------------------------------------------
  2980. void CDynamicMeshDX8::PreLock()
  2981. {
  2982. if (m_HasDrawn)
  2983. {
  2984. // Start again then
  2985. ResetVertexAndIndexCounts();
  2986. }
  2987. }
  2988. //-----------------------------------------------------------------------------
  2989. // Locks/unlocks the entire mesh
  2990. //-----------------------------------------------------------------------------
  2991. void CDynamicMeshDX8::LockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc )
  2992. {
  2993. tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s %d %d", __FUNCTION__, nVertexCount, nIndexCount );
  2994. ShaderUtil()->SyncMatrices();
  2995. {
  2996. tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "g_ShaderMutex.Lock" );
  2997. g_ShaderMutex.Lock();
  2998. }
  2999. // Yes, this may well also be called from BufferedMesh but that's ok
  3000. {
  3001. tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "PreLock" );
  3002. PreLock();
  3003. }
  3004. if (m_VertexOverride)
  3005. {
  3006. nVertexCount = 0;
  3007. }
  3008. if (m_IndexOverride)
  3009. {
  3010. nIndexCount = 0;
  3011. }
  3012. {
  3013. tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "Lock" );
  3014. Lock( nVertexCount, false, *static_cast<VertexDesc_t*>( &desc ) );
  3015. }
  3016. if (m_nFirstVertex < 0)
  3017. {
  3018. m_nFirstVertex = desc.m_nFirstVertex;
  3019. }
  3020. // When we're using a static index buffer or a flex mesh, the indices assume vertices start at 0
  3021. if ( m_IndexOverride || HasFlexMesh() )
  3022. {
  3023. desc.m_nFirstVertex -= m_nFirstVertex;
  3024. }
  3025. // Don't add indices for points; DrawIndexedPrimitive not supported for them.
  3026. if ( m_Type != MATERIAL_POINTS )
  3027. {
  3028. int nFirstIndex;
  3029. {
  3030. tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "Lock nFirstIndex" );
  3031. nFirstIndex = Lock( false, -1, nIndexCount, *static_cast<IndexDesc_t*>( &desc ) );
  3032. }
  3033. if (m_FirstIndex < 0)
  3034. {
  3035. m_FirstIndex = nFirstIndex;
  3036. }
  3037. }
  3038. else
  3039. {
  3040. desc.m_pIndices = g_nScratchIndexBuffer;
  3041. desc.m_nIndexSize = 0;
  3042. }
  3043. CBaseMeshDX8::m_bMeshLocked = true;
  3044. }
  3045. //-----------------------------------------------------------------------------
  3046. // Unlocks the mesh
  3047. //-----------------------------------------------------------------------------
  3048. void CDynamicMeshDX8::UnlockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc )
  3049. {
  3050. m_TotalVertices += nVertexCount;
  3051. m_TotalIndices += nIndexCount;
  3052. if (DebugTrace())
  3053. {
  3054. Spew( nVertexCount, nIndexCount, desc );
  3055. }
  3056. CMeshDX8::UnlockMesh( nVertexCount, nIndexCount, desc );
  3057. // This is handled in the CMeshDX8::UnlockMesh above.
  3058. //CBaseMeshDX8::m_bMeshLocked = false;
  3059. }
  3060. //-----------------------------------------------------------------------------
  3061. // Draws it
  3062. //-----------------------------------------------------------------------------
  3063. void CDynamicMeshDX8::Draw( int nFirstIndex, int nIndexCount )
  3064. {
  3065. if ( !ShaderUtil()->OnDrawMesh( this, nFirstIndex, nIndexCount ) )
  3066. {
  3067. MarkAsDrawn();
  3068. return;
  3069. }
  3070. VPROF( "CDynamicMeshDX8::Draw" );
  3071. m_HasDrawn = true;
  3072. if (m_IndexOverride || m_VertexOverride ||
  3073. ( ( m_TotalVertices > 0 ) && ( m_TotalIndices > 0 || m_Type == MATERIAL_POINTS || m_Type == MATERIAL_INSTANCED_QUADS ) ) )
  3074. {
  3075. Assert( !m_IsDrawing );
  3076. HandleLateCreation( );
  3077. // only have a non-zero first vertex when we are using static indices
  3078. int nFirstVertex = m_VertexOverride ? 0 : m_nFirstVertex;
  3079. int actualFirstVertex = m_IndexOverride ? nFirstVertex : 0;
  3080. int nVertexOffsetInBytes = HasFlexMesh() ? nFirstVertex * g_MeshMgr.VertexFormatSize( GetVertexFormat() ) : 0;
  3081. int baseIndex = m_IndexOverride ? 0 : m_FirstIndex;
  3082. // Overriding with the dynamic index buffer, preserve state!
  3083. if ( m_IndexOverride && m_pIndexBuffer == g_MeshMgr.GetDynamicIndexBuffer() )
  3084. {
  3085. baseIndex = m_FirstIndex;
  3086. }
  3087. VertexFormat_t fmt = m_VertexOverride ? GetVertexFormat() : VERTEX_FORMAT_INVALID;
  3088. if ( !SetRenderState( nVertexOffsetInBytes, actualFirstVertex, fmt ) )
  3089. return;
  3090. // Draws a portion of the mesh
  3091. int numVertices = m_VertexOverride ? m_pVertexBuffer->VertexCount() : m_TotalVertices;
  3092. if ((nFirstIndex != -1) && (nIndexCount != 0))
  3093. {
  3094. nFirstIndex += baseIndex;
  3095. }
  3096. else
  3097. {
  3098. // by default we draw the whole thing
  3099. nFirstIndex = baseIndex;
  3100. if( m_IndexOverride )
  3101. {
  3102. nIndexCount = m_pIndexBuffer->IndexCount();
  3103. Assert( nIndexCount != 0 );
  3104. }
  3105. else
  3106. {
  3107. nIndexCount = m_TotalIndices;
  3108. // Fake out the index count if we're drawing points/instanced-quads
  3109. if ( ( m_Type == MATERIAL_POINTS ) || ( m_Type == MATERIAL_INSTANCED_QUADS ) )
  3110. {
  3111. nIndexCount = m_TotalVertices;
  3112. }
  3113. Assert( nIndexCount != 0 );
  3114. }
  3115. }
  3116. // Fix up nFirstVertex to indicate the first vertex used in the data
  3117. if ( !HasFlexMesh() )
  3118. {
  3119. actualFirstVertex = nFirstVertex - actualFirstVertex;
  3120. }
  3121. s_FirstVertex = actualFirstVertex;
  3122. s_NumVertices = numVertices;
  3123. // Build a primlist with 1 element..
  3124. CPrimList prim;
  3125. prim.m_FirstIndex = nFirstIndex;
  3126. prim.m_NumIndices = nIndexCount;
  3127. Assert( nIndexCount != 0 );
  3128. s_pPrims = &prim;
  3129. s_nPrims = 1;
  3130. DrawMesh();
  3131. s_pPrims = NULL;
  3132. }
  3133. }
  3134. //-----------------------------------------------------------------------------
  3135. // This is useful when we need to dynamically modify data; just set the
  3136. // render state and draw the pass immediately
  3137. //-----------------------------------------------------------------------------
  3138. void CDynamicMeshDX8::DrawSinglePassImmediately()
  3139. {
  3140. if ((m_TotalVertices > 0) || (m_TotalIndices > 0))
  3141. {
  3142. Assert( !m_IsDrawing );
  3143. // Set the render state
  3144. if ( SetRenderState( 0, 0 ) )
  3145. {
  3146. s_FirstVertex = m_nFirstVertex;
  3147. s_NumVertices = m_TotalVertices;
  3148. // Make a temporary PrimList to hold the indices.
  3149. CPrimList prim( m_FirstIndex, m_TotalIndices );
  3150. Assert( m_TotalIndices != 0 );
  3151. s_pPrims = &prim;
  3152. s_nPrims = 1;
  3153. // Render it
  3154. RenderPass();
  3155. }
  3156. // We're done with our data
  3157. ResetVertexAndIndexCounts();
  3158. }
  3159. }
  3160. //-----------------------------------------------------------------------------
  3161. //
  3162. // A mesh that stores temporary vertex data in the correct format (for modification)
  3163. //
  3164. //-----------------------------------------------------------------------------
  3165. // Used in rendering sub-parts of the mesh
  3166. unsigned int CTempMeshDX8::s_NumIndices;
  3167. unsigned int CTempMeshDX8::s_FirstIndex;
  3168. //-----------------------------------------------------------------------------
  3169. // constructor, destructor
  3170. //-----------------------------------------------------------------------------
  3171. CTempMeshDX8::CTempMeshDX8( bool isDynamic ) : m_VertexSize(0xFFFF), m_IsDynamic(isDynamic)
  3172. {
  3173. #ifdef DBGFLAG_ASSERT
  3174. m_Locked = false;
  3175. m_InPass = false;
  3176. #endif
  3177. }
  3178. CTempMeshDX8::~CTempMeshDX8()
  3179. {
  3180. }
  3181. //-----------------------------------------------------------------------------
  3182. // Is the temp mesh dynamic?
  3183. //-----------------------------------------------------------------------------
  3184. bool CTempMeshDX8::IsDynamic() const
  3185. {
  3186. return m_IsDynamic;
  3187. }
  3188. //-----------------------------------------------------------------------------
  3189. // Sets the vertex format
  3190. //-----------------------------------------------------------------------------
  3191. void CTempMeshDX8::SetVertexFormat( VertexFormat_t format )
  3192. {
  3193. CBaseMeshDX8::SetVertexFormat(format);
  3194. m_VertexSize = g_MeshMgr.VertexFormatSize( format );
  3195. }
  3196. //-----------------------------------------------------------------------------
  3197. // returns the # of vertices (static meshes only)
  3198. //-----------------------------------------------------------------------------
  3199. int CTempMeshDX8::VertexCount() const
  3200. {
  3201. return m_VertexSize ? m_VertexData.Count() / m_VertexSize : 0;
  3202. }
  3203. //-----------------------------------------------------------------------------
  3204. // returns the # of indices
  3205. //-----------------------------------------------------------------------------
  3206. int CTempMeshDX8::IndexCount( ) const
  3207. {
  3208. return m_IndexData.Count();
  3209. }
  3210. void CTempMeshDX8::ModifyBeginEx( bool bReadOnly, int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc )
  3211. {
  3212. Assert( !m_Locked );
  3213. m_LockedVerts = nVertexCount;
  3214. m_LockedIndices = nIndexCount;
  3215. if( nVertexCount > 0 )
  3216. {
  3217. int vertexByteOffset = m_VertexSize * nFirstVertex;
  3218. // Lock it baby
  3219. unsigned char* pVertexMemory = &m_VertexData[vertexByteOffset];
  3220. // Compute the vertex index..
  3221. desc.m_nFirstVertex = vertexByteOffset / m_VertexSize;
  3222. // Set up the mesh descriptor
  3223. g_MeshMgr.ComputeVertexDescription( pVertexMemory, m_VertexFormat, desc );
  3224. }
  3225. else
  3226. {
  3227. desc.m_nFirstVertex = 0;
  3228. // Set up the mesh descriptor
  3229. g_MeshMgr.ComputeVertexDescription( 0, 0, desc );
  3230. }
  3231. if (m_Type != MATERIAL_POINTS && nIndexCount > 0 )
  3232. {
  3233. desc.m_pIndices = &m_IndexData[nFirstIndex];
  3234. desc.m_nIndexSize = 1;
  3235. }
  3236. else
  3237. {
  3238. desc.m_pIndices = g_nScratchIndexBuffer;
  3239. desc.m_nIndexSize = 0;
  3240. }
  3241. #ifdef DBGFLAG_ASSERT
  3242. m_Locked = true;
  3243. #endif
  3244. }
  3245. void CTempMeshDX8::ModifyBegin( int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc )
  3246. {
  3247. ModifyBeginEx( false, nFirstVertex, nVertexCount, nFirstIndex, nIndexCount, desc );
  3248. }
  3249. void CTempMeshDX8::ModifyEnd( MeshDesc_t& desc )
  3250. {
  3251. #ifdef DBGFLAG_ASSERT
  3252. Assert( m_Locked );
  3253. m_Locked = false;
  3254. #endif
  3255. }
  3256. //-----------------------------------------------------------------------------
  3257. // Locks/unlocks the mesh
  3258. //-----------------------------------------------------------------------------
  3259. void CTempMeshDX8::LockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc )
  3260. {
  3261. ShaderUtil()->SyncMatrices();
  3262. g_ShaderMutex.Lock();
  3263. Assert( !m_Locked );
  3264. m_LockedVerts = nVertexCount;
  3265. m_LockedIndices = nIndexCount;
  3266. if( nVertexCount > 0 )
  3267. {
  3268. int vertexByteOffset = m_VertexData.AddMultipleToTail( m_VertexSize * nVertexCount );
  3269. // Lock it baby
  3270. unsigned char* pVertexMemory = &m_VertexData[vertexByteOffset];
  3271. // Compute the vertex index..
  3272. desc.m_nFirstVertex = vertexByteOffset / m_VertexSize;
  3273. // Set up the mesh descriptor
  3274. g_MeshMgr.ComputeVertexDescription( pVertexMemory, m_VertexFormat, desc );
  3275. }
  3276. else
  3277. {
  3278. desc.m_nFirstVertex = 0;
  3279. // Set up the mesh descriptor
  3280. g_MeshMgr.ComputeVertexDescription( 0, 0, desc );
  3281. }
  3282. if (m_Type != MATERIAL_POINTS && nIndexCount > 0 )
  3283. {
  3284. int nFirstIndex = m_IndexData.AddMultipleToTail( nIndexCount );
  3285. desc.m_pIndices = &m_IndexData[nFirstIndex];
  3286. desc.m_nIndexSize = 1;
  3287. }
  3288. else
  3289. {
  3290. desc.m_pIndices = g_nScratchIndexBuffer;
  3291. desc.m_nIndexSize = 0;
  3292. }
  3293. #ifdef DBGFLAG_ASSERT
  3294. m_Locked = true;
  3295. #endif
  3296. CBaseMeshDX8::m_bMeshLocked = true;
  3297. }
  3298. void CTempMeshDX8::UnlockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc )
  3299. {
  3300. Assert( m_Locked );
  3301. // Remove unused vertices and indices
  3302. int verticesToRemove = m_LockedVerts - nVertexCount;
  3303. if( verticesToRemove != 0 )
  3304. {
  3305. m_VertexData.RemoveMultiple( m_VertexData.Count() - verticesToRemove, verticesToRemove );
  3306. }
  3307. int indicesToRemove = m_LockedIndices - nIndexCount;
  3308. if( indicesToRemove != 0 )
  3309. {
  3310. m_IndexData.RemoveMultiple( m_IndexData.Count() - indicesToRemove, indicesToRemove );
  3311. }
  3312. #ifdef DBGFLAG_ASSERT
  3313. m_Locked = false;
  3314. #endif
  3315. CBaseMeshDX8::m_bMeshLocked = false;
  3316. g_ShaderMutex.Unlock();
  3317. }
  3318. //-----------------------------------------------------------------------------
  3319. // Sets the primitive type
  3320. //-----------------------------------------------------------------------------
  3321. void CTempMeshDX8::SetPrimitiveType( MaterialPrimitiveType_t type )
  3322. {
  3323. // FIXME: Support MATERIAL_INSTANCED_QUADS for CTempMeshDX8 (X360 only)
  3324. Assert( ( type != MATERIAL_INSTANCED_QUADS ) /* || IsX360() */ );
  3325. m_Type = type;
  3326. }
  3327. MaterialPrimitiveType_t CTempMeshDX8::GetPrimitiveType( ) const
  3328. {
  3329. return m_Type;
  3330. }
  3331. //-----------------------------------------------------------------------------
  3332. // Gets the dynamic mesh
  3333. //-----------------------------------------------------------------------------
  3334. CDynamicMeshDX8* CTempMeshDX8::GetDynamicMesh( )
  3335. {
  3336. return static_cast<CDynamicMeshDX8*>(g_MeshMgr.GetActualDynamicMesh( m_VertexFormat ));
  3337. }
  3338. //-----------------------------------------------------------------------------
  3339. // Draws the entire mesh
  3340. //-----------------------------------------------------------------------------
  3341. void CTempMeshDX8::Draw( int nFirstIndex, int nIndexCount )
  3342. {
  3343. if ( !ShaderUtil()->OnDrawMesh( this, nFirstIndex, nIndexCount ) )
  3344. {
  3345. MarkAsDrawn();
  3346. return;
  3347. }
  3348. if (m_VertexData.Count() > 0)
  3349. {
  3350. if ( !g_pShaderDeviceDx8->IsDeactivated() )
  3351. {
  3352. #ifdef DRAW_SELECTION
  3353. if (!g_bDrawSelection && !ShaderAPI()->IsInSelectionMode())
  3354. #else
  3355. if (!ShaderAPI()->IsInSelectionMode())
  3356. #endif
  3357. {
  3358. s_FirstIndex = nFirstIndex;
  3359. s_NumIndices = nIndexCount;
  3360. DrawMesh( );
  3361. // This assertion fails if a BeginPass() call was not matched by
  3362. // a RenderPass() call
  3363. Assert(!m_InPass);
  3364. }
  3365. else
  3366. {
  3367. TestSelection();
  3368. }
  3369. }
  3370. // Clear out the data if this temp mesh is a dynamic one...
  3371. if (m_IsDynamic)
  3372. {
  3373. m_VertexData.RemoveAll();
  3374. m_IndexData.RemoveAll();
  3375. }
  3376. }
  3377. }
  3378. void CTempMeshDX8::CopyToMeshBuilder(
  3379. int iStartVert, // Which vertices to copy.
  3380. int nVerts,
  3381. int iStartIndex, // Which indices to copy.
  3382. int nIndices,
  3383. int indexOffset, // This is added to each index.
  3384. CMeshBuilder &builder )
  3385. {
  3386. int startOffset = iStartVert * m_VertexSize;
  3387. int endOffset = (iStartVert + nVerts) * m_VertexSize;
  3388. Assert( startOffset >= 0 && startOffset <= m_VertexData.Count() );
  3389. Assert( endOffset >= 0 && endOffset <= m_VertexData.Count() && endOffset >= startOffset );
  3390. if ( endOffset > startOffset )
  3391. {
  3392. // FIXME: make this a method of CMeshBuilder (so the 'Position' pointer accessor can be removed)
  3393. // make sure it takes a VertexFormat_t parameter for src/dest match validation
  3394. memcpy( (void*)builder.Position(), &m_VertexData[startOffset], endOffset - startOffset );
  3395. builder.AdvanceVertices( nVerts );
  3396. }
  3397. for ( int i = 0; i < nIndices; ++i )
  3398. {
  3399. builder.Index( m_IndexData[iStartIndex+i] + indexOffset );
  3400. builder.AdvanceIndex();
  3401. }
  3402. }
  3403. //-----------------------------------------------------------------------------
  3404. // Selection mode helper functions
  3405. //-----------------------------------------------------------------------------
  3406. static void ComputeModelToView( D3DXMATRIX& modelToView )
  3407. {
  3408. // Get the modelview matrix...
  3409. D3DXMATRIX world, view;
  3410. ShaderAPI()->GetMatrix( MATERIAL_MODEL, (float*)&world );
  3411. ShaderAPI()->GetMatrix( MATERIAL_VIEW, (float*)&view );
  3412. D3DXMatrixMultiply( &modelToView, &world, &view );
  3413. }
  3414. static float ComputeCullFactor( )
  3415. {
  3416. D3DCULL cullMode = ShaderAPI()->GetCullMode();
  3417. float cullFactor;
  3418. switch(cullMode)
  3419. {
  3420. case D3DCULL_CCW:
  3421. cullFactor = -1.0f;
  3422. break;
  3423. case D3DCULL_CW:
  3424. cullFactor = 1.0f;
  3425. break;
  3426. default:
  3427. cullFactor = 0.0f;
  3428. break;
  3429. };
  3430. return cullFactor;
  3431. }
  3432. //-----------------------------------------------------------------------------
  3433. // Clip to viewport
  3434. //-----------------------------------------------------------------------------
  3435. static int g_NumClipVerts;
  3436. static D3DXVECTOR3 g_ClipVerts[16];
  3437. static bool PointInsidePlane( D3DXVECTOR3* pVert, int normalInd, float val, bool nearClip )
  3438. {
  3439. if ((val > 0) || nearClip)
  3440. return (val - (*pVert)[normalInd] >= 0);
  3441. else
  3442. return ((*pVert)[normalInd] - val >= 0);
  3443. }
  3444. static void IntersectPlane( D3DXVECTOR3* pStart, D3DXVECTOR3* pEnd,
  3445. int normalInd, float val, D3DXVECTOR3* pOutVert )
  3446. {
  3447. D3DXVECTOR3 dir;
  3448. D3DXVec3Subtract( &dir, pEnd, pStart );
  3449. Assert( dir[normalInd] != 0.0f );
  3450. float t = (val - (*pStart)[normalInd]) / dir[normalInd];
  3451. pOutVert->x = pStart->x + dir.x * t;
  3452. pOutVert->y = pStart->y + dir.y * t;
  3453. pOutVert->z = pStart->z + dir.z * t;
  3454. // Avoid any precision problems.
  3455. (*pOutVert)[normalInd] = val;
  3456. }
  3457. static int ClipTriangleAgainstPlane( D3DXVECTOR3** ppVert, int nVertexCount,
  3458. D3DXVECTOR3** ppOutVert, int normalInd, float val, bool nearClip = false )
  3459. {
  3460. // Ye Olde Sutherland-Hodgman clipping algorithm
  3461. int numOutVerts = 0;
  3462. D3DXVECTOR3* pStart = ppVert[nVertexCount-1];
  3463. bool startInside = PointInsidePlane( pStart, normalInd, val, nearClip );
  3464. for (int i = 0; i < nVertexCount; ++i)
  3465. {
  3466. D3DXVECTOR3* pEnd = ppVert[i];
  3467. bool endInside = PointInsidePlane( pEnd, normalInd, val, nearClip );
  3468. if (endInside)
  3469. {
  3470. if (!startInside)
  3471. {
  3472. IntersectPlane( pStart, pEnd, normalInd, val, &g_ClipVerts[g_NumClipVerts] );
  3473. ppOutVert[numOutVerts++] = &g_ClipVerts[g_NumClipVerts++];
  3474. }
  3475. ppOutVert[numOutVerts++] = pEnd;
  3476. }
  3477. else
  3478. {
  3479. if (startInside)
  3480. {
  3481. IntersectPlane( pStart, pEnd, normalInd, val, &g_ClipVerts[g_NumClipVerts] );
  3482. ppOutVert[numOutVerts++] = &g_ClipVerts[g_NumClipVerts++];
  3483. }
  3484. }
  3485. pStart = pEnd;
  3486. startInside = endInside;
  3487. }
  3488. return numOutVerts;
  3489. }
  3490. void CTempMeshDX8::ClipTriangle( D3DXVECTOR3** ppVert, float zNear, D3DXMATRIX& projection )
  3491. {
  3492. int i;
  3493. int nVertexCount = 3;
  3494. D3DXVECTOR3* ppClipVert1[10];
  3495. D3DXVECTOR3* ppClipVert2[10];
  3496. g_NumClipVerts = 0;
  3497. // Clip against the near plane in view space to prevent negative w.
  3498. // Clip against each plane
  3499. nVertexCount = ClipTriangleAgainstPlane( ppVert, nVertexCount, ppClipVert1, 2, zNear, true );
  3500. if (nVertexCount < 3)
  3501. return;
  3502. // Sucks that I have to do this, but I have to clip near plane in view space
  3503. // Clipping in projection space is screwy when w < 0
  3504. // Transform the clipped points into projection space
  3505. Assert( g_NumClipVerts <= 2 );
  3506. for (i = 0; i < nVertexCount; ++i)
  3507. {
  3508. if (ppClipVert1[i] == &g_ClipVerts[0])
  3509. {
  3510. D3DXVec3TransformCoord( &g_ClipVerts[0], ppClipVert1[i], &projection );
  3511. }
  3512. else if (ppClipVert1[i] == &g_ClipVerts[1])
  3513. {
  3514. D3DXVec3TransformCoord( &g_ClipVerts[1], ppClipVert1[i], &projection );
  3515. }
  3516. else
  3517. {
  3518. D3DXVec3TransformCoord( &g_ClipVerts[g_NumClipVerts], ppClipVert1[i], &projection );
  3519. ppClipVert1[i] = &g_ClipVerts[g_NumClipVerts];
  3520. ++g_NumClipVerts;
  3521. }
  3522. }
  3523. nVertexCount = ClipTriangleAgainstPlane( ppClipVert1, nVertexCount, ppClipVert2, 2, 1.0f );
  3524. if (nVertexCount < 3)
  3525. return;
  3526. nVertexCount = ClipTriangleAgainstPlane( ppClipVert2, nVertexCount, ppClipVert1, 0, 1.0f );
  3527. if (nVertexCount < 3)
  3528. return;
  3529. nVertexCount = ClipTriangleAgainstPlane( ppClipVert1, nVertexCount, ppClipVert2, 0, -1.0f );
  3530. if (nVertexCount < 3)
  3531. return;
  3532. nVertexCount = ClipTriangleAgainstPlane( ppClipVert2, nVertexCount, ppClipVert1, 1, 1.0f );
  3533. if (nVertexCount < 3)
  3534. return;
  3535. nVertexCount = ClipTriangleAgainstPlane( ppClipVert1, nVertexCount, ppClipVert2, 1, -1.0f );
  3536. if (nVertexCount < 3)
  3537. return;
  3538. #ifdef DRAW_SELECTION
  3539. if( 1 || g_bDrawSelection )
  3540. {
  3541. srand( *(int*)(&ppClipVert2[0]->x) );
  3542. unsigned char r = (unsigned char)(rand() * 191.0f / VALVE_RAND_MAX) + 64;
  3543. unsigned char g = (unsigned char)(rand() * 191.0f / VALVE_RAND_MAX) + 64;
  3544. unsigned char b = (unsigned char)(rand() * 191.0f / VALVE_RAND_MAX) + 64;
  3545. ShaderAPI()->SetupSelectionModeVisualizationState();
  3546. CMeshBuilder* pMeshBuilder = ShaderAPI()->GetVertexModifyBuilder();
  3547. IMesh* pMesh = GetDynamicMesh();
  3548. pMeshBuilder->Begin( pMesh, MATERIAL_POLYGON, nVertexCount );
  3549. for ( i = 0; i < nVertexCount; ++i)
  3550. {
  3551. pMeshBuilder->Position3fv( *ppClipVert2[i] );
  3552. pMeshBuilder->Color3ub( r, g, b );
  3553. pMeshBuilder->AdvanceVertex();
  3554. }
  3555. pMeshBuilder->End();
  3556. pMesh->Draw();
  3557. pMeshBuilder->Begin( pMesh, MATERIAL_LINE_LOOP, nVertexCount );
  3558. for ( i = 0; i < nVertexCount; ++i)
  3559. {
  3560. pMeshBuilder->Position3fv( *ppClipVert2[i] );
  3561. pMeshBuilder->Color3ub( 255, 255, 255 );
  3562. pMeshBuilder->AdvanceVertex();
  3563. }
  3564. pMeshBuilder->End();
  3565. pMesh->Draw();
  3566. }
  3567. #endif
  3568. // Compute closest and furthest verts
  3569. float minz = ppClipVert2[0]->z;
  3570. float maxz = ppClipVert2[0]->z;
  3571. for ( i = 1; i < nVertexCount; ++i )
  3572. {
  3573. if (ppClipVert2[i]->z < minz)
  3574. minz = ppClipVert2[i]->z;
  3575. else if (ppClipVert2[i]->z > maxz)
  3576. maxz = ppClipVert2[i]->z;
  3577. }
  3578. ShaderAPI()->RegisterSelectionHit( minz, maxz );
  3579. }
  3580. //-----------------------------------------------------------------------------
  3581. // Selection mode
  3582. //-----------------------------------------------------------------------------
  3583. void CTempMeshDX8::TestSelection()
  3584. {
  3585. // Note that this doesn't take into account any vertex modification
  3586. // done in a vertex shader. Also it doesn't take into account any clipping
  3587. // done in hardware
  3588. // Blow off points and lines; they don't matter
  3589. if ((m_Type != MATERIAL_TRIANGLES) && (m_Type != MATERIAL_TRIANGLE_STRIP))
  3590. return;
  3591. D3DXMATRIX modelToView, projection;
  3592. ComputeModelToView( modelToView );
  3593. ShaderAPI()->GetMatrix( MATERIAL_PROJECTION, (float*)&projection );
  3594. float zNear = -projection.m[3][2] / projection.m[2][2];
  3595. D3DXVECTOR3* pPos[3];
  3596. D3DXVECTOR3 edge[2];
  3597. D3DXVECTOR3 normal;
  3598. int numTriangles;
  3599. if (m_Type == MATERIAL_TRIANGLES)
  3600. numTriangles = m_IndexData.Count() / 3;
  3601. else
  3602. numTriangles = m_IndexData.Count() - 2;
  3603. float cullFactor = ComputeCullFactor();
  3604. // Makes the lovely loop simpler
  3605. if (m_Type == MATERIAL_TRIANGLE_STRIP)
  3606. cullFactor *= -1.0f;
  3607. // We'll need some temporary memory to tell us if we're transformed the vert
  3608. int nVertexCount = m_VertexData.Count() / m_VertexSize;
  3609. static CUtlVector< unsigned char > transformedVert;
  3610. int transformedVertSize = (nVertexCount + 7) >> 3;
  3611. transformedVert.RemoveAll();
  3612. transformedVert.EnsureCapacity( transformedVertSize );
  3613. transformedVert.AddMultipleToTail( transformedVertSize );
  3614. memset( transformedVert.Base(), 0, transformedVertSize );
  3615. int indexPos;
  3616. for (int i = 0; i < numTriangles; ++i)
  3617. {
  3618. // Get the three indices
  3619. if (m_Type == MATERIAL_TRIANGLES)
  3620. {
  3621. indexPos = i * 3;
  3622. }
  3623. else
  3624. {
  3625. Assert( m_Type == MATERIAL_TRIANGLE_STRIP );
  3626. cullFactor *= -1.0f;
  3627. indexPos = i;
  3628. }
  3629. // BAH. Gotta clip to the near clip plane in view space to prevent
  3630. // negative w coords; negative coords throw off the projection-space clipper.
  3631. // Get the three positions in view space
  3632. int inFrontIdx = -1;
  3633. for (int j = 0; j < 3; ++j)
  3634. {
  3635. int index = m_IndexData[indexPos];
  3636. D3DXVECTOR3* pPosition = (D3DXVECTOR3*)&m_VertexData[index * m_VertexSize];
  3637. if ((transformedVert[index >> 3] & (1 << (index & 0x7))) == 0)
  3638. {
  3639. D3DXVec3TransformCoord( pPosition, pPosition, &modelToView );
  3640. transformedVert[index >> 3] |= (1 << (index & 0x7));
  3641. }
  3642. pPos[j] = pPosition;
  3643. if (pPos[j]->z < 0.0f)
  3644. inFrontIdx = j;
  3645. ++indexPos;
  3646. }
  3647. // all points are behind the camera
  3648. if (inFrontIdx < 0)
  3649. continue;
  3650. // backface cull....
  3651. D3DXVec3Subtract( &edge[0], pPos[1], pPos[0] );
  3652. D3DXVec3Subtract( &edge[1], pPos[2], pPos[0] );
  3653. D3DXVec3Cross( &normal, &edge[0], &edge[1] );
  3654. float dot = D3DXVec3Dot( &normal, pPos[inFrontIdx] );
  3655. if (dot * cullFactor > 0.0f)
  3656. continue;
  3657. // Clip to viewport
  3658. ClipTriangle( pPos, zNear, projection );
  3659. }
  3660. }
  3661. //-----------------------------------------------------------------------------
  3662. // Begins a render pass
  3663. //-----------------------------------------------------------------------------
  3664. void CTempMeshDX8::BeginPass( )
  3665. {
  3666. Assert( !m_InPass );
  3667. #ifdef DBGFLAG_ASSERT
  3668. m_InPass = true;
  3669. #endif
  3670. CMeshBuilder* pMeshBuilder = ShaderAPI()->GetVertexModifyBuilder();
  3671. CDynamicMeshDX8* pMesh = GetDynamicMesh( );
  3672. int nIndexCount;
  3673. int nFirstIndex;
  3674. if ((s_FirstIndex == -1) && (s_NumIndices == 0))
  3675. {
  3676. nIndexCount = m_IndexData.Count();
  3677. nFirstIndex = 0;
  3678. }
  3679. else
  3680. {
  3681. nIndexCount = s_NumIndices;
  3682. nFirstIndex = s_FirstIndex;
  3683. }
  3684. int i;
  3685. int nVertexCount = m_VertexData.Count() / m_VertexSize;
  3686. pMeshBuilder->Begin( pMesh, m_Type, nVertexCount, nIndexCount );
  3687. // Copy in the vertex data...
  3688. // Note that since we pad the vertices, it's faster for us to simply
  3689. // copy the fields we're using...
  3690. Assert( pMeshBuilder->BaseVertexData() );
  3691. memcpy( pMeshBuilder->BaseVertexData(), m_VertexData.Base(), m_VertexData.Count() );
  3692. pMeshBuilder->AdvanceVertices( m_VertexData.Count() / m_VertexSize );
  3693. for ( i = 0; i < nIndexCount; ++i )
  3694. {
  3695. pMeshBuilder->Index( m_IndexData[nFirstIndex+i] );
  3696. pMeshBuilder->AdvanceIndex();
  3697. }
  3698. // NOTE: The client is expected to modify the data after this call is made
  3699. pMeshBuilder->Reset();
  3700. }
  3701. //-----------------------------------------------------------------------------
  3702. // Draws a single pass
  3703. //-----------------------------------------------------------------------------
  3704. void CTempMeshDX8::RenderPass()
  3705. {
  3706. Assert( m_InPass );
  3707. #ifdef DBGFLAG_ASSERT
  3708. m_InPass = false;
  3709. #endif
  3710. // Have the shader API modify the vertex data as it needs
  3711. // This vertex data is modified based on state set by the material
  3712. ShaderAPI()->ModifyVertexData( );
  3713. // Done building the mesh
  3714. ShaderAPI()->GetVertexModifyBuilder()->End();
  3715. // Have the dynamic mesh render a single pass...
  3716. GetDynamicMesh()->DrawSinglePassImmediately();
  3717. }
  3718. //-----------------------------------------------------------------------------
  3719. //
  3720. // Buffered mesh implementation
  3721. //
  3722. //-----------------------------------------------------------------------------
  3723. //-----------------------------------------------------------------------------
  3724. // constructor, destructor
  3725. //-----------------------------------------------------------------------------
  3726. CBufferedMeshDX8::CBufferedMeshDX8() : m_IsFlushing(false), m_WasRendered(true)
  3727. {
  3728. m_pMesh = NULL;
  3729. #ifdef DEBUG_BUFFERED_STATE
  3730. m_BufferedStateSet = false;
  3731. #endif
  3732. }
  3733. CBufferedMeshDX8::~CBufferedMeshDX8()
  3734. {
  3735. }
  3736. //-----------------------------------------------------------------------------
  3737. // Sets the mesh
  3738. //-----------------------------------------------------------------------------
  3739. void CBufferedMeshDX8::SetMesh( CBaseMeshDX8* pMesh )
  3740. {
  3741. if (m_pMesh != pMesh)
  3742. {
  3743. ShaderAPI()->FlushBufferedPrimitives();
  3744. m_pMesh = pMesh;
  3745. }
  3746. }
  3747. //-----------------------------------------------------------------------------
  3748. // Spews the mesh data
  3749. //-----------------------------------------------------------------------------
  3750. void CBufferedMeshDX8::Spew( int nVertexCount, int nIndexCount, const MeshDesc_t &spewDesc )
  3751. {
  3752. if ( m_pMesh )
  3753. {
  3754. m_pMesh->Spew( nVertexCount, nIndexCount, spewDesc );
  3755. }
  3756. }
  3757. //-----------------------------------------------------------------------------
  3758. // Sets the material
  3759. //-----------------------------------------------------------------------------
  3760. void CBufferedMeshDX8::SetVertexFormat( VertexFormat_t format )
  3761. {
  3762. Assert( m_pMesh );
  3763. if (m_pMesh->NeedsVertexFormatReset(format))
  3764. {
  3765. ShaderAPI()->FlushBufferedPrimitives();
  3766. m_pMesh->SetVertexFormat( format );
  3767. }
  3768. }
  3769. void CBufferedMeshDX8::SetMorphFormat( MorphFormat_t format )
  3770. {
  3771. Assert( m_pMesh );
  3772. m_pMesh->SetMorphFormat( format );
  3773. }
  3774. VertexFormat_t CBufferedMeshDX8::GetVertexFormat( ) const
  3775. {
  3776. Assert( m_pMesh );
  3777. return m_pMesh->GetVertexFormat();
  3778. }
  3779. void CBufferedMeshDX8::SetMaterial( IMaterial* pMaterial )
  3780. {
  3781. #if _DEBUG
  3782. Assert( m_pMesh );
  3783. m_pMesh->SetMaterial( pMaterial );
  3784. #endif
  3785. }
  3786. void CBufferedMeshDX8::ValidateData( int nVertexCount, int nIndexCount, const MeshDesc_t & spewDesc )
  3787. {
  3788. #if _DEBUG
  3789. Assert( m_pMesh );
  3790. m_pMesh->ValidateData( nVertexCount, nIndexCount, spewDesc );
  3791. #endif
  3792. }
  3793. //-----------------------------------------------------------------------------
  3794. // Sets the flex mesh to render with this mesh
  3795. //-----------------------------------------------------------------------------
  3796. void CBufferedMeshDX8::SetFlexMesh( IMesh *pMesh, int nVertexOffsetInBytes )
  3797. {
  3798. // FIXME: Probably are situations where we don't need to flush,
  3799. // but this is going to look different in a very short while, so I'm not going to bother
  3800. ShaderAPI()->FlushBufferedPrimitives();
  3801. m_pMesh->SetFlexMesh( pMesh, nVertexOffsetInBytes );
  3802. }
  3803. //-----------------------------------------------------------------------------
  3804. // checks to see if it was rendered..
  3805. //-----------------------------------------------------------------------------
  3806. void CBufferedMeshDX8::ResetRendered()
  3807. {
  3808. m_WasRendered = false;
  3809. }
  3810. bool CBufferedMeshDX8::WasNotRendered() const
  3811. {
  3812. return !m_WasRendered;
  3813. }
  3814. //-----------------------------------------------------------------------------
  3815. // "Draws" it
  3816. //-----------------------------------------------------------------------------
  3817. void CBufferedMeshDX8::Draw( int nFirstIndex, int nIndexCount )
  3818. {
  3819. if ( !ShaderUtil()->OnDrawMesh( this, nFirstIndex, nIndexCount ) )
  3820. {
  3821. m_WasRendered = true;
  3822. MarkAsDrawn();
  3823. return;
  3824. }
  3825. Assert( !m_IsFlushing && !m_WasRendered );
  3826. // Gotta draw all of the buffered mesh
  3827. Assert( (nFirstIndex == -1) && (nIndexCount == 0) );
  3828. // No need to draw it more than once...
  3829. m_WasRendered = true;
  3830. // We've got something to flush
  3831. m_FlushNeeded = true;
  3832. // Less than 0 indices indicates we were using a standard buffer
  3833. if ( m_pMesh->HasFlexMesh() || !ShaderUtil()->GetConfig().bBufferPrimitives )
  3834. {
  3835. ShaderAPI()->FlushBufferedPrimitives();
  3836. }
  3837. }
  3838. //-----------------------------------------------------------------------------
  3839. // Sets the primitive mode
  3840. //-----------------------------------------------------------------------------
  3841. void CBufferedMeshDX8::SetPrimitiveType( MaterialPrimitiveType_t type )
  3842. {
  3843. Assert( IsX360() || ( type != MATERIAL_INSTANCED_QUADS ) );
  3844. Assert( type != MATERIAL_HETEROGENOUS );
  3845. if (type != GetPrimitiveType())
  3846. {
  3847. ShaderAPI()->FlushBufferedPrimitives();
  3848. m_pMesh->SetPrimitiveType(type);
  3849. }
  3850. }
  3851. MaterialPrimitiveType_t CBufferedMeshDX8::GetPrimitiveType( ) const
  3852. {
  3853. return m_pMesh->GetPrimitiveType();
  3854. }
  3855. //-----------------------------------------------------------------------------
  3856. // Locks/unlocks the entire mesh
  3857. //-----------------------------------------------------------------------------
  3858. void CBufferedMeshDX8::LockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc )
  3859. {
  3860. ShaderUtil()->SyncMatrices();
  3861. Assert( m_pMesh );
  3862. Assert( m_WasRendered );
  3863. // Do some pre-lock processing
  3864. m_pMesh->PreLock();
  3865. // for tristrips, gotta make degenerate ones...
  3866. m_ExtraIndices = 0;
  3867. bool tristripFixup = (m_pMesh->IndexCount() != 0) &&
  3868. (m_pMesh->GetPrimitiveType() == MATERIAL_TRIANGLE_STRIP);
  3869. if (tristripFixup)
  3870. {
  3871. m_ExtraIndices = (m_pMesh->IndexCount() & 0x1) != 0 ? 3 : 2;
  3872. nIndexCount += m_ExtraIndices;
  3873. }
  3874. // Flush if we gotta
  3875. if (!m_pMesh->HasEnoughRoom(nVertexCount, nIndexCount))
  3876. {
  3877. ShaderAPI()->FlushBufferedPrimitives();
  3878. }
  3879. m_pMesh->LockMesh( nVertexCount, nIndexCount, desc );
  3880. // This is taken care of in the function above.
  3881. // CBaseMeshDX8::m_bMeshLocked = true;
  3882. // Deal with fixing up the tristrip..
  3883. if ( tristripFixup && desc.m_nIndexSize )
  3884. {
  3885. char buf[32];
  3886. if (DebugTrace())
  3887. {
  3888. if (m_ExtraIndices == 3)
  3889. sprintf(buf,"Link Index: %d %d\n", m_LastIndex, m_LastIndex);
  3890. else
  3891. sprintf(buf,"Link Index: %d\n", m_LastIndex);
  3892. Plat_DebugString(buf);
  3893. }
  3894. *desc.m_pIndices++ = m_LastIndex;
  3895. if (m_ExtraIndices == 3)
  3896. {
  3897. *desc.m_pIndices++ = m_LastIndex;
  3898. }
  3899. // Leave room for the last padding index
  3900. ++desc.m_pIndices;
  3901. }
  3902. m_WasRendered = false;
  3903. #ifdef DEBUG_BUFFERED_MESHES
  3904. if (m_BufferedStateSet)
  3905. {
  3906. BufferedState_t compare;
  3907. ShaderAPI()->GetBufferedState( compare );
  3908. Assert( !memcmp( &compare, &m_BufferedState, sizeof(compare) ) );
  3909. }
  3910. else
  3911. {
  3912. ShaderAPI()->GetBufferedState( m_BufferedState );
  3913. m_BufferedStateSet = true;
  3914. }
  3915. #endif
  3916. }
  3917. //-----------------------------------------------------------------------------
  3918. // Locks/unlocks the entire mesh
  3919. //-----------------------------------------------------------------------------
  3920. void CBufferedMeshDX8::UnlockMesh( int nVertexCount, int nIndexCount, MeshDesc_t& desc )
  3921. {
  3922. Assert( m_pMesh );
  3923. // Gotta fix up the first index to batch strips reasonably
  3924. if ((m_pMesh->GetPrimitiveType() == MATERIAL_TRIANGLE_STRIP) && desc.m_nIndexSize )
  3925. {
  3926. if (m_ExtraIndices > 0)
  3927. {
  3928. *(desc.m_pIndices - 1) = *desc.m_pIndices;
  3929. if (DebugTrace())
  3930. {
  3931. char buf[32];
  3932. sprintf(buf,"Link Index: %d\n", *desc.m_pIndices);
  3933. Plat_DebugString(buf);
  3934. }
  3935. }
  3936. // Remember the last index for next time
  3937. m_LastIndex = desc.m_pIndices[nIndexCount - 1];
  3938. nIndexCount += m_ExtraIndices;
  3939. }
  3940. m_pMesh->UnlockMesh( nVertexCount, nIndexCount, desc );
  3941. // This is taken care of in the function above.
  3942. // CBaseMeshDX8::m_bMeshLocked = false;
  3943. }
  3944. //-----------------------------------------------------------------------------
  3945. // Renders a pass
  3946. //-----------------------------------------------------------------------------
  3947. void CBufferedMeshDX8::RenderPass()
  3948. {
  3949. // this should never be called!
  3950. Assert(0);
  3951. }
  3952. //-----------------------------------------------------------------------------
  3953. // Flushes queued data
  3954. //-----------------------------------------------------------------------------
  3955. void CBufferedMeshDX8::Flush( )
  3956. {
  3957. // If you are hitting this assert you are causing a flush between a
  3958. // meshbuilder begin/end and you are more than likely losing rendering data.
  3959. AssertOnce( !CBaseMeshDX8::m_bMeshLocked );
  3960. if ( m_pMesh && !m_IsFlushing && m_FlushNeeded )
  3961. {
  3962. VPROF( "CBufferedMeshDX8::Flush" );
  3963. #ifdef DEBUG_BUFFERED_MESHES
  3964. if( m_BufferedStateSet )
  3965. {
  3966. BufferedState_t compare;
  3967. ShaderAPI()->GetBufferedState( compare );
  3968. Assert( !memcmp( &compare, &m_BufferedState, sizeof(compare) ) );
  3969. m_BufferedStateSet = false;
  3970. }
  3971. #endif
  3972. m_IsFlushing = true;
  3973. // Actually draws the data using the mesh's material
  3974. static_cast<IMesh*>(m_pMesh)->Draw();
  3975. m_IsFlushing = false;
  3976. m_FlushNeeded = false;
  3977. m_pMesh->SetFlexMesh( NULL, 0 );
  3978. }
  3979. }
  3980. //-----------------------------------------------------------------------------
  3981. //
  3982. // Mesh manager implementation
  3983. //
  3984. //-----------------------------------------------------------------------------
  3985. //-----------------------------------------------------------------------------
  3986. // Constructor, destructor
  3987. //-----------------------------------------------------------------------------
  3988. CMeshMgr::CMeshMgr() :
  3989. m_pDynamicIndexBuffer(0),
  3990. m_DynamicTempMesh(true),
  3991. m_pVertexIDBuffer(0),
  3992. m_pCurrentVertexBuffer( NULL ),
  3993. m_CurrentVertexFormat( 0 ),
  3994. m_pCurrentIndexBuffer( NULL ),
  3995. m_DynamicIndexBuffer( SHADER_BUFFER_TYPE_DYNAMIC, MATERIAL_INDEX_FORMAT_16BIT, INDEX_BUFFER_SIZE, "dynamic" ),
  3996. m_DynamicVertexBuffer( SHADER_BUFFER_TYPE_DYNAMIC, VERTEX_FORMAT_UNKNOWN, DYNAMIC_VERTEX_BUFFER_MEMORY, "dynamic" )
  3997. {
  3998. m_bUseFatVertices = false;
  3999. m_nIndexBufferOffset = 0;
  4000. memset( m_pVertexBufferOffset, 0, sizeof(m_pVertexBufferOffset) );
  4001. memset( m_pCurrentVertexStride, 0, sizeof(m_pCurrentVertexStride) );
  4002. memset( m_pFirstVertex, 0, sizeof(m_pFirstVertex) );
  4003. memset( m_pVertexCount, 0, sizeof(m_pVertexCount) );
  4004. m_nUnusedVertexFields = 0;
  4005. m_nUnusedTextureCoords = 0;
  4006. m_pZeroVertexBuffer = NULL;
  4007. }
  4008. CMeshMgr::~CMeshMgr()
  4009. {
  4010. }
  4011. //-----------------------------------------------------------------------------
  4012. // Initialize, shutdown
  4013. //-----------------------------------------------------------------------------
  4014. void CMeshMgr::Init()
  4015. {
  4016. m_DynamicMesh.Init( 0 );
  4017. m_DynamicFlexMesh.Init( 1 );
  4018. CreateDynamicIndexBuffer();
  4019. // If we're running in vs3.0, allocate a vertexID buffer
  4020. CreateVertexIDBuffer();
  4021. CreateZeroVertexBuffer();
  4022. m_BufferedMode = !IsX360();
  4023. }
  4024. void CMeshMgr::Shutdown()
  4025. {
  4026. CleanUp();
  4027. }
  4028. //-----------------------------------------------------------------------------
  4029. // Task switch...
  4030. //-----------------------------------------------------------------------------
  4031. void CMeshMgr::ReleaseBuffers()
  4032. {
  4033. if ( IsPC() && mat_debugalttab.GetBool() )
  4034. {
  4035. Warning( "mat_debugalttab: CMeshMgr::ReleaseBuffers\n" );
  4036. }
  4037. CleanUp();
  4038. m_DynamicMesh.Reset( );
  4039. m_DynamicFlexMesh.Reset( );
  4040. }
  4041. void CMeshMgr::RestoreBuffers()
  4042. {
  4043. if ( IsPC() && mat_debugalttab.GetBool() )
  4044. {
  4045. Warning( "mat_debugalttab: CMeshMgr::RestoreBuffers\n" );
  4046. }
  4047. Init();
  4048. }
  4049. //-----------------------------------------------------------------------------
  4050. // Cleans up vertex and index buffers
  4051. //-----------------------------------------------------------------------------
  4052. void CMeshMgr::CleanUp()
  4053. {
  4054. DestroyDynamicIndexBuffer();
  4055. DestroyVertexBuffers();
  4056. // If we're running in vs3.0, allocate a vertexID buffer
  4057. DestroyVertexIDBuffer();
  4058. DestroyZeroVertexBuffer();
  4059. }
  4060. //-----------------------------------------------------------------------------
  4061. // Fills a vertexID buffer
  4062. //-----------------------------------------------------------------------------
  4063. void CMeshMgr::FillVertexIDBuffer( CVertexBuffer *pVertexIDBuffer, int nCount )
  4064. {
  4065. if ( IsX360() )
  4066. return;
  4067. // Fill the buffer with the values 0->(nCount-1)
  4068. int nBaseVertexIndex = 0;
  4069. float *pBuffer = (float*)pVertexIDBuffer->Lock( nCount, nBaseVertexIndex );
  4070. for ( int i = 0; i < nCount; ++i )
  4071. {
  4072. *pBuffer++ = (float)i;
  4073. }
  4074. pVertexIDBuffer->Unlock( nCount );
  4075. }
  4076. //-----------------------------------------------------------------------------
  4077. // Creates, destroys the dynamic index buffer
  4078. //-----------------------------------------------------------------------------
  4079. void CMeshMgr::CreateDynamicIndexBuffer()
  4080. {
  4081. DestroyDynamicIndexBuffer();
  4082. SafeAssign( &m_pDynamicIndexBuffer, new CIndexBuffer( Dx9Device(), INDEX_BUFFER_SIZE, ShaderAPI()->UsingSoftwareVertexProcessing(), true ) );
  4083. }
  4084. void CMeshMgr::DestroyDynamicIndexBuffer()
  4085. {
  4086. SafeRelease( &m_pDynamicIndexBuffer );
  4087. }
  4088. //-----------------------------------------------------------------------------
  4089. // Creates, destroys the vertexID buffer
  4090. //-----------------------------------------------------------------------------
  4091. void CMeshMgr::CreateVertexIDBuffer()
  4092. {
  4093. if ( IsX360() )
  4094. return;
  4095. DestroyVertexIDBuffer();
  4096. // Track mesh allocations
  4097. g_VBAllocTracker->TrackMeshAllocations( "CreateVertexIDBuffer" );
  4098. if ( g_pHardwareConfig->HasFastVertexTextures() )
  4099. {
  4100. m_pVertexIDBuffer = new CVertexBuffer( Dx9Device(), 0, 0, sizeof(float),
  4101. VERTEX_BUFFER_SIZE, TEXTURE_GROUP_STATIC_VERTEX_BUFFER_OTHER, ShaderAPI()->UsingSoftwareVertexProcessing() );
  4102. FillVertexIDBuffer( m_pVertexIDBuffer, VERTEX_BUFFER_SIZE );
  4103. }
  4104. g_VBAllocTracker->TrackMeshAllocations( NULL );
  4105. }
  4106. void CMeshMgr::CreateZeroVertexBuffer()
  4107. {
  4108. if ( !m_pZeroVertexBuffer )
  4109. {
  4110. // In GL glVertexAttribPointer() doesn't support strides of 0, so we need to allocate a dummy vertex buffer large enough to handle 16-bit indices with a stride of 4 byte per vertex, plus a bit more for safety (in case basevertexindex is > 0).
  4111. // We could also try just disabling any vertex attribs that fetch from stream 2 and need 0's, but AMD reports this could hit a slow path in the driver. Argh.
  4112. uint nBufSize = IsOpenGL() ? ( 65536 * 2 * 4 ) : 4096;
  4113. HRESULT hr = Dx9Device()->CreateVertexBuffer( nBufSize, D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &m_pZeroVertexBuffer, NULL );
  4114. if ( !FAILED( hr ) )
  4115. {
  4116. void *pData = NULL;
  4117. m_pZeroVertexBuffer->Lock( 0, nBufSize, &pData, D3DLOCK_NOSYSLOCK );
  4118. if ( pData )
  4119. {
  4120. V_memset( pData, 0, nBufSize );
  4121. m_pZeroVertexBuffer->Unlock();
  4122. }
  4123. }
  4124. }
  4125. }
  4126. void CMeshMgr::DestroyZeroVertexBuffer()
  4127. {
  4128. if ( m_pZeroVertexBuffer )
  4129. {
  4130. m_pZeroVertexBuffer->Release();
  4131. m_pZeroVertexBuffer = NULL;
  4132. }
  4133. }
  4134. void CMeshMgr::DestroyVertexIDBuffer()
  4135. {
  4136. if ( m_pVertexIDBuffer )
  4137. {
  4138. delete m_pVertexIDBuffer;
  4139. m_pVertexIDBuffer = NULL;
  4140. }
  4141. }
  4142. CVertexBuffer *CMeshMgr::GetVertexIDBuffer( )
  4143. {
  4144. return m_pVertexIDBuffer;
  4145. }
  4146. //-----------------------------------------------------------------------------
  4147. // Unused vertex fields
  4148. //-----------------------------------------------------------------------------
  4149. void CMeshMgr::MarkUnusedVertexFields( unsigned int nFlags, int nTexCoordCount, bool *pUnusedTexCoords )
  4150. {
  4151. m_nUnusedVertexFields = nFlags;
  4152. m_nUnusedTextureCoords = 0;
  4153. for ( int i = 0; i < nTexCoordCount; ++i )
  4154. {
  4155. if ( pUnusedTexCoords[i] )
  4156. {
  4157. m_nUnusedTextureCoords |= ( 1 << i );
  4158. }
  4159. }
  4160. }
  4161. //-----------------------------------------------------------------------------
  4162. // Is the mesh dynamic?
  4163. //-----------------------------------------------------------------------------
  4164. bool CMeshMgr::IsDynamicMesh( IMesh* pMesh ) const
  4165. {
  4166. return ( pMesh == &m_DynamicMesh ) || ( pMesh == &m_DynamicFlexMesh );
  4167. }
  4168. bool CMeshMgr::IsBufferedDynamicMesh( IMesh* pMesh ) const
  4169. {
  4170. return ( pMesh == &m_BufferedMesh );
  4171. }
  4172. bool CMeshMgr::IsDynamicVertexBuffer( IVertexBuffer *pVertexBuffer ) const
  4173. {
  4174. return ( pVertexBuffer == &m_DynamicVertexBuffer );
  4175. }
  4176. bool CMeshMgr::IsDynamicIndexBuffer( IIndexBuffer *pIndexBuffer ) const
  4177. {
  4178. return ( pIndexBuffer == &m_DynamicIndexBuffer );
  4179. }
  4180. //-----------------------------------------------------------------------------
  4181. // Discards the dynamic vertex and index buffer
  4182. //-----------------------------------------------------------------------------
  4183. void CMeshMgr::DiscardVertexBuffers()
  4184. {
  4185. VPROF_BUDGET( "CMeshMgr::DiscardVertexBuffers", VPROF_BUDGETGROUP_SWAP_BUFFERS );
  4186. // This shouldn't be necessary, but it seems to be on GeForce 2
  4187. // It helps when running WC and the engine simultaneously.
  4188. ResetMeshRenderState();
  4189. if ( !g_pShaderDeviceDx8->IsDeactivated() )
  4190. {
  4191. for (int i = m_DynamicVertexBuffers.Count(); --i >= 0; )
  4192. {
  4193. m_DynamicVertexBuffers[i].m_pBuffer->FlushAtFrameStart();
  4194. }
  4195. m_pDynamicIndexBuffer->FlushAtFrameStart();
  4196. }
  4197. }
  4198. //-----------------------------------------------------------------------------
  4199. // Releases all dynamic vertex buffers
  4200. //-----------------------------------------------------------------------------
  4201. void CMeshMgr::DestroyVertexBuffers()
  4202. {
  4203. // Necessary for cleanup
  4204. RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
  4205. RECORD_INT( -1 );
  4206. RECORD_INT( 0 );
  4207. RECORD_INT( 0 );
  4208. RECORD_INT( 0 );
  4209. D3DSetStreamSource( 0, 0, 0, 0 );
  4210. RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
  4211. RECORD_INT( -1 );
  4212. RECORD_INT( 1 );
  4213. RECORD_INT( 0 );
  4214. RECORD_INT( 0 );
  4215. D3DSetStreamSource( 1, 0, 0, 0 );
  4216. RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
  4217. RECORD_INT( -1 );
  4218. RECORD_INT( 2 );
  4219. RECORD_INT( 0 );
  4220. RECORD_INT( 0 );
  4221. D3DSetStreamSource( 2, 0, 0, 0 );
  4222. #ifndef _X360
  4223. RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
  4224. RECORD_INT( -1 );
  4225. RECORD_INT( 3 );
  4226. RECORD_INT( 0 );
  4227. RECORD_INT( 0 );
  4228. D3DSetStreamSource( 3, 0, 0, 0 );
  4229. #endif
  4230. for (int i = m_DynamicVertexBuffers.Count(); --i >= 0; )
  4231. {
  4232. if (m_DynamicVertexBuffers[i].m_pBuffer)
  4233. {
  4234. delete m_DynamicVertexBuffers[i].m_pBuffer;
  4235. }
  4236. }
  4237. m_DynamicVertexBuffers.RemoveAll();
  4238. m_DynamicMesh.Reset();
  4239. m_DynamicFlexMesh.Reset();
  4240. }
  4241. //-----------------------------------------------------------------------------
  4242. // Flushes the dynamic mesh
  4243. //-----------------------------------------------------------------------------
  4244. void CMeshMgr::Flush()
  4245. {
  4246. if ( IsPC() )
  4247. {
  4248. m_BufferedMesh.HandleLateCreation();
  4249. m_BufferedMesh.Flush();
  4250. }
  4251. }
  4252. //-----------------------------------------------------------------------------
  4253. // Creates, destroys static meshes
  4254. //-----------------------------------------------------------------------------
  4255. IMesh* CMeshMgr::CreateStaticMesh( VertexFormat_t format, const char *pTextureBudgetGroup, IMaterial * pMaterial )
  4256. {
  4257. // FIXME: Use a fixed-size allocator
  4258. CMeshDX8* pNewMesh = new CMeshDX8( pTextureBudgetGroup );
  4259. pNewMesh->SetVertexFormat( format );
  4260. if ( pMaterial != NULL )
  4261. {
  4262. pNewMesh->SetMorphFormat( pMaterial->GetMorphFormat() );
  4263. pNewMesh->SetMaterial( pMaterial );
  4264. }
  4265. return pNewMesh;
  4266. }
  4267. void CMeshMgr::DestroyStaticMesh( IMesh* pMesh )
  4268. {
  4269. // Don't destroy the dynamic mesh!
  4270. Assert( !IsDynamicMesh( pMesh ) );
  4271. CBaseMeshDX8* pMeshImp = static_cast<CBaseMeshDX8*>(pMesh);
  4272. if (pMeshImp)
  4273. {
  4274. delete pMeshImp;
  4275. }
  4276. }
  4277. //-----------------------------------------------------------------------------
  4278. // Gets at the *real* dynamic mesh
  4279. //-----------------------------------------------------------------------------
  4280. IMesh* CMeshMgr::GetActualDynamicMesh( VertexFormat_t format )
  4281. {
  4282. m_DynamicMesh.SetVertexFormat( format );
  4283. return &m_DynamicMesh;
  4284. }
  4285. //-----------------------------------------------------------------------------
  4286. // Copy a static mesh index buffer to a dynamic mesh index buffer
  4287. //-----------------------------------------------------------------------------
  4288. void CMeshMgr::CopyStaticMeshIndexBufferToTempMeshIndexBuffer( CTempMeshDX8 *pDstIndexMesh,
  4289. CMeshDX8 *pSrcIndexMesh )
  4290. {
  4291. tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s", __FUNCTION__ );
  4292. Assert( !pSrcIndexMesh->IsDynamic() );
  4293. int nIndexCount = pSrcIndexMesh->IndexCount();
  4294. CMeshBuilder dstMeshBuilder;
  4295. dstMeshBuilder.Begin( pDstIndexMesh, pSrcIndexMesh->GetPrimitiveType(), 0, nIndexCount );
  4296. CIndexBuffer *srcIndexBuffer = pSrcIndexMesh->GetIndexBuffer();
  4297. int dummy = 0;
  4298. unsigned short *srcIndexArray = srcIndexBuffer->Lock( false, nIndexCount, dummy, 0 );
  4299. int i;
  4300. for( i = 0; i < nIndexCount; i++ )
  4301. {
  4302. dstMeshBuilder.Index( srcIndexArray[i] );
  4303. dstMeshBuilder.AdvanceIndex();
  4304. }
  4305. srcIndexBuffer->Unlock( 0 );
  4306. dstMeshBuilder.End();
  4307. }
  4308. IMesh *CMeshMgr::GetFlexMesh()
  4309. {
  4310. if ( g_pMaterialSystemHardwareConfig->SupportsPixelShaders_2_b() )
  4311. {
  4312. // FIXME: Kinda ugly size.. 28 bytes
  4313. m_DynamicFlexMesh.SetVertexFormat( VERTEX_POSITION | VERTEX_NORMAL | VERTEX_WRINKLE | VERTEX_FORMAT_USE_EXACT_FORMAT );
  4314. }
  4315. else
  4316. {
  4317. // Same size as a pair of float3s (24 bytes)
  4318. m_DynamicFlexMesh.SetVertexFormat( VERTEX_POSITION | VERTEX_NORMAL | VERTEX_FORMAT_USE_EXACT_FORMAT );
  4319. }
  4320. return &m_DynamicFlexMesh;
  4321. }
  4322. //-----------------------------------------------------------------------------
  4323. // Gets at the dynamic mesh
  4324. //-----------------------------------------------------------------------------
  4325. IMesh* CMeshMgr::GetDynamicMesh( IMaterial* pMaterial, VertexFormat_t vertexFormat, int nHWSkinBoneCount,
  4326. bool buffered, IMesh* pVertexOverride, IMesh* pIndexOverride )
  4327. {
  4328. tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s", __FUNCTION__ );
  4329. Assert( (pMaterial == NULL) || ((IMaterialInternal *)pMaterial)->IsRealTimeVersion() );
  4330. if ( IsX360() )
  4331. {
  4332. buffered = false;
  4333. }
  4334. // Can't be buffered if we're overriding the buffers
  4335. if ( pVertexOverride || pIndexOverride )
  4336. {
  4337. buffered = false;
  4338. }
  4339. // When going from buffered to unbuffered mode, need to flush..
  4340. if ((m_BufferedMode != buffered) && m_BufferedMode)
  4341. {
  4342. m_BufferedMesh.SetMesh(0);
  4343. }
  4344. m_BufferedMode = buffered;
  4345. IMaterialInternal* pMatInternal = static_cast<IMaterialInternal*>(pMaterial);
  4346. bool needTempMesh = ShaderAPI()->IsInSelectionMode();
  4347. #ifdef DRAW_SELECTION
  4348. if( g_bDrawSelection )
  4349. {
  4350. needTempMesh = true;
  4351. }
  4352. #endif
  4353. CBaseMeshDX8* pMesh;
  4354. if ( needTempMesh )
  4355. {
  4356. // These haven't been implemented yet for temp meshes!
  4357. // I'm not a hundred percent sure how to implement them; it would
  4358. // involve a lock and a copy at least, which would stall the entire
  4359. // rendering pipeline.
  4360. Assert( !pVertexOverride );
  4361. if( pIndexOverride )
  4362. {
  4363. CopyStaticMeshIndexBufferToTempMeshIndexBuffer( &m_DynamicTempMesh,
  4364. ( CMeshDX8 * )pIndexOverride );
  4365. }
  4366. pMesh = &m_DynamicTempMesh;
  4367. }
  4368. else
  4369. {
  4370. pMesh = &m_DynamicMesh;
  4371. }
  4372. if ( m_BufferedMode )
  4373. {
  4374. Assert( !m_BufferedMesh.WasNotRendered() );
  4375. m_BufferedMesh.SetMesh( pMesh );
  4376. pMesh = &m_BufferedMesh;
  4377. }
  4378. if( !pVertexOverride )
  4379. {
  4380. // Remove VERTEX_FORMAT_COMPRESSED from the material's format (dynamic meshes don't
  4381. // support compression, and all materials should support uncompressed verts too)
  4382. VertexFormat_t materialFormat = pMatInternal->GetVertexFormat() & ~VERTEX_FORMAT_COMPRESSED;
  4383. VertexFormat_t fmt = ( vertexFormat != 0 ) ? vertexFormat : materialFormat;
  4384. if ( vertexFormat != 0 )
  4385. {
  4386. int nVertexFormatBoneWeights = NumBoneWeights( vertexFormat );
  4387. if ( nHWSkinBoneCount < nVertexFormatBoneWeights )
  4388. {
  4389. nHWSkinBoneCount = nVertexFormatBoneWeights;
  4390. }
  4391. }
  4392. // Force the requested number of bone weights
  4393. fmt &= ~VERTEX_BONE_WEIGHT_MASK;
  4394. if ( nHWSkinBoneCount > 0 )
  4395. {
  4396. fmt |= VERTEX_BONEWEIGHT( 2 );
  4397. fmt |= VERTEX_BONE_INDEX;
  4398. }
  4399. pMesh->SetVertexFormat( fmt );
  4400. }
  4401. else
  4402. {
  4403. CBaseMeshDX8 *pDX8Mesh = static_cast<CBaseMeshDX8*>(pVertexOverride);
  4404. pMesh->SetVertexFormat( pDX8Mesh->GetVertexFormat() );
  4405. }
  4406. pMesh->SetMorphFormat( pMatInternal->GetMorphFormat() );
  4407. pMesh->SetMaterial( pMatInternal );
  4408. // Note this works because we're guaranteed to not be using a buffered mesh
  4409. // when we have overrides on
  4410. // FIXME: Make work for temp meshes
  4411. if ( pMesh == &m_DynamicMesh )
  4412. {
  4413. CBaseMeshDX8* pBaseVertex = static_cast<CBaseMeshDX8*>( pVertexOverride );
  4414. if ( pBaseVertex )
  4415. {
  4416. m_DynamicMesh.OverrideVertexBuffer( pBaseVertex->GetVertexBuffer() );
  4417. }
  4418. CBaseMeshDX8* pBaseIndex = static_cast<CBaseMeshDX8*>( pIndexOverride );
  4419. if ( pBaseIndex )
  4420. {
  4421. m_DynamicMesh.OverrideIndexBuffer( pBaseIndex->GetIndexBuffer() );
  4422. }
  4423. }
  4424. return pMesh;
  4425. }
  4426. //-----------------------------------------------------------------------------
  4427. // Used to construct vertex data
  4428. //-----------------------------------------------------------------------------
  4429. void CMeshMgr::ComputeVertexDescription( unsigned char* pBuffer,
  4430. VertexFormat_t vertexFormat, MeshDesc_t& desc ) const
  4431. {
  4432. ComputeVertexDesc( pBuffer, vertexFormat, (VertexDesc_t &)desc );
  4433. }
  4434. //-----------------------------------------------------------------------------
  4435. // Computes the vertex format
  4436. //-----------------------------------------------------------------------------
  4437. VertexFormat_t CMeshMgr::ComputeVertexFormat( unsigned int flags,
  4438. int nTexCoordArraySize, int* pTexCoordDimensions, int numBoneWeights,
  4439. int userDataSize ) const
  4440. {
  4441. // Construct a bitfield that makes sense and is unique from the standard FVF formats
  4442. VertexFormat_t fmt = flags & ~VERTEX_FORMAT_USE_EXACT_FORMAT;
  4443. if ( g_pHardwareConfig->SupportsCompressedVertices() == VERTEX_COMPRESSION_NONE )
  4444. {
  4445. // Vertex compression is disabled - make sure all materials
  4446. // say "No!" to compressed verts ( tested in IsValidVertexFormat() )
  4447. fmt &= ~VERTEX_FORMAT_COMPRESSED;
  4448. }
  4449. // This'll take 3 bits at most
  4450. Assert( numBoneWeights <= 4 );
  4451. if ( numBoneWeights > 0 )
  4452. {
  4453. fmt |= VERTEX_BONEWEIGHT( 2 ); // Always exactly two weights
  4454. }
  4455. // Size is measured in # of floats
  4456. Assert( userDataSize <= 4 );
  4457. fmt |= VERTEX_USERDATA_SIZE(userDataSize);
  4458. // NOTE: If pTexCoordDimensions isn't specified, then nTexCoordArraySize
  4459. // is interpreted as meaning that we have n 2D texcoords in the first N texcoord slots
  4460. nTexCoordArraySize = min( nTexCoordArraySize, (int)VERTEX_MAX_TEXTURE_COORDINATES );
  4461. for ( int i = 0; i < nTexCoordArraySize; ++i )
  4462. {
  4463. if ( pTexCoordDimensions )
  4464. {
  4465. Assert( pTexCoordDimensions[i] >= 0 && pTexCoordDimensions[i] <= 4 );
  4466. fmt |= VERTEX_TEXCOORD_SIZE( (TextureStage_t)i, pTexCoordDimensions[i] );
  4467. }
  4468. else
  4469. {
  4470. fmt |= VERTEX_TEXCOORD_SIZE( (TextureStage_t)i, 2 );
  4471. }
  4472. }
  4473. return fmt;
  4474. }
  4475. //-----------------------------------------------------------------------------
  4476. // Use fat vertices (for tools)
  4477. //-----------------------------------------------------------------------------
  4478. void CMeshMgr::UseFatVertices( bool bUseFat )
  4479. {
  4480. m_bUseFatVertices = bUseFat;
  4481. }
  4482. //-----------------------------------------------------------------------------
  4483. // Returns the number of vertices we can render using the dynamic mesh
  4484. //-----------------------------------------------------------------------------
  4485. void CMeshMgr::GetMaxToRender( IMesh *pMesh, bool bMaxUntilFlush, int *pMaxVerts, int *pMaxIndices )
  4486. {
  4487. CBaseMeshDX8 *pBaseMesh = static_cast<CBaseMeshDX8*>( pMesh );
  4488. if ( !pBaseMesh )
  4489. {
  4490. *pMaxVerts = 0;
  4491. *pMaxIndices = m_pDynamicIndexBuffer->IndexCount();
  4492. return;
  4493. }
  4494. if ( IsBufferedDynamicMesh( pMesh ) )
  4495. {
  4496. pBaseMesh = (CBaseMeshDX8*)static_cast<CBufferedMeshDX8*>( pBaseMesh )->GetMesh();
  4497. pMesh = pBaseMesh;
  4498. }
  4499. // Static mesh? Max you can use is 65535
  4500. if ( !IsDynamicMesh( pMesh ) )
  4501. {
  4502. *pMaxVerts = 65535;
  4503. *pMaxIndices = 65535;
  4504. return;
  4505. }
  4506. CVertexBuffer *pVertexBuffer = pBaseMesh->GetVertexBuffer();
  4507. CIndexBuffer *pIndexBuffer = pBaseMesh->GetIndexBuffer();
  4508. if ( !pVertexBuffer )
  4509. {
  4510. *pMaxVerts = 0;
  4511. *pMaxIndices = 0;
  4512. return;
  4513. }
  4514. if ( !bMaxUntilFlush )
  4515. {
  4516. *pMaxVerts = ShaderAPI()->GetCurrentDynamicVBSize() / pVertexBuffer->VertexSize();
  4517. if ( *pMaxVerts > 65535 )
  4518. {
  4519. *pMaxVerts = 65535;
  4520. }
  4521. *pMaxIndices = pIndexBuffer ? pIndexBuffer->IndexCount() : 0;
  4522. return;
  4523. }
  4524. *pMaxVerts = pVertexBuffer->NumVerticesUntilFlush();
  4525. *pMaxIndices = pIndexBuffer ? pIndexBuffer->IndexCount() - pIndexBuffer->IndexPosition() : 0;
  4526. if ( *pMaxVerts == 0 )
  4527. {
  4528. *pMaxVerts = ShaderAPI()->GetCurrentDynamicVBSize() / pVertexBuffer->VertexSize();
  4529. }
  4530. if ( *pMaxVerts > 65535 )
  4531. {
  4532. *pMaxVerts = 65535;
  4533. }
  4534. if ( *pMaxIndices == 0 )
  4535. {
  4536. *pMaxIndices = pIndexBuffer ? pIndexBuffer->IndexCount() : 0;
  4537. }
  4538. }
  4539. int CMeshMgr::GetMaxVerticesToRender( IMaterial *pMaterial )
  4540. {
  4541. Assert( (pMaterial == NULL) || ((IMaterialInternal *)pMaterial)->IsRealTimeVersion() );
  4542. // Be conservative, assume no compression (in here, we don't know if the caller will used a compressed VB or not)
  4543. // FIXME: allow the caller to specify which compression type should be used to compute size from the vertex format
  4544. // (this can vary between multiple VBs/Meshes using the same material)
  4545. VertexFormat_t fmt = pMaterial->GetVertexFormat() & ~VERTEX_FORMAT_COMPRESSED;
  4546. int nVertexSize = VertexFormatSize( fmt );
  4547. if ( nVertexSize == 0 )
  4548. {
  4549. // unable to determine vertex format information, possibly due to device loss.
  4550. Warning( "bad vertex size for material %s\n", pMaterial->GetName() );
  4551. return 0;
  4552. }
  4553. int nMaxVerts = ShaderAPI()->GetCurrentDynamicVBSize() / nVertexSize;
  4554. return MIN( nMaxVerts, 65535 );
  4555. }
  4556. int CMeshMgr::GetMaxIndicesToRender( )
  4557. {
  4558. return INDEX_BUFFER_SIZE;
  4559. }
  4560. //-----------------------------------------------------------------------------
  4561. // Returns a vertex buffer appropriate for the flags
  4562. //-----------------------------------------------------------------------------
  4563. CVertexBuffer *CMeshMgr::FindOrCreateVertexBuffer( int nDynamicBufferId, VertexFormat_t vertexFormat )
  4564. {
  4565. int vertexSize = VertexFormatSize( vertexFormat );
  4566. while ( m_DynamicVertexBuffers.Count() <= nDynamicBufferId )
  4567. {
  4568. // Track VB allocations (override any prior allocator string set higher up on the callstack)
  4569. g_VBAllocTracker->TrackMeshAllocations( NULL );
  4570. g_VBAllocTracker->TrackMeshAllocations( "CMeshMgr::FindOrCreateVertexBuffer (dynamic VB)" );
  4571. // create the single 1MB dynamic vb that will be shared amongst all consumers
  4572. // the correct thing is to use the largest expected vertex format size of max elements, but this
  4573. // creates an undesirably large buffer - instead create the buffer we want, and fix consumers that bork
  4574. // NOTE: GetCurrentDynamicVBSize returns a smaller value during level transitions
  4575. int nBufferMemory = ShaderAPI()->GetCurrentDynamicVBSize();
  4576. int nIndex = m_DynamicVertexBuffers.AddToTail();
  4577. m_DynamicVertexBuffers[nIndex].m_VertexSize = 0;
  4578. m_DynamicVertexBuffers[nIndex].m_pBuffer = new CVertexBuffer( Dx9Device(), 0, 0,
  4579. nBufferMemory / VERTEX_BUFFER_SIZE, VERTEX_BUFFER_SIZE, TEXTURE_GROUP_STATIC_VERTEX_BUFFER_OTHER, ShaderAPI()->UsingSoftwareVertexProcessing(), true );
  4580. g_VBAllocTracker->TrackMeshAllocations( NULL );
  4581. }
  4582. if ( m_DynamicVertexBuffers[nDynamicBufferId].m_VertexSize != vertexSize )
  4583. {
  4584. // provide caller with dynamic vb in expected format
  4585. // NOTE: GetCurrentDynamicVBSize returns a smaller value during level transitions
  4586. int nBufferMemory = ShaderAPI()->GetCurrentDynamicVBSize();
  4587. m_DynamicVertexBuffers[nDynamicBufferId].m_VertexSize = vertexSize;
  4588. m_DynamicVertexBuffers[nDynamicBufferId].m_pBuffer->ChangeConfiguration( vertexSize, nBufferMemory );
  4589. // size changed means stream stride needs update
  4590. // mark cached stream state as invalid to reset stream
  4591. if ( nDynamicBufferId == 0 )
  4592. {
  4593. g_pLastVertex = NULL;
  4594. }
  4595. }
  4596. return m_DynamicVertexBuffers[nDynamicBufferId].m_pBuffer;
  4597. }
  4598. CIndexBuffer *CMeshMgr::GetDynamicIndexBuffer()
  4599. {
  4600. return m_pDynamicIndexBuffer;
  4601. }
  4602. IVertexBuffer *CMeshMgr::GetDynamicVertexBuffer( IMaterial *pMaterial, bool buffered )
  4603. {
  4604. Assert( 0 );
  4605. return NULL;
  4606. // return ( IMeshDX8 * )GetDynamicMesh( pMaterial, buffered, NULL, NULL );
  4607. }
  4608. IIndexBuffer *CMeshMgr::GetDynamicIndexBuffer( IMaterial *pMaterial, bool buffered )
  4609. {
  4610. Assert( 0 );
  4611. return NULL;
  4612. // return ( IMeshDX8 * )GetDynamicMesh( pMaterial, buffered, NULL, NULL );
  4613. }
  4614. //-----------------------------------------------------------------------------
  4615. IVertexBuffer *CMeshMgr::CreateVertexBuffer( ShaderBufferType_t type, VertexFormat_t fmt, int nVertexCount, const char *pBudgetGroup )
  4616. {
  4617. // FIXME: Use a fixed-size allocator
  4618. CVertexBufferDx8 *pNewVertexBuffer = new CVertexBufferDx8( type, fmt, nVertexCount, pBudgetGroup );
  4619. return pNewVertexBuffer;
  4620. }
  4621. IIndexBuffer *CMeshMgr::CreateIndexBuffer( ShaderBufferType_t bufferType, MaterialIndexFormat_t fmt, int nIndexCount, const char *pBudgetGroup )
  4622. {
  4623. switch( bufferType )
  4624. {
  4625. case SHADER_BUFFER_TYPE_STATIC:
  4626. case SHADER_BUFFER_TYPE_DYNAMIC:
  4627. {
  4628. CIndexBufferDx8 *pIndexBuffer = new CIndexBufferDx8( bufferType, fmt, nIndexCount, pBudgetGroup );
  4629. return pIndexBuffer;
  4630. }
  4631. case SHADER_BUFFER_TYPE_STATIC_TEMP:
  4632. case SHADER_BUFFER_TYPE_DYNAMIC_TEMP:
  4633. Assert( 0 );
  4634. return NULL;
  4635. default:
  4636. Assert( 0 );
  4637. return NULL;
  4638. }
  4639. }
  4640. void CMeshMgr::DestroyVertexBuffer( IVertexBuffer *pVertexBuffer )
  4641. {
  4642. if ( pVertexBuffer && !IsDynamicVertexBuffer( pVertexBuffer ) )
  4643. {
  4644. delete pVertexBuffer;
  4645. }
  4646. }
  4647. void CMeshMgr::DestroyIndexBuffer( IIndexBuffer *pIndexBuffer )
  4648. {
  4649. if ( pIndexBuffer && !IsDynamicIndexBuffer( pIndexBuffer ) )
  4650. {
  4651. delete pIndexBuffer;
  4652. }
  4653. }
  4654. // Do we need to specify the stream here in the case of locking multiple dynamic VBs on different streams?
  4655. IVertexBuffer *CMeshMgr::GetDynamicVertexBuffer( int streamID, VertexFormat_t vertexFormat, bool bBuffered )
  4656. {
  4657. if ( IsX360() )
  4658. {
  4659. bBuffered = false;
  4660. }
  4661. if ( CompressionType( vertexFormat ) != VERTEX_COMPRESSION_NONE )
  4662. {
  4663. // UNDONE: support compressed dynamic meshes if needed (pro: less VB memory, con: time spent compressing)
  4664. DebuggerBreak();
  4665. return NULL;
  4666. }
  4667. // MESHFIXME
  4668. #if 0
  4669. if ( ( m_BufferedMode != bBuffered ) && m_BufferedMode )
  4670. {
  4671. m_BufferedIndexBuffer.SetIndexBuffer( NULL );
  4672. }
  4673. #endif
  4674. m_BufferedMode = bBuffered;
  4675. Assert( !m_BufferedMode ); // MESHFIXME: don't deal with buffered VBs yet.
  4676. bool needTempMesh = ShaderAPI()->IsInSelectionMode();
  4677. #ifdef DRAW_SELECTION
  4678. if( g_bDrawSelection )
  4679. {
  4680. needTempMesh = true;
  4681. }
  4682. #endif
  4683. Assert( !needTempMesh ); // MESHFIXME: don't support temp meshes here yet.
  4684. CVertexBufferDx8 *pVertexBuffer;
  4685. if ( needTempMesh )
  4686. {
  4687. Assert( 0 ); // MESHFIXME: don't do this yet.
  4688. // pVertexBuffer = &m_DynamicTempVertexBuffer;
  4689. pVertexBuffer = NULL;
  4690. }
  4691. else
  4692. {
  4693. pVertexBuffer = &m_DynamicVertexBuffer;
  4694. }
  4695. if ( m_BufferedMode )
  4696. {
  4697. Assert( 0 ); // don't support this yet.
  4698. #if 0
  4699. Assert( !m_BufferedMesh.WasNotRendered() );
  4700. m_BufferedMesh.SetMesh( pMesh );
  4701. pMesh = &m_BufferedMesh;
  4702. #endif
  4703. }
  4704. return pVertexBuffer;
  4705. }
  4706. IIndexBuffer *CMeshMgr::GetDynamicIndexBuffer( MaterialIndexFormat_t fmt, bool bBuffered )
  4707. {
  4708. if ( IsX360() )
  4709. {
  4710. bBuffered = false;
  4711. }
  4712. m_BufferedMode = bBuffered;
  4713. Assert( !m_BufferedMode );
  4714. #ifdef DBGFLAG_ASSERT
  4715. bool needTempMesh =
  4716. #endif
  4717. ShaderAPI()->IsInSelectionMode();
  4718. #ifdef DRAW_SELECTION
  4719. if( g_bDrawSelection )
  4720. {
  4721. needTempMesh = true;
  4722. }
  4723. #endif
  4724. Assert( !needTempMesh ); // don't handle this yet. MESHFIXME
  4725. CIndexBufferBase *pIndexBuffer = &m_DynamicIndexBuffer;
  4726. return pIndexBuffer;
  4727. }
  4728. void CMeshMgr::SetVertexIDStreamState()
  4729. {
  4730. if ( IsX360() )
  4731. return;
  4732. // MESHFIXME : This path is only used for the new index/vertex buffer interfaces.
  4733. // MESHFIXME : This path is only used for the new index/vertex buffer interfaces.
  4734. bool bUsingVertexID = false;//IsUsingVertexID();
  4735. // if ( bUsingVertexID != g_bUsingVertexID )
  4736. {
  4737. if ( bUsingVertexID )
  4738. {
  4739. // NOTE: Morphing doesn't work with dynamic buffers!!! BLEAH
  4740. // It's because the indices (which are not 0 based for dynamic buffers)
  4741. // are accessing both the vertexID buffer + the regular vertex buffer.
  4742. // This *might* be fixable with baseVertexIndex?
  4743. Assert( !m_pCurrentVertexBuffer->IsDynamic() );
  4744. CVertexBuffer *pVertexIDBuffer = g_MeshMgr.GetVertexIDBuffer( );
  4745. RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
  4746. RECORD_INT( pVertexIDBuffer->UID() );
  4747. RECORD_INT( 3 );
  4748. RECORD_INT( 0 );
  4749. RECORD_INT( pVertexIDBuffer->VertexSize() );
  4750. D3DSetStreamSource( 3, pVertexIDBuffer->GetInterface(), 0, pVertexIDBuffer->VertexSize() );
  4751. pVertexIDBuffer->HandlePerFrameTextureStats( ShaderAPI()->GetCurrentFrameCounter() );
  4752. }
  4753. else
  4754. {
  4755. RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
  4756. RECORD_INT( -1 ); // vertex buffer id
  4757. RECORD_INT( 3 ); // stream
  4758. RECORD_INT( 0 ); // vertex offset
  4759. RECORD_INT( 0 ); // vertex size
  4760. D3DSetStreamSource( 3, 0, 0, 0 );
  4761. }
  4762. g_bUsingVertexID = bUsingVertexID;
  4763. }
  4764. }
  4765. void CMeshMgr::SetColorStreamState()
  4766. {
  4767. if ( g_pLastColorMesh )
  4768. {
  4769. RECORD_COMMAND( DX8_SET_STREAM_SOURCE, 4 );
  4770. RECORD_INT( -1 ); // vertex buffer id
  4771. RECORD_INT( 1 ); // stream
  4772. RECORD_INT( 0 ); // vertex offset
  4773. RECORD_INT( 0 ); // vertex size
  4774. D3DSetStreamSource( 1, 0, 0, 0 );
  4775. }
  4776. g_pLastColorMesh = NULL;
  4777. g_nLastColorMeshVertOffsetInBytes = 0;
  4778. }
  4779. void CMeshMgr::SetVertexStreamState( int nVertOffsetInBytes, int nVertexStride )
  4780. {
  4781. // Calls in here assume shader support...
  4782. if ( HardwareConfig()->SupportsVertexAndPixelShaders() )
  4783. {
  4784. // Set a 4kb all-zero static VB into the flex/wrinkle stream with a stride of 0 bytes, so the vertex shader always reads valid floating point values (otherwise it can get NaN's/Inf's, and under OpenGL this is bad on NVidia)
  4785. // togl requires non-zero strides, but on D3D9 we can set a stride of 0 for a little more efficiency.
  4786. D3DSetStreamSource( 2, g_MeshMgr.GetZeroVertexBuffer(), 0, IsOpenGL() ? 4 : 0 );
  4787. // cFlexScale.x masks flex in vertex shader
  4788. if ( g_pHardwareConfig->Caps().m_SupportsVertexShaders_2_0 )
  4789. {
  4790. float c[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
  4791. ShaderAPI()->SetVertexShaderConstant( VERTEX_SHADER_FLEXSCALE, c, 1 );
  4792. }
  4793. g_bFlexMeshStreamSet = false;
  4794. }
  4795. // MESHFIXME : This path is only used for the new index/vertex buffer interfaces.
  4796. if ( g_pLastVertex || ( g_pLastVertexBuffer != m_pCurrentVertexBuffer->GetDx9Buffer() ) ||
  4797. ( g_nLastVertOffsetInBytes != nVertOffsetInBytes ) || ( g_nLastVertStride != nVertexStride ))
  4798. {
  4799. Assert( m_pCurrentVertexBuffer && m_pCurrentVertexBuffer->GetDx9Buffer() );
  4800. D3DSetStreamSource( 0, m_pCurrentVertexBuffer->GetDx9Buffer(), nVertOffsetInBytes, nVertexStride );
  4801. m_pCurrentVertexBuffer->HandlePerFrameTextureStats( ShaderAPI()->GetCurrentFrameCounter() );
  4802. g_pLastVertex = NULL;
  4803. g_nLastVertStride = nVertexStride;
  4804. g_pLastVertexBuffer = m_pCurrentVertexBuffer->GetDx9Buffer();
  4805. g_nLastVertOffsetInBytes = nVertOffsetInBytes;
  4806. }
  4807. }
  4808. bool CMeshMgr::SetRenderState( int nVertexOffsetInBytes, int nFirstVertexIdx, VertexFormat_t vertexFormat, int nVertexStride )
  4809. {
  4810. // Can't set the state if we're deactivated
  4811. if ( g_pShaderDeviceDx8->IsDeactivated() )
  4812. {
  4813. ResetMeshRenderState();
  4814. return false;
  4815. }
  4816. // make sure the vertex format is a superset of the current material's
  4817. // vertex format...
  4818. // MESHFIXME : This path is only used for the new index/vertex buffer interfaces.
  4819. #if 0
  4820. // FIXME
  4821. if ( !IsValidVertexFormat( vertexFormat ) )
  4822. {
  4823. Warning( "Material %s is being applied to a model, you need $model=1 in the .vmt file!\n",
  4824. ShaderAPI()->GetBoundMaterial()->GetName() );
  4825. return false;
  4826. }
  4827. #endif
  4828. SetVertexIDStreamState();
  4829. SetColorStreamState();
  4830. SetVertexStreamState( nVertexOffsetInBytes, nVertexStride );
  4831. SetIndexStreamState( nFirstVertexIdx );
  4832. return true;
  4833. }
  4834. void CMeshMgr::BindVertexBuffer( int nStreamID, IVertexBuffer *pVertexBuffer, int nOffsetInBytes, int nFirstVertex, int nVertexCount, VertexFormat_t fmt, int nRepetitions )
  4835. {
  4836. // FIXME: Multiple stream support isn't implemented yet
  4837. Assert( nStreamID == 0 );
  4838. m_pCurrentVertexBuffer = static_cast< CVertexBufferDx8 * >( pVertexBuffer );
  4839. m_CurrentVertexFormat = fmt;
  4840. m_pVertexBufferOffset[nStreamID] = nOffsetInBytes;
  4841. m_pCurrentVertexStride[nStreamID] = m_pCurrentVertexBuffer->VertexSize();
  4842. m_pFirstVertex[nStreamID] = nFirstVertex;
  4843. m_pVertexCount[nStreamID] = nVertexCount,
  4844. m_pVertexIDBuffer = NULL;
  4845. }
  4846. void CMeshMgr::BindIndexBuffer( IIndexBuffer *pIndexBuffer, int nOffsetInBytes )
  4847. {
  4848. m_pCurrentIndexBuffer = static_cast< CIndexBufferBase * >( pIndexBuffer );
  4849. m_nIndexBufferOffset = nOffsetInBytes;
  4850. }
  4851. void CMeshMgr::Draw( MaterialPrimitiveType_t primitiveType, int nFirstIndex, int nIndexCount )
  4852. {
  4853. // MESHFIXME : This path is only used for the new index/vertex buffer interfaces.
  4854. // make sure we aren't using a morph stream for this path.
  4855. // Assert( !IsUsingMorphData() );
  4856. // Assert( !m_pColorMesh );
  4857. SetRenderState( m_pVertexBufferOffset[0], /* nFirstVertexIdx */0, m_CurrentVertexFormat, m_pCurrentVertexStride[0] );
  4858. m_PrimitiveType = MATERIAL_TRIANGLES;
  4859. Assert( primitiveType == MATERIAL_TRIANGLES );
  4860. m_nFirstIndex = nFirstIndex;
  4861. m_nNumIndices = nIndexCount;
  4862. ShaderAPI()->DrawWithVertexAndIndexBuffers();
  4863. }
  4864. void CMeshMgr::RenderPassWithVertexAndIndexBuffers( void )
  4865. {
  4866. // LOCK_SHADERAPI(); MESHFIXME
  4867. VPROF( "CShaderAPIDX8::RenderPassWithVertexAndIndexBuffers" );
  4868. Assert( m_PrimitiveType != MATERIAL_HETEROGENOUS );
  4869. // for ( int iPrim=0; iPrim < s_nPrims; iPrim++ )
  4870. {
  4871. // CPrimList *pPrim = &s_pPrims[iPrim];
  4872. // if ( pPrim->m_NumIndices == 0 )
  4873. // continue;
  4874. if ( m_PrimitiveType == MATERIAL_POINTS )
  4875. {
  4876. // (For point lists, we don't actually fill in indices, but we treat it as
  4877. // though there are indices for the list up until here).
  4878. Assert( 0 );
  4879. // Dx9Device()->DrawPrimitive( ComputeMode( m_PrimitiveType ), s_FirstVertex, pPrim->m_NumIndices );
  4880. }
  4881. else
  4882. {
  4883. // int numPrimitives = NumPrimitives( s_NumVertices, pPrim->m_NumIndices );
  4884. // Warning( "CMeshMgr::RenderPassWithVertexAndIndexBuffers: DrawIndexedPrimitive: m_nFirstIndex = %d numPrimitives = %d\n", ( int )( ( CDynamiCIndexBufferDx8 * )m_pCurrentIndexBuffer )->m_FirstIndex, ( int )( m_nNumIndices / 3 ) );
  4885. {
  4886. VPROF( "Dx9Device()->DrawIndexedPrimitive" );
  4887. // VPROF_INCREMENT_COUNTER( "DrawIndexedPrimitive", 1 );
  4888. // VPROF_INCREMENT_COUNTER( "numPrimitives", numPrimitives );
  4889. // Dx9Device()->DrawIndexedPrimitive(
  4890. // m_Mode,
  4891. // m_FirstIndex,
  4892. // s_FirstVertex,
  4893. // s_NumVertices,
  4894. // pPrim->m_FirstIndex,
  4895. // numPrimitives );
  4896. Assert( m_nFirstIndex >= 0 );
  4897. #ifdef CHECK_INDICES
  4898. // g_pLastVertex - this is the current vertex buffer
  4899. // g_pLastColorMesh - this is the curent color mesh, if there is one.
  4900. // g_pLastIndex - this is the current index buffer.
  4901. // vertoffset : m_FirstIndex
  4902. CIndexBufferDx8 *pIndexBuffer = assert_cast< CIndexBufferDx8 * >( m_pCurrentIndexBuffer );
  4903. if( m_PrimitiveType == MATERIAL_TRIANGLES || m_PrimitiveType == MATERIAL_TRIANGLE_STRIP )
  4904. {
  4905. // FIXME: need to be able to deal with multiple stream here, but don't bother for now.
  4906. int j;
  4907. int numVerts = m_pVertexCount[0];
  4908. for( j = 0; j < m_nNumIndices; j++ )
  4909. {
  4910. int index = pIndexBuffer->GetShadowIndex( j + m_nFirstIndex );
  4911. Assert( index >= m_pFirstVertex[0] );
  4912. Assert( index < m_pFirstVertex[0] + numVerts );
  4913. }
  4914. }
  4915. #endif // CHECK_INDICES
  4916. Dx9Device()->DrawIndexedPrimitive(
  4917. ComputeMode( m_PrimitiveType ), // Member of the D3DPRIMITIVETYPE enumerated type, describing the type of primitive to render. D3DPT_POINTLIST is not supported with this method.
  4918. /*m_FirstIndex*/ 0, // Offset from the start of the vertex buffer to the first vertex index. An index of 0 in the index buffer refers to this location in the vertex buffer.
  4919. /*s_FirstVertex*/ m_pFirstVertex[0],// Minimum vertex index for vertices used during this call. This is a zero based index relative to BaseVertexIndex.
  4920. // This is zero for now since we don't do more than one batch yet with the new mesh interface.
  4921. /*s_NumVertices*/ m_pVertexCount[0],
  4922. // Number of vertices used during this call. The first vertex is located at index: BaseVertexIndex + MinIndex.
  4923. // This is simple the number of verts in the current vertex buffer for now since we don't do more than one batch with the new mesh interface.
  4924. m_nFirstIndex /*pPrim->m_FirstIndex*/, // Index of the first index to use when accesssing the vertex buffer. Beginning at StartIndex to index vertices from the vertex buffer.
  4925. m_nNumIndices / 3/*numPrimitives*/ // Number of primitives to render. The number of vertices used is a function of the primitive count and the primitive type.
  4926. );
  4927. Assert( CMeshDX8::s_FirstVertex == 0 );
  4928. Assert( CMeshDX8::s_NumVertices == 0 );
  4929. }
  4930. }
  4931. }
  4932. }
  4933. //-----------------------------------------------------------------------------
  4934. void CMeshMgr::SetIndexStreamState( int firstVertexIdx )
  4935. {
  4936. CIndexBufferDx8 *pIndexBuffer = assert_cast< CIndexBufferDx8* >( m_pCurrentIndexBuffer );
  4937. IDirect3DIndexBuffer9 *pDx9Buffer = pIndexBuffer ? pIndexBuffer->GetDx9Buffer() : NULL;
  4938. if ( g_pLastIndex || g_pLastIndexBuffer != pDx9Buffer )
  4939. {
  4940. Dx9Device()->SetIndices( pDx9Buffer );
  4941. pIndexBuffer->HandlePerFrameTextureStats( ShaderAPI()->GetCurrentFrameCounter() );
  4942. g_pLastIndexBuffer = pDx9Buffer;
  4943. SafeRelease( &g_pLastIndex );
  4944. g_LastVertexIdx = -1;
  4945. }
  4946. }