Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6931 lines
209 KiB

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