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.

4402 lines
140 KiB

  1. //==== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. =======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #ifndef IMESH_H
  7. #define IMESH_H
  8. #ifdef _WIN32
  9. #pragma once
  10. #endif
  11. #include "tier1/interface.h"
  12. #include "materialsystem/imaterial.h"
  13. #include <float.h>
  14. #include <string.h>
  15. #include "tier0/dbg.h"
  16. #include "tier2/meshutils.h"
  17. #if defined( DX_TO_GL_ABSTRACTION )
  18. // Swap these so that we do color swapping on 10.6.2, which doesn't have EXT_vertex_array_bgra
  19. #define OPENGL_SWAP_COLORS
  20. #endif
  21. #ifdef _PS3
  22. #define CELL_GCM_SWAP_COLORS
  23. #endif
  24. // Max number of instances that will be submitted at once on consoles in the model fast path
  25. // (This is important because console builds have smaller stack sizes than PC and we stackalloc()
  26. // a lot of intermediate data per batch)
  27. #define CONSOLE_MAX_MODEL_FAST_PATH_BATCH_SIZE 200
  28. //-----------------------------------------------------------------------------
  29. // forward declarations
  30. //-----------------------------------------------------------------------------
  31. class IMaterial;
  32. class CMeshBuilder;
  33. class IMaterialVar;
  34. typedef uint64 VertexFormat_t;
  35. struct ShaderStencilState_t;
  36. //-----------------------------------------------------------------------------
  37. // Define this to find write-combine problems
  38. //-----------------------------------------------------------------------------
  39. #ifdef _DEBUG
  40. //#ifndef DEBUG_WRITE_COMBINE
  41. //#define DEBUG_WRITE_COMBINE 1
  42. //#endif
  43. #endif
  44. //-----------------------------------------------------------------------------
  45. // The Vertex Buffer interface
  46. //-----------------------------------------------------------------------------
  47. enum
  48. {
  49. VERTEX_MAX_TEXTURE_COORDINATES = 8,
  50. BONE_MATRIX_INDEX_INVALID = 255
  51. };
  52. // Internal maximums for sizes. Don't use directly, use IMaterialSystem::GetMaxToRender()
  53. enum
  54. {
  55. #ifdef PLATFORM_X360
  56. INDEX_BUFFER_SIZE = 65504,
  57. DYNAMIC_VERTEX_BUFFER_MEMORY = ( 4096 ) * 1024,
  58. #else
  59. INDEX_BUFFER_SIZE = 32768,
  60. DYNAMIC_VERTEX_BUFFER_MEMORY = ( 1024 + 512 ) * 1024,
  61. #endif
  62. DYNAMIC_VERTEX_BUFFER_MEMORY_SMALL = 384 * 1024, // Only allocate this much during map transitions
  63. };
  64. // Vertex fields must be written in well-defined order to achieve write combining,
  65. // which is a perf booster
  66. enum WriteCombineOrdering_t
  67. {
  68. MB_FIELD_NONE = -1,
  69. MB_FIELD_POSITION = 0,
  70. MB_FIELD_BONE_WEIGHTS,
  71. MB_FIELD_BONE_INDEX,
  72. MB_FIELD_NORMAL,
  73. MB_FIELD_COLOR,
  74. MB_FIELD_SPECULAR,
  75. MB_FIELD_TEXCOORD_FIRST,
  76. MB_FIELD_TEXCOORD_LAST = MB_FIELD_TEXCOORD_FIRST + VERTEX_MAX_TEXTURE_COORDINATES - 1,
  77. MB_FIELD_TANGENT_S,
  78. MB_FIELD_TANGENT_T,
  79. MB_FIELD_USERDATA,
  80. };
  81. #define MB_FIELD_TEXCOORD( nStage ) ( MB_FIELD_TEXCOORD_FIRST + ( nStage ) )
  82. struct VertexDesc_t
  83. {
  84. // These can be set to zero if there are pointers to dummy buffers, when the
  85. // actual buffer format doesn't contain the data but it needs to be safe to
  86. // use all the CMeshBuilder functions.
  87. int m_VertexSize_Position;
  88. int m_VertexSize_BoneWeight;
  89. int m_VertexSize_BoneMatrixIndex;
  90. int m_VertexSize_Normal;
  91. int m_VertexSize_Color;
  92. int m_VertexSize_Specular;
  93. int m_VertexSize_TexCoord[VERTEX_MAX_TEXTURE_COORDINATES];
  94. int m_VertexSize_TangentS;
  95. int m_VertexSize_TangentT;
  96. int m_VertexSize_Wrinkle;
  97. int m_VertexSize_UserData;
  98. int m_ActualVertexSize; // Size of the vertices.. Some of the m_VertexSize_ elements above
  99. // are set to this value and some are set to zero depending on which
  100. // fields exist in a buffer's vertex format.
  101. // The type of compression applied to this vertex data
  102. VertexCompressionType_t m_CompressionType;
  103. // Number of bone weights per vertex...
  104. int m_NumBoneWeights;
  105. // Pointers to our current vertex data
  106. float *m_pPosition;
  107. float *m_pBoneWeight;
  108. #ifndef NEW_SKINNING
  109. unsigned char *m_pBoneMatrixIndex;
  110. #else
  111. float *m_pBoneMatrixIndex;
  112. #endif
  113. float *m_pNormal;
  114. unsigned char *m_pColor;
  115. unsigned char *m_pSpecular;
  116. float *m_pTexCoord[VERTEX_MAX_TEXTURE_COORDINATES];
  117. // Tangent space *associated with one particular set of texcoords*
  118. float *m_pTangentS;
  119. float *m_pTangentT;
  120. float *m_pWrinkle;
  121. // user data
  122. float *m_pUserData;
  123. // The first vertex index (used for buffered vertex buffers, or cards that don't support stream offset)
  124. int m_nFirstVertex;
  125. // The offset in bytes of the memory we're writing into
  126. // from the start of the D3D buffer (will be 0 for static meshes)
  127. unsigned int m_nOffset;
  128. #ifdef DEBUG_WRITE_COMBINE
  129. int m_nLastWrittenField;
  130. unsigned char* m_pLastWrittenAddress;
  131. #endif
  132. };
  133. struct IndexDesc_t
  134. {
  135. // Pointers to the index data
  136. unsigned short *m_pIndices;
  137. // The offset in bytes of the memory we're writing into
  138. // from the start of the D3D buffer (will be 0 for static meshes)
  139. unsigned int m_nOffset;
  140. // The first index (used for buffered index buffers, or cards that don't support stream offset)
  141. unsigned int m_nFirstIndex;
  142. // 1 if the device is active, 0 if the device isn't active.
  143. // Faster than doing if checks for null m_pIndices if someone is
  144. // trying to write the m_pIndices while the device is inactive.
  145. unsigned int m_nIndexSize;
  146. };
  147. //-----------------------------------------------------------------------------
  148. // The Mesh memory descriptor
  149. //-----------------------------------------------------------------------------
  150. struct MeshDesc_t : public VertexDesc_t, public IndexDesc_t
  151. {
  152. };
  153. //-----------------------------------------------------------------------------
  154. // The Mesh memory descriptor
  155. //-----------------------------------------------------------------------------
  156. struct MeshBuffersAllocationSettings_t
  157. {
  158. uint32 m_uiIbUsageFlags;
  159. };
  160. //-----------------------------------------------------------------------------
  161. // Standard vertex formats for models
  162. //-----------------------------------------------------------------------------
  163. struct ModelVertexDX8_t
  164. {
  165. Vector m_vecPosition;
  166. Vector m_vecNormal;
  167. Vector2D m_vecTexCoord;
  168. Vector4D m_vecUserData;
  169. };
  170. //---------------------------------------------------------------------------------------
  171. // Thin Vertex format for use with ATI tessellator in quad mode
  172. //---------------------------------------------------------------------------------------
  173. struct QuadTessVertex_t
  174. {
  175. Vector4D m_vTangent; // last component is Binormal flip and Wrinkle weight
  176. Vector4D m_vUV01; // UV coordinates for points Interior (0), and Parametric V Edge (1)
  177. Vector4D m_vUV23; // UV coordinates for points Parametric U Edge (2), and Corner (3)
  178. };
  179. struct MeshBoneRemap_t // see BoneStateChangeHeader_t
  180. {
  181. DECLARE_BYTESWAP_DATADESC();
  182. int m_nActualBoneIndex;
  183. int m_nSrcBoneIndex;
  184. };
  185. struct MeshInstanceData_t
  186. {
  187. int m_nIndexOffset;
  188. int m_nIndexCount;
  189. int m_nBoneCount;
  190. MeshBoneRemap_t * m_pBoneRemap; // there are bone count of these, they index into pose to world
  191. matrix3x4_t * m_pPoseToWorld; // transforms for the *entire* model, indexed into by m_pBoneIndex. Potentially more than bone count of these
  192. const ITexture * m_pEnvCubemap;
  193. MaterialLightingState_t *m_pLightingState;
  194. MaterialPrimitiveType_t m_nPrimType;
  195. const IVertexBuffer * m_pVertexBuffer;
  196. int m_nVertexOffsetInBytes;
  197. const IIndexBuffer * m_pIndexBuffer;
  198. const IVertexBuffer * m_pColorBuffer;
  199. int m_nColorVertexOffsetInBytes;
  200. ShaderStencilState_t * m_pStencilState;
  201. Vector4D m_DiffuseModulation;
  202. int m_nLightmapPageId;
  203. bool m_bColorBufferHasIndirectLightingOnly;
  204. };
  205. //-----------------------------------------------------------------------------
  206. // Utility methods for buffer builders
  207. //-----------------------------------------------------------------------------
  208. inline float *OffsetFloatPointer( float *pBufferPointer, int nVertexCount, int vertexSize )
  209. {
  210. return reinterpret_cast<float *>(
  211. reinterpret_cast<unsigned char *>(pBufferPointer) +
  212. nVertexCount * vertexSize);
  213. }
  214. inline const float *OffsetFloatPointer( const float *pBufferPointer, int nVertexCount, int vertexSize )
  215. {
  216. return reinterpret_cast<const float*>(
  217. reinterpret_cast<unsigned char const*>(pBufferPointer) +
  218. nVertexCount * vertexSize);
  219. }
  220. inline void IncrementFloatPointer( float* &pBufferPointer, int vertexSize )
  221. {
  222. pBufferPointer = reinterpret_cast<float*>( reinterpret_cast<unsigned char*>( pBufferPointer ) + vertexSize );
  223. }
  224. inline int PackRGBToPlatformColor( int r, int g, int b, int a )
  225. {
  226. #ifdef OPENGL_SWAP_COLORS
  227. int col = r | (g << 8) | (b << 16) | (a << 24); // r, g, b, a in memory
  228. #elif defined( CELL_GCM_SWAP_COLORS )
  229. int col = ( r << 24 ) | ( g << 16 ) | ( b << 8 ) | a;
  230. #else
  231. int col = b | (g << 8) | (r << 16) | (a << 24);
  232. #endif
  233. return col;
  234. }
  235. //-----------------------------------------------------------------------------
  236. // Used in lists of indexed primitives.
  237. //-----------------------------------------------------------------------------
  238. class CPrimList
  239. {
  240. public:
  241. CPrimList();
  242. CPrimList( int nFirstIndex, int nIndexCount );
  243. int m_FirstIndex;
  244. int m_NumIndices;
  245. };
  246. inline CPrimList::CPrimList()
  247. {
  248. }
  249. inline CPrimList::CPrimList( int nFirstIndex, int nIndexCount )
  250. {
  251. m_FirstIndex = nFirstIndex;
  252. m_NumIndices = nIndexCount;
  253. }
  254. abstract_class IVertexBuffer
  255. {
  256. public:
  257. // NOTE: The following two methods are only valid for static vertex buffers
  258. // Returns the number of vertices and the format of the vertex buffer
  259. virtual int VertexCount() const = 0;
  260. virtual VertexFormat_t GetVertexFormat() const = 0;
  261. // Is this vertex buffer dynamic?
  262. virtual bool IsDynamic() const = 0;
  263. // NOTE: For dynamic vertex buffers only!
  264. // Casts the memory of the dynamic vertex buffer to the appropriate type
  265. virtual void BeginCastBuffer( VertexFormat_t format ) = 0;
  266. virtual void EndCastBuffer() = 0;
  267. // Returns the number of vertices that can still be written into the buffer
  268. virtual int GetRoomRemaining() const = 0;
  269. virtual bool Lock( int nVertexCount, bool bAppend, VertexDesc_t &desc ) = 0;
  270. virtual void Unlock( int nVertexCount, VertexDesc_t &desc ) = 0;
  271. // Spews the mesh data
  272. virtual void Spew( int nVertexCount, const VertexDesc_t &desc ) = 0;
  273. // Call this in debug mode to make sure our data is good.
  274. virtual void ValidateData( int nVertexCount, const VertexDesc_t & desc ) = 0;
  275. };
  276. abstract_class IIndexBuffer
  277. {
  278. public:
  279. // NOTE: The following two methods are only valid for static index buffers
  280. // Returns the number of indices and the format of the index buffer
  281. virtual int IndexCount() const = 0;
  282. virtual MaterialIndexFormat_t IndexFormat() const = 0;
  283. // Is this index buffer dynamic?
  284. virtual bool IsDynamic() const = 0;
  285. // NOTE: For dynamic index buffers only!
  286. // Casts the memory of the dynamic index buffer to the appropriate type
  287. virtual void BeginCastBuffer( MaterialIndexFormat_t format ) = 0;
  288. virtual void EndCastBuffer() = 0;
  289. // Returns the number of indices that can still be written into the buffer
  290. virtual int GetRoomRemaining() const = 0;
  291. // Locks, unlocks the index buffer
  292. virtual bool Lock( int nMaxIndexCount, bool bAppend, IndexDesc_t &desc ) = 0;
  293. virtual void Unlock( int nWrittenIndexCount, IndexDesc_t &desc ) = 0;
  294. // FIXME: Remove this!! Here only for backward compat on IMesh
  295. // Locks, unlocks the index buffer for modify
  296. virtual void ModifyBegin( bool bReadOnly, int nFirstIndex, int nIndexCount, IndexDesc_t& desc ) = 0;
  297. virtual void ModifyEnd( IndexDesc_t& desc ) = 0;
  298. // Spews the mesh data
  299. virtual void Spew( int nIndexCount, const IndexDesc_t &desc ) = 0;
  300. // Ensures the data in the index buffer is valid
  301. virtual void ValidateData( int nIndexCount, const IndexDesc_t &desc ) = 0;
  302. // For backward compat to IMesh
  303. virtual IMesh* GetMesh() = 0;
  304. };
  305. //-----------------------------------------------------------------------------
  306. abstract_class ICachedPerFrameMeshData
  307. {
  308. public:
  309. virtual void Free() = 0;
  310. };
  311. //-----------------------------------------------------------------------------
  312. // Interface to the mesh - needs to contain an IVertexBuffer and an IIndexBuffer to emulate old mesh behavior
  313. //-----------------------------------------------------------------------------
  314. abstract_class IMesh : public IVertexBuffer, public IIndexBuffer
  315. {
  316. public:
  317. // -----------------------------------
  318. // Sets/gets the primitive type
  319. virtual void SetPrimitiveType( MaterialPrimitiveType_t type ) = 0;
  320. // Draws the mesh
  321. virtual void Draw( int nFirstIndex = -1, int nIndexCount = 0 ) = 0;
  322. virtual void SetColorMesh( IMesh *pColorMesh, int nVertexOffset ) = 0;
  323. // Draw a list of (lists of) primitives. Batching your lists together that use
  324. // the same lightmap, material, vertex and index buffers with multipass shaders
  325. // can drastically reduce state-switching overhead.
  326. // NOTE: this only works with STATIC meshes.
  327. virtual void Draw( CPrimList *pLists, int nLists ) = 0;
  328. // Copy verts and/or indices to a mesh builder. This only works for temp meshes!
  329. virtual void CopyToMeshBuilder(
  330. int iStartVert, // Which vertices to copy.
  331. int nVerts,
  332. int iStartIndex, // Which indices to copy.
  333. int nIndices,
  334. int indexOffset, // This is added to each index.
  335. CMeshBuilder &builder ) = 0;
  336. // Spews the mesh data
  337. virtual void Spew( int nVertexCount, int nIndexCount, const MeshDesc_t &desc ) = 0;
  338. // Call this in debug mode to make sure our data is good.
  339. virtual void ValidateData( int nVertexCount, int nIndexCount, const MeshDesc_t &desc ) = 0;
  340. // New version
  341. // Locks/unlocks the mesh, providing space for nVertexCount and nIndexCount.
  342. // nIndexCount of -1 means don't lock the index buffer...
  343. virtual void LockMesh( int nVertexCount, int nIndexCount, MeshDesc_t &desc, MeshBuffersAllocationSettings_t *pSettings = 0 ) = 0;
  344. virtual void ModifyBegin( int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc ) = 0;
  345. virtual void ModifyEnd( MeshDesc_t& desc ) = 0;
  346. virtual void UnlockMesh( int nVertexCount, int nIndexCount, MeshDesc_t &desc ) = 0;
  347. virtual void ModifyBeginEx( bool bReadOnly, int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t &desc ) = 0;
  348. virtual void SetFlexMesh( IMesh *pMesh, int nVertexOffset ) = 0;
  349. virtual void DisableFlexMesh() = 0;
  350. virtual void MarkAsDrawn() = 0;
  351. // NOTE: I chose to create this method strictly because it's 2 days to code lock
  352. // and I could use the DrawInstances technique without a larger code change
  353. // Draws the mesh w/ modulation.
  354. virtual void DrawModulated( const Vector4D &diffuseModulation, int nFirstIndex = -1, int nIndexCount = 0 ) = 0;
  355. virtual unsigned int ComputeMemoryUsed() = 0;
  356. virtual void * AccessRawHardwareDataStream( uint8 nRawStreamIndex, uint32 numBytes, uint32 uiFlags, void *pvContext ) = 0;
  357. virtual ICachedPerFrameMeshData *GetCachedPerFrameMeshData() = 0;
  358. virtual void ReconstructFromCachedPerFrameMeshData( ICachedPerFrameMeshData *pData ) = 0;
  359. };
  360. #include "meshreader.h"
  361. #define INVALID_BUFFER_OFFSET 0xFFFFFFFFUL
  362. // flags for advancevertex optimization
  363. #define VTX_HAVEPOS 1
  364. #define VTX_HAVENORMAL 2
  365. #define VTX_HAVECOLOR 4
  366. #define VTX_HAVEALL ( VTX_HAVEPOS | VTX_HAVENORMAL | VTX_HAVECOLOR )
  367. //-----------------------------------------------------------------------------
  368. //
  369. // Helper class used to define vertex buffers
  370. //
  371. //-----------------------------------------------------------------------------
  372. class CVertexBuilder : private VertexDesc_t
  373. {
  374. public:
  375. CVertexBuilder();
  376. CVertexBuilder( IVertexBuffer *pVertexBuffer, VertexFormat_t fmt = 0 );
  377. ~CVertexBuilder();
  378. // Begins, ends modification of the index buffer (returns true if the lock succeeded)
  379. // A lock may not succeed if append is set to true and there isn't enough room
  380. // NOTE: Append is only used with dynamic index buffers; it's ignored for static buffers
  381. bool Lock( int nMaxIndexCount, bool bAppend = false );
  382. void Unlock();
  383. // Spews the current data
  384. // NOTE: Can only be called during a lock/unlock block
  385. void SpewData();
  386. // Returns the number of indices we can fit into the buffer without needing to discard
  387. int GetRoomRemaining() const;
  388. // Binds this vertex buffer
  389. void Bind( IMatRenderContext *pContext, int nStreamID, VertexFormat_t usage = 0 );
  390. // Returns the byte offset
  391. int Offset() const;
  392. // This must be called before Begin, if a vertex buffer with a compressed format is to be used
  393. void SetCompressionType( VertexCompressionType_t compressionType );
  394. void ValidateCompressionType();
  395. void Begin( IVertexBuffer *pVertexBuffer, int nVertexCount, int *nFirstVertex );
  396. void Begin( IVertexBuffer *pVertexBuffer, int nVertexCount );
  397. // Use this when you're done writing
  398. // Set bDraw to true to call m_pMesh->Draw automatically.
  399. void End( bool bSpewData = false );
  400. // Locks the vertex buffer to modify existing data
  401. // Passing nVertexCount == -1 says to lock all the vertices for modification.
  402. void BeginModify( IVertexBuffer *pVertexBuffer, int nFirstVertex = 0, int nVertexCount = -1 );
  403. void EndModify( bool bSpewData = false );
  404. // returns the number of vertices
  405. int VertexCount() const;
  406. // Returns the total number of vertices across all Locks()
  407. int TotalVertexCount() const;
  408. // Resets the mesh builder so it points to the start of everything again
  409. void Reset();
  410. // Returns the size of the vertex
  411. int VertexSize() { return m_ActualVertexSize; }
  412. // returns the data size of a given texture coordinate
  413. int TextureCoordinateSize( int nTexCoordNumber ) { return m_VertexSize_TexCoord[ nTexCoordNumber ]; }
  414. // Returns the base vertex memory pointer
  415. void* BaseVertexData();
  416. // Selects the nth Vertex and Index
  417. void SelectVertex( int idx );
  418. // Advances the current vertex and index by one
  419. void AdvanceVertex();
  420. template<int nFlags, int nNumTexCoords> void AdvanceVertexF();
  421. void AdvanceVertices( int nVerts );
  422. template<int nFlags, int nNumTexCoords> void AdvanceVerticesF( int nVerts );
  423. int GetCurrentVertex() const;
  424. int GetFirstVertex() const;
  425. // Data retrieval...
  426. const float *Position() const;
  427. const float *Normal() const;
  428. unsigned int Color() const;
  429. unsigned char *Specular() const;
  430. const float *TexCoord( int stage ) const;
  431. const float *TangentS() const;
  432. const float *TangentT() const;
  433. const float *BoneWeight() const;
  434. float Wrinkle() const;
  435. int NumBoneWeights() const;
  436. #ifndef NEW_SKINNING
  437. unsigned char *BoneMatrix() const;
  438. #else
  439. float *BoneMatrix() const;
  440. #endif
  441. // position setting
  442. void Position3f( float x, float y, float z );
  443. void Position3f( int nVertexOffset, float x, float y, float z );
  444. void Position3f( const fltx4 &fl4Position );
  445. void Position3fv( const float *v );
  446. void Position3fv( int nVertexOffset, const float *v );
  447. // normal setting
  448. void Normal3f( float nx, float ny, float nz );
  449. void Normal3f( const fltx4 &fl4Normal );
  450. void Normal3fv( const float *n );
  451. void NormalDelta3fv( const float *n );
  452. void NormalDelta3f( float nx, float ny, float nz );
  453. // normal setting (templatized for code which needs to support compressed vertices)
  454. template <VertexCompressionType_t T> void CompressedNormal3f( float nx, float ny, float nz );
  455. template <VertexCompressionType_t T> void CompressedNormal3fv( const float *n );
  456. // color setting
  457. void Color3f( float r, float g, float b );
  458. void Color3fv( const float *rgb );
  459. void Color4f( float r, float g, float b, float a );
  460. void Color4fv( const float *rgba );
  461. // Faster versions of color
  462. void Color3ub( unsigned char r, unsigned char g, unsigned char b );
  463. void Color3ubv( unsigned char const* rgb );
  464. void Color4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a );
  465. void Color4ub( int nVertexOffset, unsigned char r, unsigned char g, unsigned char b, unsigned char a );
  466. void Color4ubv( unsigned char const* rgba );
  467. void Color4Packed( int packedColor );
  468. int PackColor4( unsigned char r, unsigned char g, unsigned char b, unsigned char a );
  469. // specular color setting
  470. void Specular3f( float r, float g, float b );
  471. void Specular3fv( const float *rgb );
  472. void Specular4f( float r, float g, float b, float a );
  473. void Specular4fv( const float *rgba );
  474. // Faster version of specular
  475. void Specular3ub( unsigned char r, unsigned char g, unsigned char b );
  476. void Specular3ubv( unsigned char const *c );
  477. void Specular4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a );
  478. void Specular4ubv( unsigned char const *c );
  479. // texture coordinate setting
  480. void TexCoord1f( int stage, float s );
  481. void TexCoord2f( int stage, float s, float t );
  482. void TexCoord2f( int nVertexOffset, int stage, float s, float t );
  483. void TexCoord2fv( int stage, const float *st );
  484. void TexCoord3f( int stage, float s, float t, float u );
  485. void TexCoord3f( int nVertexOffset, int stage, float s, float t, float u );
  486. void TexCoord3fv( int stage, const float *stu );
  487. void TexCoord3fv( int nVertexOffset, int stage, const float *stu );
  488. void TexCoord4f( int stage, float s, float t, float u, float w );
  489. void TexCoord4fv( int stage, const float *stuv );
  490. void TexCoord4f( int nVertexOffset, int stage, float s, float t, float u, float w );
  491. void TexCoord4fv( int nVertexOffset, int stage, const float *stuv );
  492. void TexCoord4f( int nStage, const fltx4 &fl4stuv );
  493. void TexCoordSubRect2f( int stage, float s, float t, float offsetS, float offsetT, float scaleS, float scaleT );
  494. void TexCoordSubRect2fv( int stage, const float *st, const float *offset, const float *scale );
  495. // tangent space
  496. void TangentS3f( float sx, float sy, float sz );
  497. void TangentS3fv( const float* s );
  498. void TangentT3f( float tx, float ty, float tz );
  499. void TangentT3fv( const float* t );
  500. // Wrinkle
  501. void Wrinkle1f( float flWrinkle );
  502. // bone weights
  503. void BoneWeight( int idx, float weight );
  504. void BoneWeights2( float weight1, float weight2 );
  505. // bone weights (templatized for code which needs to support compressed vertices)
  506. template <VertexCompressionType_t T> void CompressedBoneWeight3fv( const float * pWeights );
  507. // bone matrix index
  508. void BoneMatrix( int idx, int matrixIndex );
  509. void BoneMatrices4( int matrixIdx0, int matrixIdx1, int matrixIdx2, int matrixIdx3 );
  510. // Generic per-vertex data
  511. void UserData( const float* pData );
  512. // Generic per-vertex data (templatized for code which needs to support compressed vertices)
  513. template <VertexCompressionType_t T> void CompressedUserData( const float* pData );
  514. // Fast Vertex! No need to call advance vertex, and no random access allowed.
  515. // WARNING - these are low level functions that are intended only for use
  516. // in the software vertex skinner.
  517. void FastVertex( const ModelVertexDX8_t &vertex );
  518. void FastVertexSSE( const ModelVertexDX8_t &vertex );
  519. void FastQuadVertexSSE( const QuadTessVertex_t &vertex );
  520. // Add number of verts and current vert since FastVertex routines do not update.
  521. void FastAdvanceNVertices( int n );
  522. #if defined( _X360 )
  523. void VertexDX8ToX360( const ModelVertexDX8_t &vertex );
  524. #endif
  525. // FIXME: Remove! Backward compat so we can use this from a CMeshBuilder.
  526. void AttachBegin( IMesh* pMesh, int nMaxVertexCount, const MeshDesc_t &desc );
  527. void AttachEnd();
  528. void AttachBeginModify( IMesh* pMesh, int nFirstVertex, int nVertexCount, const MeshDesc_t &desc );
  529. void AttachEndModify();
  530. private:
  531. // The vertex buffer we're modifying
  532. IVertexBuffer *m_pVertexBuffer;
  533. // Used to make sure Begin/End calls and BeginModify/EndModify calls match.
  534. bool m_bModify;
  535. // Max number of indices and vertices
  536. int m_nMaxVertexCount;
  537. // Number of indices and vertices
  538. int m_nVertexCount;
  539. // The current vertex and index
  540. mutable int m_nCurrentVertex;
  541. // Optimization: Pointer to the current pos, norm, texcoord, and color
  542. mutable float *m_pCurrPosition;
  543. mutable float *m_pCurrNormal;
  544. mutable unsigned char *m_pCurrColor;
  545. mutable float *m_pCurrTexCoord[VERTEX_MAX_TEXTURE_COORDINATES];
  546. // Total number of vertices appended
  547. int m_nTotalVertexCount;
  548. // First vertex buffer offset + index
  549. unsigned int m_nBufferOffset;
  550. unsigned int m_nBufferFirstVertex;
  551. #if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 )
  552. // Debug checks to make sure we write userdata4/tangents AFTER normals
  553. bool m_bWrittenNormal : 1;
  554. bool m_bWrittenUserData : 1;
  555. #endif
  556. friend class CMeshBuilder;
  557. };
  558. //-----------------------------------------------------------------------------
  559. //
  560. // Inline methods of CVertexBuilder
  561. //
  562. //-----------------------------------------------------------------------------
  563. inline CVertexBuilder::CVertexBuilder()
  564. {
  565. m_pVertexBuffer = NULL;
  566. m_nBufferOffset = INVALID_BUFFER_OFFSET;
  567. m_nBufferFirstVertex = 0;
  568. m_nVertexCount = 0;
  569. m_nCurrentVertex = 0;
  570. m_nMaxVertexCount = 0;
  571. m_nTotalVertexCount = 0;
  572. m_CompressionType = VERTEX_COMPRESSION_INVALID;
  573. #ifdef _DEBUG
  574. m_pCurrPosition = NULL;
  575. m_pCurrNormal = NULL;
  576. m_pCurrColor = NULL;
  577. memset( m_pCurrTexCoord, 0, sizeof( m_pCurrTexCoord ) );
  578. m_bModify = false;
  579. #endif
  580. }
  581. inline CVertexBuilder::CVertexBuilder( IVertexBuffer *pVertexBuffer, VertexFormat_t fmt )
  582. {
  583. m_pVertexBuffer = pVertexBuffer;
  584. m_nBufferOffset = INVALID_BUFFER_OFFSET;
  585. m_nBufferFirstVertex = 0;
  586. m_nVertexCount = 0;
  587. m_nCurrentVertex = 0;
  588. m_nMaxVertexCount = 0;
  589. m_nTotalVertexCount = 0;
  590. m_CompressionType = VERTEX_COMPRESSION_INVALID;
  591. if ( m_pVertexBuffer->IsDynamic() )
  592. {
  593. m_pVertexBuffer->BeginCastBuffer( fmt );
  594. }
  595. else
  596. {
  597. Assert( m_pVertexBuffer->GetVertexFormat() == fmt );
  598. }
  599. #ifdef _DEBUG
  600. m_pCurrPosition = NULL;
  601. m_pCurrNormal = NULL;
  602. m_pCurrColor = NULL;
  603. memset( m_pCurrTexCoord, 0, sizeof( m_pCurrTexCoord ) );
  604. m_bModify = false;
  605. #endif
  606. }
  607. inline CVertexBuilder::~CVertexBuilder()
  608. {
  609. if ( m_pVertexBuffer && m_pVertexBuffer->IsDynamic() )
  610. {
  611. m_pVertexBuffer->EndCastBuffer();
  612. }
  613. }
  614. //-----------------------------------------------------------------------------
  615. // Begins, ends modification of the index buffer
  616. //-----------------------------------------------------------------------------
  617. inline bool CVertexBuilder::Lock( int nMaxVertexCount, bool bAppend )
  618. {
  619. Assert( m_pVertexBuffer );
  620. m_bModify = false;
  621. m_nMaxVertexCount = nMaxVertexCount;
  622. bool bFirstLock = ( m_nBufferOffset == INVALID_BUFFER_OFFSET );
  623. if ( bFirstLock )
  624. {
  625. bAppend = false;
  626. }
  627. if ( !bAppend )
  628. {
  629. m_nTotalVertexCount = 0;
  630. }
  631. // Lock the vertex buffer
  632. if ( !m_pVertexBuffer->Lock( m_nMaxVertexCount, bAppend, *this ) )
  633. {
  634. m_nMaxVertexCount = 0;
  635. return false;
  636. }
  637. Reset();
  638. if ( bFirstLock )
  639. {
  640. m_nBufferOffset = m_nOffset;
  641. m_nBufferFirstVertex = m_nFirstVertex;
  642. }
  643. return true;
  644. }
  645. inline void CVertexBuilder::Unlock()
  646. {
  647. Assert( !m_bModify && m_pVertexBuffer );
  648. #ifdef _DEBUG
  649. m_pVertexBuffer->ValidateData( m_nVertexCount, *this );
  650. #endif
  651. m_pVertexBuffer->Unlock( m_nVertexCount, *this );
  652. m_nTotalVertexCount += m_nVertexCount;
  653. m_nMaxVertexCount = 0;
  654. #ifdef _DEBUG
  655. // Null out our data...
  656. m_pCurrPosition = NULL;
  657. m_pCurrNormal = NULL;
  658. m_pCurrColor = NULL;
  659. memset( m_pCurrTexCoord, 0, sizeof( m_pCurrTexCoord ) );
  660. memset( static_cast<VertexDesc_t*>( this ), 0, sizeof(VertexDesc_t) );
  661. #endif
  662. }
  663. inline void CVertexBuilder::SpewData()
  664. {
  665. m_pVertexBuffer->Spew( m_nVertexCount, *this );
  666. }
  667. //-----------------------------------------------------------------------------
  668. // Binds this vertex buffer
  669. //-----------------------------------------------------------------------------
  670. inline void CVertexBuilder::Bind( IMatRenderContext *pContext, int nStreamID, VertexFormat_t usage )
  671. {
  672. if ( m_pVertexBuffer && ( m_nBufferOffset != INVALID_BUFFER_OFFSET ) )
  673. {
  674. pContext->BindVertexBuffer( nStreamID, m_pVertexBuffer, m_nBufferOffset,
  675. m_nFirstVertex, m_nTotalVertexCount, usage ? usage : m_pVertexBuffer->GetVertexFormat() );
  676. }
  677. else
  678. {
  679. pContext->BindVertexBuffer( nStreamID, NULL, 0, 0, 0, 0 );
  680. }
  681. }
  682. //-----------------------------------------------------------------------------
  683. // Returns the byte offset
  684. //-----------------------------------------------------------------------------
  685. inline int CVertexBuilder::Offset() const
  686. {
  687. return m_nBufferOffset;
  688. }
  689. inline int CVertexBuilder::GetFirstVertex() const
  690. {
  691. return m_nBufferFirstVertex;
  692. }
  693. //-----------------------------------------------------------------------------
  694. // Specify the type of vertex compression that this CMeshBuilder will perform
  695. //-----------------------------------------------------------------------------
  696. inline void CVertexBuilder::SetCompressionType( VertexCompressionType_t compressionType )
  697. {
  698. // The real purpose of this method is to allow us to emit a Warning in Begin()
  699. m_CompressionType = compressionType;
  700. }
  701. inline void CVertexBuilder::ValidateCompressionType()
  702. {
  703. #ifdef _DEBUG
  704. VertexCompressionType_t vbCompressionType = CompressionType( m_pVertexBuffer->GetVertexFormat() );
  705. if ( vbCompressionType != VERTEX_COMPRESSION_NONE )
  706. {
  707. Assert( m_CompressionType == vbCompressionType );
  708. if ( m_CompressionType != vbCompressionType )
  709. {
  710. Warning( "ERROR: CVertexBuilder::SetCompressionType() must be called to specify the same vertex compression type (%s) as the vertex buffer being modified."
  711. "Junk vertices will be rendered, or there will be a crash in CVertexBuilder!\n",
  712. vbCompressionType == VERTEX_COMPRESSION_ON ? "VERTEX_COMPRESSION_ON" : "VERTEX_COMPRESSION_NONE" );
  713. }
  714. // Never use vertex compression for dynamic VBs (the conversions can really hurt perf)
  715. Assert( !m_pVertexBuffer->IsDynamic() );
  716. }
  717. #endif
  718. }
  719. inline void CVertexBuilder::Begin( IVertexBuffer *pVertexBuffer, int nVertexCount )
  720. {
  721. Assert( pVertexBuffer && (!m_pVertexBuffer) );
  722. m_pVertexBuffer = pVertexBuffer;
  723. m_bModify = false;
  724. m_nMaxVertexCount = nVertexCount;
  725. m_nVertexCount = 0;
  726. // Make sure SetCompressionType was called correctly, if this VB is compressed
  727. ValidateCompressionType();
  728. // Lock the vertex and index buffer
  729. m_pVertexBuffer->Lock( m_nMaxVertexCount, false, *this );
  730. // Point to the start of the buffers..
  731. Reset();
  732. }
  733. //-----------------------------------------------------------------------------
  734. // Use this when you're done modifying the mesh
  735. //-----------------------------------------------------------------------------
  736. inline void CVertexBuilder::End( bool bSpewData )
  737. {
  738. // Make sure they called Begin()
  739. Assert( !m_bModify );
  740. if ( bSpewData )
  741. {
  742. m_pVertexBuffer->Spew( m_nVertexCount, *this );
  743. }
  744. #ifdef _DEBUG
  745. m_pVertexBuffer->ValidateData( m_nVertexCount, *this );
  746. #endif
  747. // Unlock our buffers
  748. m_pVertexBuffer->Unlock( m_nVertexCount, *this );
  749. m_pVertexBuffer = 0;
  750. m_nMaxVertexCount = 0;
  751. m_CompressionType = VERTEX_COMPRESSION_INVALID;
  752. #ifdef _DEBUG
  753. // Null out our pointers...
  754. m_pCurrPosition = NULL;
  755. m_pCurrNormal = NULL;
  756. m_pCurrColor = NULL;
  757. memset( m_pCurrTexCoord, 0, sizeof( m_pCurrTexCoord ) );
  758. memset( static_cast< VertexDesc_t* >( this ), 0, sizeof(VertexDesc_t) );
  759. #endif
  760. }
  761. //-----------------------------------------------------------------------------
  762. // FIXME: Remove! Backward compat so we can use this from a CMeshBuilder.
  763. //-----------------------------------------------------------------------------
  764. inline void CVertexBuilder::AttachBegin( IMesh* pMesh, int nMaxVertexCount, const MeshDesc_t &desc )
  765. {
  766. m_pVertexBuffer = pMesh;
  767. memcpy( static_cast<VertexDesc_t*>( this ), static_cast<const VertexDesc_t*>( &desc ), sizeof(VertexDesc_t) );
  768. m_nMaxVertexCount = nMaxVertexCount;
  769. m_NumBoneWeights = m_NumBoneWeights == 0 ? 0 : 2; // Two weights if any
  770. m_nVertexCount = 0;
  771. m_bModify = false;
  772. // Make sure SetCompressionType was called correctly, if this VB is compressed
  773. ValidateCompressionType();
  774. if ( m_nBufferOffset == INVALID_BUFFER_OFFSET )
  775. {
  776. m_nTotalVertexCount = 0;
  777. m_nBufferOffset = static_cast< const VertexDesc_t* >( &desc )->m_nOffset;
  778. m_nBufferFirstVertex = desc.m_nFirstVertex;
  779. }
  780. }
  781. inline void CVertexBuilder::AttachEnd()
  782. {
  783. // Make sure they called Begin()
  784. Assert( !m_bModify );
  785. m_nMaxVertexCount = 0;
  786. m_pVertexBuffer = NULL;
  787. m_CompressionType = VERTEX_COMPRESSION_INVALID;
  788. #ifdef _DEBUG
  789. // Null out our pointers...
  790. m_pCurrPosition = NULL;
  791. m_pCurrNormal = NULL;
  792. m_pCurrColor = NULL;
  793. memset( m_pCurrTexCoord, 0, sizeof( m_pCurrTexCoord ) );
  794. memset( static_cast<VertexDesc_t*>( this ), 0, sizeof(VertexDesc_t) );
  795. #endif
  796. }
  797. inline void CVertexBuilder::AttachBeginModify( IMesh* pMesh, int nFirstVertex, int nVertexCount, const MeshDesc_t &desc )
  798. {
  799. Assert( pMesh && (!m_pVertexBuffer) );
  800. m_pVertexBuffer = pMesh;
  801. memcpy( static_cast<VertexDesc_t*>( this ), static_cast<const VertexDesc_t*>( &desc ), sizeof(VertexDesc_t) );
  802. m_nMaxVertexCount = m_nVertexCount = nVertexCount;
  803. m_NumBoneWeights = m_NumBoneWeights == 0 ? 0 : 2; // Two weights if any
  804. m_bModify = true;
  805. // Make sure SetCompressionType was called correctly, if this VB is compressed
  806. ValidateCompressionType();
  807. }
  808. inline void CVertexBuilder::AttachEndModify()
  809. {
  810. Assert( m_pVertexBuffer );
  811. Assert( m_bModify ); // Make sure they called BeginModify.
  812. m_pVertexBuffer = 0;
  813. m_nMaxVertexCount = 0;
  814. m_CompressionType = VERTEX_COMPRESSION_INVALID;
  815. #ifdef _DEBUG
  816. // Null out our pointers...
  817. m_pCurrPosition = NULL;
  818. m_pCurrNormal = NULL;
  819. m_pCurrColor = NULL;
  820. memset( m_pCurrTexCoord, 0, sizeof( m_pCurrTexCoord ) );
  821. memset( static_cast<VertexDesc_t*>( this ), 0, sizeof(VertexDesc_t) );
  822. #endif
  823. }
  824. //-----------------------------------------------------------------------------
  825. // Computes the first min non-null address
  826. //-----------------------------------------------------------------------------
  827. inline unsigned char* FindMinAddress( void *pAddress1, void *pAddress2, int nAddress2Size )
  828. {
  829. if ( nAddress2Size == 0 )
  830. return (unsigned char*)pAddress1;
  831. if ( !pAddress1 )
  832. return (unsigned char*)pAddress2;
  833. return ( pAddress1 < pAddress2 ) ? (unsigned char*)pAddress1 : (unsigned char*)pAddress2;
  834. }
  835. //-----------------------------------------------------------------------------
  836. // Resets the vertex buffer builder so it points to the start of everything again
  837. //-----------------------------------------------------------------------------
  838. inline void CVertexBuilder::Reset()
  839. {
  840. m_nCurrentVertex = 0;
  841. m_pCurrPosition = m_pPosition;
  842. m_pCurrNormal = m_pNormal;
  843. for ( int i = 0; i < NELEMS( m_pCurrTexCoord ); i++ )
  844. {
  845. m_pCurrTexCoord[i] = m_pTexCoord[i];
  846. }
  847. m_pCurrColor = m_pColor;
  848. #if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) )
  849. m_bWrittenNormal = false;
  850. m_bWrittenUserData = false;
  851. #endif
  852. #ifdef DEBUG_WRITE_COMBINE
  853. // Logic for m_pLastWrittenAddress is tricky. It really wants the min of the
  854. // non-null address pointers.
  855. m_nLastWrittenField = MB_FIELD_NONE;
  856. m_pLastWrittenAddress = NULL;
  857. m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pPosition, m_VertexSize_Position );
  858. m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pBoneWeight, m_VertexSize_BoneWeight );
  859. m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pBoneMatrixIndex, m_VertexSize_BoneMatrixIndex );
  860. m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pNormal, m_VertexSize_Normal );
  861. m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pColor, m_VertexSize_Color );
  862. m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pSpecular, m_VertexSize_Specular );
  863. for ( int i = 0; i < VERTEX_MAX_TEXTURE_COORDINATES; ++i )
  864. {
  865. m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pTexCoord[i], m_VertexSize_TexCoord[i] );
  866. }
  867. m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pTangentS, m_VertexSize_TangentS );
  868. m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pTangentT, m_VertexSize_TangentT );
  869. m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pUserData, m_VertexSize_UserData );
  870. #endif
  871. }
  872. //-----------------------------------------------------------------------------
  873. // returns the number of vertices
  874. //-----------------------------------------------------------------------------
  875. inline int CVertexBuilder::VertexCount() const
  876. {
  877. return m_nVertexCount;
  878. }
  879. //-----------------------------------------------------------------------------
  880. // Returns the total number of vertices across all Locks()
  881. //-----------------------------------------------------------------------------
  882. inline int CVertexBuilder::TotalVertexCount() const
  883. {
  884. return m_nTotalVertexCount;
  885. }
  886. //-----------------------------------------------------------------------------
  887. // Returns the base vertex memory pointer
  888. //-----------------------------------------------------------------------------
  889. inline void* CVertexBuilder::BaseVertexData()
  890. {
  891. // FIXME: If there's no position specified, we need to find
  892. // the base address
  893. Assert( m_pPosition );
  894. return m_pPosition;
  895. }
  896. //-----------------------------------------------------------------------------
  897. // Selects the current vertex
  898. //-----------------------------------------------------------------------------
  899. inline void CVertexBuilder::SelectVertex( int nIndex )
  900. {
  901. // NOTE: This index is expected to be relative
  902. Assert( (nIndex >= 0) && (nIndex < m_nMaxVertexCount) );
  903. m_nCurrentVertex = nIndex;
  904. m_pCurrPosition = OffsetFloatPointer( m_pPosition, m_nCurrentVertex, m_VertexSize_Position );
  905. m_pCurrNormal = OffsetFloatPointer( m_pNormal, m_nCurrentVertex, m_VertexSize_Normal );
  906. COMPILE_TIME_ASSERT( VERTEX_MAX_TEXTURE_COORDINATES == 8 );
  907. m_pCurrTexCoord[0] = OffsetFloatPointer( m_pTexCoord[0], m_nCurrentVertex, m_VertexSize_TexCoord[0] );
  908. m_pCurrTexCoord[1] = OffsetFloatPointer( m_pTexCoord[1], m_nCurrentVertex, m_VertexSize_TexCoord[1] );
  909. m_pCurrTexCoord[2] = OffsetFloatPointer( m_pTexCoord[2], m_nCurrentVertex, m_VertexSize_TexCoord[2] );
  910. m_pCurrTexCoord[3] = OffsetFloatPointer( m_pTexCoord[3], m_nCurrentVertex, m_VertexSize_TexCoord[3] );
  911. m_pCurrTexCoord[4] = OffsetFloatPointer( m_pTexCoord[4], m_nCurrentVertex, m_VertexSize_TexCoord[4] );
  912. m_pCurrTexCoord[5] = OffsetFloatPointer( m_pTexCoord[5], m_nCurrentVertex, m_VertexSize_TexCoord[5] );
  913. m_pCurrTexCoord[6] = OffsetFloatPointer( m_pTexCoord[6], m_nCurrentVertex, m_VertexSize_TexCoord[6] );
  914. m_pCurrTexCoord[7] = OffsetFloatPointer( m_pTexCoord[7], m_nCurrentVertex, m_VertexSize_TexCoord[7] );
  915. m_pCurrColor = m_pColor + m_nCurrentVertex * m_VertexSize_Color;
  916. #if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) )
  917. m_bWrittenNormal = false;
  918. m_bWrittenUserData = false;
  919. #endif
  920. }
  921. //-----------------------------------------------------------------------------
  922. // Advances vertex after you're done writing to it.
  923. //-----------------------------------------------------------------------------
  924. template<int nFlags, int nNumTexCoords> FORCEINLINE void CVertexBuilder::AdvanceVertexF()
  925. {
  926. if ( ++m_nCurrentVertex > m_nVertexCount )
  927. {
  928. m_nVertexCount = m_nCurrentVertex;
  929. }
  930. if ( nFlags & VTX_HAVEPOS )
  931. IncrementFloatPointer( m_pCurrPosition, m_VertexSize_Position );
  932. if ( nFlags & VTX_HAVENORMAL )
  933. IncrementFloatPointer( m_pCurrNormal, m_VertexSize_Normal );
  934. if ( nFlags & VTX_HAVECOLOR )
  935. m_pCurrColor += m_VertexSize_Color;
  936. COMPILE_TIME_ASSERT( VERTEX_MAX_TEXTURE_COORDINATES == 8 );
  937. if ( nNumTexCoords > 0 )
  938. IncrementFloatPointer( m_pCurrTexCoord[0], m_VertexSize_TexCoord[0] );
  939. if ( nNumTexCoords > 1 )
  940. IncrementFloatPointer( m_pCurrTexCoord[1], m_VertexSize_TexCoord[1] );
  941. if ( nNumTexCoords > 2 )
  942. IncrementFloatPointer( m_pCurrTexCoord[2], m_VertexSize_TexCoord[2] );
  943. if ( nNumTexCoords > 3 )
  944. IncrementFloatPointer( m_pCurrTexCoord[3], m_VertexSize_TexCoord[3] );
  945. if ( nNumTexCoords > 4 )
  946. IncrementFloatPointer( m_pCurrTexCoord[4], m_VertexSize_TexCoord[4] );
  947. if ( nNumTexCoords > 5 )
  948. IncrementFloatPointer( m_pCurrTexCoord[5], m_VertexSize_TexCoord[5] );
  949. if ( nNumTexCoords > 6 )
  950. IncrementFloatPointer( m_pCurrTexCoord[6], m_VertexSize_TexCoord[6] );
  951. if ( nNumTexCoords > 7 )
  952. IncrementFloatPointer( m_pCurrTexCoord[7], m_VertexSize_TexCoord[7] );
  953. #if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) )
  954. m_bWrittenNormal = false;
  955. m_bWrittenUserData = false;
  956. #endif
  957. }
  958. inline void CVertexBuilder::AdvanceVertex()
  959. {
  960. AdvanceVertexF<VTX_HAVEALL, 8>();
  961. }
  962. template<int nFlags, int nNumTexCoords>
  963. FORCEINLINE void CVertexBuilder::AdvanceVerticesF( int nVerts )
  964. {
  965. m_nCurrentVertex += nVerts;
  966. if ( m_nCurrentVertex > m_nVertexCount )
  967. {
  968. m_nVertexCount = m_nCurrentVertex;
  969. }
  970. if ( nFlags & VTX_HAVEPOS )
  971. IncrementFloatPointer( m_pCurrPosition, m_VertexSize_Position*nVerts );
  972. if ( nFlags & VTX_HAVENORMAL )
  973. IncrementFloatPointer( m_pCurrNormal, m_VertexSize_Normal*nVerts );
  974. if ( nFlags & VTX_HAVECOLOR )
  975. m_pCurrColor += m_VertexSize_Color*nVerts;
  976. COMPILE_TIME_ASSERT( VERTEX_MAX_TEXTURE_COORDINATES == 8 );
  977. if ( nNumTexCoords > 0 )
  978. IncrementFloatPointer( m_pCurrTexCoord[0], m_VertexSize_TexCoord[0]*nVerts );
  979. if ( nNumTexCoords > 1 )
  980. IncrementFloatPointer( m_pCurrTexCoord[1], m_VertexSize_TexCoord[1]*nVerts );
  981. if ( nNumTexCoords > 2 )
  982. IncrementFloatPointer( m_pCurrTexCoord[2], m_VertexSize_TexCoord[2]*nVerts );
  983. if ( nNumTexCoords > 3 )
  984. IncrementFloatPointer( m_pCurrTexCoord[3], m_VertexSize_TexCoord[3]*nVerts );
  985. if ( nNumTexCoords > 4 )
  986. IncrementFloatPointer( m_pCurrTexCoord[4], m_VertexSize_TexCoord[4]*nVerts );
  987. if ( nNumTexCoords > 5 )
  988. IncrementFloatPointer( m_pCurrTexCoord[5], m_VertexSize_TexCoord[5]*nVerts );
  989. if ( nNumTexCoords > 6 )
  990. IncrementFloatPointer( m_pCurrTexCoord[6], m_VertexSize_TexCoord[6]*nVerts );
  991. if ( nNumTexCoords > 7 )
  992. IncrementFloatPointer( m_pCurrTexCoord[7], m_VertexSize_TexCoord[7]*nVerts );
  993. #if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) )
  994. m_bWrittenNormal = false;
  995. m_bWrittenUserData = false;
  996. #endif
  997. }
  998. inline void CVertexBuilder::AdvanceVertices( int nVerts )
  999. {
  1000. AdvanceVerticesF<VTX_HAVEALL, 8>( nVerts );
  1001. }
  1002. //-----------------------------------------------------------------------------
  1003. // For use with the FastVertex methods, advances the current vertex by N
  1004. //-----------------------------------------------------------------------------
  1005. inline void CVertexBuilder::FastAdvanceNVertices( int n )
  1006. {
  1007. m_nCurrentVertex += n;
  1008. m_nVertexCount = m_nCurrentVertex;
  1009. }
  1010. inline void CVertexBuilder::FastVertex( const ModelVertexDX8_t &vertex )
  1011. {
  1012. Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // FIXME: support compressed verts if needed
  1013. Assert( m_nCurrentVertex < m_nMaxVertexCount );
  1014. #if defined( _WIN32 ) && !defined( _X360 ) && !defined( _M_X64 )
  1015. const void *pRead = &vertex;
  1016. void *pCurrPos = m_pCurrPosition;
  1017. __asm
  1018. {
  1019. mov esi, pRead
  1020. mov edi, pCurrPos
  1021. movq mm0, [esi + 0]
  1022. movq mm1, [esi + 8]
  1023. movq mm2, [esi + 16]
  1024. movq mm3, [esi + 24]
  1025. movq mm4, [esi + 32]
  1026. movq mm5, [esi + 40]
  1027. movntq [edi + 0], mm0
  1028. movntq [edi + 8], mm1
  1029. movntq [edi + 16], mm2
  1030. movntq [edi + 24], mm3
  1031. movntq [edi + 32], mm4
  1032. movntq [edi + 40], mm5
  1033. emms
  1034. }
  1035. #elif defined(GNUC)
  1036. const void *pRead = &vertex;
  1037. void *pCurrPos = m_pCurrPosition;
  1038. __asm__ __volatile__ (
  1039. "movq (%0), %%mm0\n"
  1040. "movq 8(%0), %%mm1\n"
  1041. "movq 16(%0), %%mm2\n"
  1042. "movq 24(%0), %%mm3\n"
  1043. "movq 32(%0), %%mm4\n"
  1044. "movq 40(%0), %%mm5\n"
  1045. "movq 48(%0), %%mm6\n"
  1046. "movq 56(%0), %%mm7\n"
  1047. "movntq %%mm0, (%1)\n"
  1048. "movntq %%mm1, 8(%1)\n"
  1049. "movntq %%mm2, 16(%1)\n"
  1050. "movntq %%mm3, 24(%1)\n"
  1051. "movntq %%mm4, 32(%1)\n"
  1052. "movntq %%mm5, 40(%1)\n"
  1053. "movntq %%mm6, 48(%1)\n"
  1054. "movntq %%mm7, 56(%1)\n"
  1055. "emms\n"
  1056. :: "r" (pRead), "r" (pCurrPos) : "memory");
  1057. #else
  1058. Error( "Implement CMeshBuilder::FastVertex(dx8)" );
  1059. #endif
  1060. IncrementFloatPointer( m_pCurrPosition, m_VertexSize_Position );
  1061. // m_nVertexCount = ++m_nCurrentVertex;
  1062. #if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) )
  1063. m_bWrittenNormal = false;
  1064. m_bWrittenUserData = false;
  1065. #endif
  1066. }
  1067. inline void CVertexBuilder::FastVertexSSE( const ModelVertexDX8_t &vertex )
  1068. {
  1069. Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // FIXME: support compressed verts if needed
  1070. Assert( m_nCurrentVertex < m_nMaxVertexCount );
  1071. #if defined( _WIN32 ) && !defined( _X360 ) && !defined( _M_X64 )
  1072. const void *pRead = &vertex;
  1073. void *pCurrPos = m_pCurrPosition;
  1074. __asm
  1075. {
  1076. mov esi, pRead
  1077. mov edi, pCurrPos
  1078. movaps xmm0, [esi + 0]
  1079. movaps xmm1, [esi + 16]
  1080. movaps xmm2, [esi + 32]
  1081. movntps [edi + 0], xmm0
  1082. movntps [edi + 16], xmm1
  1083. movntps [edi + 32], xmm2
  1084. }
  1085. #elif defined(GNUC)
  1086. const void *pRead = &vertex;
  1087. void *pCurrPos = m_pCurrPosition;
  1088. __asm__ __volatile__ (
  1089. "movaps (%0), %%xmm0\n"
  1090. "movaps 16(%0), %%xmm1\n"
  1091. "movaps 32(%0), %%xmm2\n"
  1092. "movaps 48(%0), %%xmm3\n"
  1093. "movntps %%xmm0, (%1)\n"
  1094. "movntps %%xmm1, 16(%1)\n"
  1095. "movntps %%xmm2, 32(%1)\n"
  1096. "movntps %%xmm3, 48(%1)\n"
  1097. :: "r" (pRead), "r" (pCurrPos) : "memory");
  1098. #else
  1099. Error( "Implement CMeshBuilder::FastVertexSSE((dx8)" );
  1100. #endif
  1101. IncrementFloatPointer( m_pCurrPosition, m_VertexSize_Position );
  1102. // m_nVertexCount = ++m_nCurrentVertex;
  1103. #if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) )
  1104. m_bWrittenNormal = false;
  1105. m_bWrittenUserData = false;
  1106. #endif
  1107. }
  1108. inline void CVertexBuilder::FastQuadVertexSSE( const QuadTessVertex_t &vertex )
  1109. {
  1110. Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // FIXME: support compressed verts if needed
  1111. Assert( m_nCurrentVertex < m_nMaxVertexCount );
  1112. #if defined( _WIN32 ) && !defined( _X360 ) && !defined( _M_X64 )
  1113. const void *pRead = &vertex;
  1114. void *pCurrPos = m_pCurrPosition;
  1115. __asm
  1116. {
  1117. mov esi, pRead
  1118. mov edi, pCurrPos
  1119. movaps xmm0, [esi + 0]
  1120. movaps xmm1, [esi + 16]
  1121. movaps xmm2, [esi + 32]
  1122. movntps [edi + 0], xmm0
  1123. movntps [edi + 16], xmm1
  1124. movntps [edi + 32], xmm2
  1125. }
  1126. #endif
  1127. IncrementFloatPointer( m_pCurrPosition, m_VertexSize_Position );
  1128. // m_nVertexCount = ++m_nCurrentVertex;
  1129. #if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) )
  1130. m_bWrittenNormal = false;
  1131. m_bWrittenUserData = false;
  1132. #endif
  1133. }
  1134. //-----------------------------------------------------------------------------
  1135. // Returns the current vertex
  1136. //-----------------------------------------------------------------------------
  1137. inline int CVertexBuilder::GetCurrentVertex() const
  1138. {
  1139. return m_nCurrentVertex;
  1140. }
  1141. //-----------------------------------------------------------------------------
  1142. // Copies a vertex into the x360 format
  1143. //-----------------------------------------------------------------------------
  1144. #if defined( _X360 )
  1145. inline void CVertexBuilder::VertexDX8ToX360( const ModelVertexDX8_t &vertex )
  1146. {
  1147. Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // FIXME: support compressed verts if needed
  1148. Assert( m_nCurrentVertex < m_nMaxVertexCount );
  1149. // get the start of the data
  1150. unsigned char *pDst = (unsigned char*)m_pCurrPosition;
  1151. Assert( m_VertexSize_Position > 0 ); // Assume position is always present
  1152. Assert( GetVertexElementSize( VERTEX_ELEMENT_POSITION, VERTEX_COMPRESSION_NONE ) == sizeof( vertex.m_vecPosition ) );
  1153. memcpy( pDst, vertex.m_vecPosition.Base(), sizeof( vertex.m_vecPosition ) );
  1154. pDst += sizeof( vertex.m_vecPosition );
  1155. if ( m_VertexSize_Normal )
  1156. {
  1157. Assert( GetVertexElementSize( VERTEX_ELEMENT_NORMAL, VERTEX_COMPRESSION_NONE ) == sizeof( vertex.m_vecNormal ) );
  1158. memcpy( pDst, vertex.m_vecNormal.Base(), sizeof( vertex.m_vecNormal ) );
  1159. pDst += sizeof( vertex.m_vecNormal );
  1160. }
  1161. if ( m_VertexSize_TexCoord[0] )
  1162. {
  1163. Assert( GetVertexElementSize( VERTEX_ELEMENT_TEXCOORD2D_0, VERTEX_COMPRESSION_NONE ) == sizeof( vertex.m_vecTexCoord ) );
  1164. memcpy( pDst, vertex.m_vecTexCoord.Base(), sizeof( vertex.m_vecTexCoord ) );
  1165. pDst += sizeof( vertex.m_vecTexCoord );
  1166. }
  1167. if ( m_VertexSize_UserData )
  1168. {
  1169. Assert( GetVertexElementSize( VERTEX_ELEMENT_USERDATA4, VERTEX_COMPRESSION_NONE ) == sizeof( vertex.m_vecUserData ) );
  1170. memcpy( pDst, vertex.m_vecUserData.Base(), sizeof( vertex.m_vecUserData ) );
  1171. pDst += sizeof( vertex.m_vecUserData );
  1172. }
  1173. // ensure code is synced with the mesh builder that established the offsets
  1174. Assert( pDst - (unsigned char*)m_pCurrPosition == m_VertexSize_Position );
  1175. IncrementFloatPointer( m_pCurrPosition, m_VertexSize_Position );
  1176. #if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) )
  1177. m_bWrittenNormal = false;
  1178. m_bWrittenUserData = false;
  1179. #endif
  1180. }
  1181. #endif
  1182. //-----------------------------------------------------------------------------
  1183. // Data retrieval...
  1184. //-----------------------------------------------------------------------------
  1185. inline const float* CVertexBuilder::Position() const
  1186. {
  1187. // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately)
  1188. // for code that needs to access compressed data (and/or a return-by-value templatized accessor)
  1189. Assert( m_CompressionType == VERTEX_COMPRESSION_NONE );
  1190. Assert( m_nCurrentVertex < m_nMaxVertexCount );
  1191. return m_pCurrPosition;
  1192. }
  1193. inline const float* CVertexBuilder::Normal() const
  1194. {
  1195. // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately)
  1196. // for code that needs to access compressed data (and/or a return-by-value templatized accessor)
  1197. Assert( m_CompressionType == VERTEX_COMPRESSION_NONE );
  1198. Assert( m_nCurrentVertex < m_nMaxVertexCount );
  1199. return m_pCurrNormal;
  1200. }
  1201. inline unsigned int CVertexBuilder::Color() const
  1202. {
  1203. // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately)
  1204. // for code that needs to access compressed data (and/or a return-by-value templatized accessor)
  1205. Assert( m_CompressionType == VERTEX_COMPRESSION_NONE );
  1206. // Swizzle it so it returns the same format as accepted by Color4ubv - rgba
  1207. Assert( m_nCurrentVertex < m_nMaxVertexCount );
  1208. unsigned int color;
  1209. if ( IsPC() || !IsX360() )
  1210. {
  1211. color = (m_pCurrColor[3] << 24) | (m_pCurrColor[0] << 16) | (m_pCurrColor[1] << 8) | (m_pCurrColor[2]);
  1212. }
  1213. else
  1214. {
  1215. // in memory as argb, back to rgba
  1216. color = (m_pCurrColor[1] << 24) | (m_pCurrColor[2] << 16) | (m_pCurrColor[3] << 8) | (m_pCurrColor[0]);
  1217. }
  1218. return color;
  1219. }
  1220. inline unsigned char *CVertexBuilder::Specular() const
  1221. {
  1222. // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately)
  1223. // for code that needs to access compressed data (and/or a return-by-value templatized accessor)
  1224. Assert( m_CompressionType == VERTEX_COMPRESSION_NONE );
  1225. Assert( m_nCurrentVertex < m_nMaxVertexCount );
  1226. return m_pSpecular + m_nCurrentVertex * m_VertexSize_Specular;
  1227. }
  1228. inline const float* CVertexBuilder::TexCoord( int stage ) const
  1229. {
  1230. // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately)
  1231. // for code that needs to access compressed data (and/or a return-by-value templatized accessor)
  1232. Assert( m_CompressionType == VERTEX_COMPRESSION_NONE );
  1233. Assert( m_nCurrentVertex < m_nMaxVertexCount );
  1234. return m_pCurrTexCoord[stage];
  1235. }
  1236. inline const float* CVertexBuilder::TangentS() const
  1237. {
  1238. // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately)
  1239. // for code that needs to access compressed data (and/or a return-by-value templatized accessor)
  1240. Assert( m_CompressionType == VERTEX_COMPRESSION_NONE );
  1241. Assert( m_nCurrentVertex < m_nMaxVertexCount );
  1242. return OffsetFloatPointer( m_pTangentS, m_nCurrentVertex, m_VertexSize_TangentS );
  1243. }
  1244. inline const float* CVertexBuilder::TangentT() const
  1245. {
  1246. // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately)
  1247. // for code that needs to access compressed data (and/or a return-by-value templatized accessor)
  1248. Assert( m_CompressionType == VERTEX_COMPRESSION_NONE );
  1249. Assert( m_nCurrentVertex < m_nMaxVertexCount );
  1250. return OffsetFloatPointer( m_pTangentT, m_nCurrentVertex, m_VertexSize_TangentT );
  1251. }
  1252. inline float CVertexBuilder::Wrinkle() const
  1253. {
  1254. // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately)
  1255. // for code that needs to access compressed data (and/or a return-by-value templatized accessor)
  1256. Assert( m_CompressionType == VERTEX_COMPRESSION_NONE );
  1257. Assert( m_nCurrentVertex < m_nMaxVertexCount );
  1258. return *OffsetFloatPointer( m_pWrinkle, m_nCurrentVertex, m_VertexSize_Wrinkle );
  1259. }
  1260. inline const float* CVertexBuilder::BoneWeight() const
  1261. {
  1262. // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately)
  1263. // for code that needs to access compressed data (and/or a return-by-value templatized accessor)
  1264. Assert( m_CompressionType == VERTEX_COMPRESSION_NONE );
  1265. Assert( m_nCurrentVertex < m_nMaxVertexCount );
  1266. return OffsetFloatPointer( m_pBoneWeight, m_nCurrentVertex, m_VertexSize_BoneWeight );
  1267. }
  1268. inline int CVertexBuilder::NumBoneWeights() const
  1269. {
  1270. return m_NumBoneWeights;
  1271. }
  1272. #ifndef NEW_SKINNING
  1273. inline unsigned char* CVertexBuilder::BoneMatrix() const
  1274. {
  1275. // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately)
  1276. // for code that needs to access compressed data (and/or a return-by-value templatized accessor)
  1277. Assert( m_CompressionType == VERTEX_COMPRESSION_NONE );
  1278. Assert( m_nCurrentVertex < m_nMaxVertexCount );
  1279. return m_pBoneMatrixIndex + m_nCurrentVertex * m_VertexSize_BoneMatrixIndex;
  1280. }
  1281. #else
  1282. inline float* CVertexBuilder::BoneMatrix() const
  1283. {
  1284. // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately)
  1285. // for code that needs to access compressed data (and/or a return-by-value templatized accessor)
  1286. Assert( m_CompressionType == VERTEX_COMPRESSION_NONE );
  1287. Assert( m_nCurrentVertex < m_nMaxVertexCount );
  1288. return m_pBoneMatrixIndex + m_nCurrentVertex * m_VertexSize_BoneMatrixIndex;
  1289. }
  1290. #endif
  1291. //-----------------------------------------------------------------------------
  1292. // Position setting methods
  1293. //-----------------------------------------------------------------------------
  1294. inline void CVertexBuilder::Position3f( float x, float y, float z )
  1295. {
  1296. Assert( m_pPosition && m_pCurrPosition );
  1297. Assert( IsFinite(x) && IsFinite(y) && IsFinite(z) );
  1298. float *pDst = m_pCurrPosition;
  1299. *pDst++ = x;
  1300. *pDst++ = y;
  1301. *pDst = z;
  1302. }
  1303. inline void CVertexBuilder::Position3f( int nVertexOffset, float x, float y, float z )
  1304. {
  1305. Assert( m_pPosition && m_pCurrPosition );
  1306. Assert( IsFinite(x) && IsFinite(y) && IsFinite(z) );
  1307. float *pDst = OffsetFloatPointer( m_pCurrPosition, nVertexOffset, m_VertexSize_Position );
  1308. *pDst++ = x;
  1309. *pDst++ = y;
  1310. *pDst = z;
  1311. }
  1312. inline void CVertexBuilder::Position3f( const fltx4 &fl4Position )
  1313. {
  1314. Assert( m_pPosition && m_pCurrPosition );
  1315. StoreUnaligned3SIMD( m_pCurrPosition, fl4Position );
  1316. }
  1317. inline void CVertexBuilder::Position3fv( const float *v )
  1318. {
  1319. Assert(v);
  1320. Assert( m_pPosition && m_pCurrPosition );
  1321. float *pDst = m_pCurrPosition;
  1322. *pDst++ = *v++;
  1323. *pDst++ = *v++;
  1324. *pDst = *v;
  1325. }
  1326. inline void CVertexBuilder::Position3fv( int nVertexOffset, const float *v )
  1327. {
  1328. Assert(v);
  1329. Assert( m_pPosition && m_pCurrPosition );
  1330. float *pDst = OffsetFloatPointer( m_pCurrPosition, nVertexOffset, m_VertexSize_Position );
  1331. *pDst++ = *v++;
  1332. *pDst++ = *v++;
  1333. *pDst = *v;
  1334. }
  1335. //-----------------------------------------------------------------------------
  1336. // Normal setting methods
  1337. //-----------------------------------------------------------------------------
  1338. inline void CVertexBuilder::Normal3f( float nx, float ny, float nz )
  1339. {
  1340. Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // Use the templatized version if you want to support compression
  1341. Assert( m_pNormal );
  1342. Assert( IsFinite(nx) && IsFinite(ny) && IsFinite(nz) );
  1343. Assert( nx >= -1.05f && nx <= 1.05f );
  1344. Assert( ny >= -1.05f && ny <= 1.05f );
  1345. Assert( nz >= -1.05f && nz <= 1.05f );
  1346. float *pDst = m_pCurrNormal;
  1347. *pDst++ = nx;
  1348. *pDst++ = ny;
  1349. *pDst = nz;
  1350. }
  1351. inline void CVertexBuilder::Normal3f( const fltx4 &fl4Normal )
  1352. {
  1353. Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // Use the templatized version if you want to support compression
  1354. Assert( m_pNormal );
  1355. StoreUnaligned3SIMD( m_pCurrNormal, fl4Normal );
  1356. }
  1357. inline void CVertexBuilder::Normal3fv( const float *n )
  1358. {
  1359. Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // Use the templatized version if you want to support compression
  1360. Assert( n );
  1361. Assert( m_pNormal && m_pCurrNormal );
  1362. Assert( IsFinite(n[0]) && IsFinite(n[1]) && IsFinite(n[2]) );
  1363. Assert( n[0] >= -1.05f && n[0] <= 1.05f );
  1364. Assert( n[1] >= -1.05f && n[1] <= 1.05f );
  1365. Assert( n[2] >= -1.05f && n[2] <= 1.05f );
  1366. float *pDst = m_pCurrNormal;
  1367. *pDst++ = *n++;
  1368. *pDst++ = *n++;
  1369. *pDst = *n;
  1370. }
  1371. inline void CVertexBuilder::NormalDelta3f( float nx, float ny, float nz )
  1372. {
  1373. Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // Use the templatized version if you want to support compression
  1374. Assert( m_pNormal );
  1375. Assert( IsFinite(nx) && IsFinite(ny) && IsFinite(nz) );
  1376. float *pDst = m_pCurrNormal;
  1377. *pDst++ = nx;
  1378. *pDst++ = ny;
  1379. *pDst = nz;
  1380. }
  1381. inline void CVertexBuilder::NormalDelta3fv( const float *n )
  1382. {
  1383. Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // Use the templatized version if you want to support compression
  1384. Assert( n );
  1385. Assert( m_pNormal && m_pCurrNormal );
  1386. Assert( IsFinite(n[0]) && IsFinite(n[1]) && IsFinite(n[2]) );
  1387. float *pDst = m_pCurrNormal;
  1388. *pDst++ = *n++;
  1389. *pDst++ = *n++;
  1390. *pDst = *n;
  1391. }
  1392. //-----------------------------------------------------------------------------
  1393. // Templatized normal setting methods which support compressed vertices
  1394. //-----------------------------------------------------------------------------
  1395. template <VertexCompressionType_t T> inline void CVertexBuilder::CompressedNormal3f( float nx, float ny, float nz )
  1396. {
  1397. Assert( T == m_CompressionType );
  1398. Assert( m_pNormal && m_pCurrNormal );
  1399. Assert( IsFinite(nx) && IsFinite(ny) && IsFinite(nz) );
  1400. Assert( nx >= -1.05f && nx <= 1.05f );
  1401. Assert( ny >= -1.05f && ny <= 1.05f );
  1402. Assert( nz >= -1.05f && nz <= 1.05f );
  1403. // FIXME: studiorender is passing in non-unit normals
  1404. //float lengthSqd = nx*nx + ny*ny + nz*nz;
  1405. //Assert( lengthSqd >= 0.95f && lengthSqd <= 1.05f );
  1406. if ( T == VERTEX_COMPRESSION_ON )
  1407. {
  1408. #if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 )
  1409. PackNormal_SHORT2( nx, ny, nz, (unsigned int *)m_pCurrNormal );
  1410. #else //( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 )
  1411. // NOTE: write the normal into the lower 16 bits of a word, clearing the top 16 bits - a userdata4
  1412. // tangent must be written into the upper 16 bits by CompressedUserData() *AFTER* this.
  1413. #ifdef _DEBUG
  1414. Assert( m_bWrittenUserData == false );
  1415. m_bWrittenNormal = true;
  1416. #endif
  1417. PackNormal_UBYTE4( nx, ny, nz, (unsigned int *)m_pCurrNormal );
  1418. #endif
  1419. }
  1420. else
  1421. {
  1422. float *pDst = m_pCurrNormal;
  1423. *pDst++ = nx;
  1424. *pDst++ = ny;
  1425. *pDst = nz;
  1426. }
  1427. }
  1428. template <VertexCompressionType_t T> inline void CVertexBuilder::CompressedNormal3fv( const float *n )
  1429. {
  1430. Assert( n );
  1431. CompressedNormal3f<T>( n[0], n[1], n[2] );
  1432. }
  1433. //-----------------------------------------------------------------------------
  1434. // Color setting methods
  1435. //-----------------------------------------------------------------------------
  1436. inline void CVertexBuilder::Color3f( float r, float g, float b )
  1437. {
  1438. Assert( m_pColor && m_pCurrColor );
  1439. Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) );
  1440. Assert( (r >= 0.0) && (g >= 0.0) && (b >= 0.0) );
  1441. Assert( (r <= 1.0) && (g <= 1.0) && (b <= 1.0) );
  1442. #ifdef OPENGL_SWAP_COLORS
  1443. int col = (FastFToC(r)) | (FastFToC(g) << 8) | (FastFToC(b) << 16) | 0xFF000000;
  1444. #elif defined( CELL_GCM_SWAP_COLORS )
  1445. int col = (FastFToC(b) << 8) | (FastFToC(g) << 16) | (FastFToC(r) << 24) | 0x000000FF;
  1446. #else
  1447. int col = (FastFToC(b)) | (FastFToC(g) << 8) | (FastFToC(r) << 16) | 0xFF000000;
  1448. #endif
  1449. *(int*)m_pCurrColor = col;
  1450. }
  1451. inline void CVertexBuilder::Color3fv( const float *rgb )
  1452. {
  1453. Assert(rgb);
  1454. Assert( m_pColor && m_pCurrColor );
  1455. Assert( IsFinite(rgb[0]) && IsFinite(rgb[1]) && IsFinite(rgb[2]) );
  1456. Assert( (rgb[0] >= 0.0) && (rgb[1] >= 0.0) && (rgb[2] >= 0.0) );
  1457. Assert( (rgb[0] <= 1.0) && (rgb[1] <= 1.0) && (rgb[2] <= 1.0) );
  1458. #ifdef OPENGL_SWAP_COLORS
  1459. int col = (FastFToC(rgb[0])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[2]) << 16) | 0xFF000000;
  1460. #elif defined( CELL_GCM_SWAP_COLORS )
  1461. int col = (FastFToC(rgb[2]) << 8) | (FastFToC(rgb[1]) << 16) | (FastFToC(rgb[0]) << 24) | 0x000000FF;
  1462. #else
  1463. int col = (FastFToC(rgb[2])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[0]) << 16) | 0xFF000000;
  1464. #endif
  1465. *(int*)m_pCurrColor = col;
  1466. }
  1467. inline void CVertexBuilder::Color4f( float r, float g, float b, float a )
  1468. {
  1469. Assert( m_pColor && m_pCurrColor );
  1470. Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) && IsFinite(a) );
  1471. Assert( (r >= 0.0) && (g >= 0.0) && (b >= 0.0) && (a >= 0.0) );
  1472. Assert( (r <= 1.0) && (g <= 1.0) && (b <= 1.0) && (a <= 1.0) );
  1473. #ifdef OPENGL_SWAP_COLORS
  1474. int col = (FastFToC(r)) | (FastFToC(g) << 8) | (FastFToC(b) << 16) | (FastFToC(a) << 24);
  1475. #elif defined( CELL_GCM_SWAP_COLORS )
  1476. int col = (FastFToC(b) << 8) | (FastFToC(g) << 16) | (FastFToC(r) << 24) | (FastFToC(a));
  1477. #else
  1478. int col = (FastFToC(b)) | (FastFToC(g) << 8) | (FastFToC(r) << 16) | (FastFToC(a) << 24);
  1479. #endif
  1480. *(int*)m_pCurrColor = col;
  1481. }
  1482. inline void CVertexBuilder::Color4fv( const float *rgba )
  1483. {
  1484. Assert(rgba);
  1485. Assert( m_pColor && m_pCurrColor );
  1486. Assert( IsFinite(rgba[0]) && IsFinite(rgba[1]) && IsFinite(rgba[2]) && IsFinite(rgba[3]) );
  1487. Assert( (rgba[0] >= 0.0) && (rgba[1] >= 0.0) && (rgba[2] >= 0.0) && (rgba[3] >= 0.0) );
  1488. Assert( (rgba[0] <= 1.0) && (rgba[1] <= 1.0) && (rgba[2] <= 1.0) && (rgba[3] <= 1.0) );
  1489. #ifdef OPENGL_SWAP_COLORS
  1490. int col = (FastFToC(rgba[0])) | (FastFToC(rgba[1]) << 8) | (FastFToC(rgba[2]) << 16) | (FastFToC(rgba[3]) << 24);
  1491. #elif defined( CELL_GCM_SWAP_COLORS )
  1492. int col = (FastFToC(rgba[2]) << 8) | (FastFToC(rgba[1]) << 16) | (FastFToC(rgba[0]) << 24) | (FastFToC(rgba[3]));
  1493. #else
  1494. int col = (FastFToC(rgba[2])) | (FastFToC(rgba[1]) << 8) | (FastFToC(rgba[0]) << 16) | (FastFToC(rgba[3]) << 24);
  1495. #endif
  1496. *(int*)m_pCurrColor = col;
  1497. }
  1498. //-----------------------------------------------------------------------------
  1499. // Faster versions of color
  1500. //-----------------------------------------------------------------------------
  1501. // note that on the OSX target (OpenGL) whenever there is vertex data being written as bytes - they need to be written in R,G,B,A memory order
  1502. inline void CVertexBuilder::Color3ub( unsigned char r, unsigned char g, unsigned char b )
  1503. {
  1504. Assert( m_pColor && m_pCurrColor );
  1505. #ifdef OPENGL_SWAP_COLORS
  1506. int col = r | (g << 8) | (b << 16) | 0xFF000000; // r, g, b, a in memory
  1507. #elif defined( CELL_GCM_SWAP_COLORS )
  1508. int col = (b << 8) | (g << 16) | (r << 24) | 0x000000FF;
  1509. #else
  1510. int col = b | (g << 8) | (r << 16) | 0xFF000000;
  1511. #endif
  1512. *(int*)m_pCurrColor = col;
  1513. }
  1514. inline void CVertexBuilder::Color3ubv( unsigned char const* rgb )
  1515. {
  1516. Assert(rgb);
  1517. Assert( m_pColor && m_pCurrColor );
  1518. #ifdef OPENGL_SWAP_COLORS
  1519. int col = rgb[0] | (rgb[1] << 8) | (rgb[2] << 16) | 0xFF000000; // r, g, b, a in memory
  1520. #elif defined( CELL_GCM_SWAP_COLORS )
  1521. int col = ( rgb[2] << 8 ) | ( rgb[1] << 16 ) | ( rgb[0] << 24 ) | 0x000000FF;
  1522. #else
  1523. int col = rgb[2] | (rgb[1] << 8) | (rgb[0] << 16) | 0xFF000000;
  1524. #endif
  1525. *(int*)m_pCurrColor = col;
  1526. }
  1527. inline void CVertexBuilder::Color4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a )
  1528. {
  1529. Assert( m_pColor && m_pCurrColor );
  1530. #ifdef OPENGL_SWAP_COLORS
  1531. int col = r | (g << 8) | (b << 16) | (a << 24); // r, g, b, a in memory
  1532. #elif defined( CELL_GCM_SWAP_COLORS )
  1533. int col = ( r << 24 ) | ( g << 16 ) | ( b << 8 ) | a;
  1534. #else
  1535. int col = b | (g << 8) | (r << 16) | (a << 24);
  1536. #endif
  1537. *(int*)m_pCurrColor = col;
  1538. }
  1539. inline void CVertexBuilder::Color4ub( int nVertexOffset, unsigned char r, unsigned char g, unsigned char b, unsigned char a )
  1540. {
  1541. Assert( m_pColor && m_pCurrColor );
  1542. #ifdef OPENGL_SWAP_COLORS
  1543. int col = r | (g << 8) | (b << 16) | (a << 24); // r, g, b, a in memory
  1544. #elif defined( CELL_GCM_SWAP_COLORS )
  1545. int col = ( r << 24 ) | ( g << 16 ) | ( b << 8 ) | a;
  1546. #else
  1547. int col = b | (g << 8) | (r << 16) | (a << 24);
  1548. #endif
  1549. *(int*)( m_pCurrColor + nVertexOffset * m_VertexSize_Color ) = col;
  1550. }
  1551. inline void CVertexBuilder::Color4ubv( unsigned char const* rgba )
  1552. {
  1553. Assert( rgba );
  1554. Assert( m_pColor && m_pCurrColor );
  1555. #ifdef OPENGL_SWAP_COLORS
  1556. int col = rgba[0] | (rgba[1] << 8) | (rgba[2] << 16) | (rgba[3] << 24); // r, g, b, a in memory
  1557. #elif defined( CELL_GCM_SWAP_COLORS )
  1558. int col = ( rgba[0] << 24 ) | ( rgba[1] << 16 ) | ( rgba[2] << 8 ) | rgba[3];
  1559. #else
  1560. int col = rgba[2] | (rgba[1] << 8) | (rgba[0] << 16) | (rgba[3] << 24);
  1561. #endif
  1562. *(int*)m_pCurrColor = col;
  1563. }
  1564. FORCEINLINE void CVertexBuilder::Color4Packed( int packedColor )
  1565. {
  1566. *(int*)m_pCurrColor = packedColor;
  1567. }
  1568. FORCEINLINE int CVertexBuilder::PackColor4( unsigned char r, unsigned char g, unsigned char b, unsigned char a )
  1569. {
  1570. #if 0 && defined( CELL_GCM_SWAP_COLORS ) // TODO: do we need to swap this, too? PS3 order is RGBA, big endian, because we treat it as a simple UN8 vector
  1571. return ( r << 24 ) | ( g << 16 ) | ( b << 8 ) | a;
  1572. #else
  1573. return b | (g << 8) | (r << 16) | (a << 24);
  1574. #endif
  1575. }
  1576. inline void CVertexBuilder::Specular3f( float r, float g, float b )
  1577. {
  1578. Assert( m_pSpecular );
  1579. Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) );
  1580. Assert( (r >= 0.0) && (g >= 0.0) && (b >= 0.0) );
  1581. Assert( (r <= 1.0) && (g <= 1.0) && (b <= 1.0) );
  1582. unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular];
  1583. #ifdef OPENGL_SWAP_COLORS
  1584. int col = (FastFToC(r)) | (FastFToC(g) << 8) | (FastFToC(b) << 16) | 0xFF000000;
  1585. #elif defined( CELL_GCM_SWAP_COLORS )
  1586. int col = (FastFToC(b) << 8) | (FastFToC(g) << 16) | (FastFToC(r) << 24) | 0x000000FF;
  1587. #else
  1588. int col = (FastFToC(b)) | (FastFToC(g) << 8) | (FastFToC(r) << 16) | 0xFF000000;
  1589. #endif
  1590. *(int*)pSpecular = col;
  1591. }
  1592. inline void CVertexBuilder::Specular3fv( const float *rgb )
  1593. {
  1594. Assert(rgb);
  1595. Assert( m_pSpecular );
  1596. Assert( IsFinite(rgb[0]) && IsFinite(rgb[1]) && IsFinite(rgb[2]) );
  1597. Assert( (rgb[0] >= 0.0) && (rgb[1] >= 0.0) && (rgb[2] >= 0.0) );
  1598. Assert( (rgb[0] <= 1.0) && (rgb[1] <= 1.0) && (rgb[2] <= 1.0) );
  1599. unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular];
  1600. #ifdef OPENGL_SWAP_COLORS
  1601. int col = (FastFToC(rgb[0])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[2]) << 16) | 0xFF000000;
  1602. #elif defined( CELL_GCM_SWAP_COLORS )
  1603. int col = (FastFToC(rgb[2]) << 8) | (FastFToC(rgb[1]) << 16) | (FastFToC(rgb[0]) << 24) | 0x000000FF;
  1604. #else
  1605. int col = (FastFToC(rgb[2])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[0]) << 16) | 0xFF000000;
  1606. #endif
  1607. *(int*)pSpecular = col;
  1608. }
  1609. inline void CVertexBuilder::Specular4f( float r, float g, float b, float a )
  1610. {
  1611. Assert( m_pSpecular );
  1612. Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) && IsFinite(a) );
  1613. Assert( (r >= 0.0) && (g >= 0.0) && (b >= 0.0) && (a >= 0.0) );
  1614. Assert( (r <= 1.0) && (g <= 1.0) && (b <= 1.0) && (a <= 1.0f) );
  1615. unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular];
  1616. #ifdef OPENGL_SWAP_COLORS
  1617. int col = (FastFToC(r)) | (FastFToC(g) << 8) | (FastFToC(b) << 16) | (FastFToC(a) << 24);
  1618. #elif defined( CELL_GCM_SWAP_COLORS )
  1619. int col = (FastFToC(b) << 8) | (FastFToC(g) << 16) | (FastFToC(r) << 24) | (FastFToC(a));
  1620. #else
  1621. int col = (FastFToC(b)) | (FastFToC(g) << 8) | (FastFToC(r) << 16) | (FastFToC(a) << 24);
  1622. #endif
  1623. *(int*)pSpecular = col;
  1624. }
  1625. inline void CVertexBuilder::Specular4fv( const float *rgb )
  1626. {
  1627. Assert(rgb);
  1628. Assert( m_pSpecular );
  1629. Assert( IsFinite(rgb[0]) && IsFinite(rgb[1]) && IsFinite(rgb[2]) && IsFinite(rgb[3]) );
  1630. Assert( (rgb[0] >= 0.0) && (rgb[1] >= 0.0) && (rgb[2] >= 0.0) && (rgb[3] >= 0.0) );
  1631. Assert( (rgb[0] <= 1.0) && (rgb[1] <= 1.0) && (rgb[2] <= 1.0) && (rgb[3] <= 1.0) );
  1632. unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular];
  1633. #ifdef OPENGL_SWAP_COLORS
  1634. int col = (FastFToC(rgb[0])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[2]) << 16) | (FastFToC(rgb[3]) << 24);
  1635. #elif defined( CELL_GCM_SWAP_COLORS )
  1636. int col = (FastFToC(rgb[2]) << 8) | (FastFToC(rgb[1]) << 16) | (FastFToC(rgb[0]) << 24) | (FastFToC(rgb[3]));
  1637. #else
  1638. int col = (FastFToC(rgb[2])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[0]) << 16) | (FastFToC(rgb[3]) << 24);
  1639. #endif
  1640. *(int*)pSpecular = col;
  1641. }
  1642. inline void CVertexBuilder::Specular3ub( unsigned char r, unsigned char g, unsigned char b )
  1643. {
  1644. Assert( m_pSpecular );
  1645. unsigned char *pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular];
  1646. #ifdef OPENGL_SWAP_COLORS
  1647. int col = r | (g << 8) | (b << 16) | 0xFF000000; // r, g, b, a in memory
  1648. #elif defined( CELL_GCM_SWAP_COLORS )
  1649. int col = ( r << 24 ) | ( g << 16 ) | ( b << 8 ) | 0x000000FF;
  1650. #else
  1651. int col = b | (g << 8) | (r << 16) | 0xFF000000;
  1652. #endif
  1653. *(int*)pSpecular = col;
  1654. }
  1655. inline void CVertexBuilder::Specular3ubv( unsigned char const *c )
  1656. {
  1657. Assert( m_pSpecular );
  1658. unsigned char *pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular];
  1659. #ifdef OPENGL_SWAP_COLORS
  1660. int col = c[0] | (c[1] << 8) | (c[2] << 16) | 0xFF000000; // r, g, b, a in memory
  1661. #elif defined( CELL_GCM_SWAP_COLORS )
  1662. int col = ( c[0] << 24 ) | ( c[1] << 16 ) | ( c[2] << 8 ) | 0x000000FF;
  1663. #else
  1664. int col = c[2] | (c[1] << 8) | (c[0] << 16) | 0xFF000000;
  1665. #endif
  1666. *(int*)pSpecular = col;
  1667. }
  1668. inline void CVertexBuilder::Specular4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a )
  1669. {
  1670. Assert( m_pSpecular );
  1671. unsigned char *pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular];
  1672. #ifdef OPENGL_SWAP_COLORS
  1673. int col = r | (g << 8) | (b << 16) | (a << 24); // r, g, b, a in memory
  1674. #elif defined( CELL_GCM_SWAP_COLORS )
  1675. int col = ( r << 24 ) | ( g << 16 ) | ( b << 8 ) | a;
  1676. #else
  1677. int col = b | (g << 8) | (r << 16) | (a << 24);
  1678. #endif
  1679. *(int*)pSpecular = col;
  1680. }
  1681. inline void CVertexBuilder::Specular4ubv( unsigned char const *c )
  1682. {
  1683. Assert( m_pSpecular );
  1684. unsigned char *pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular];
  1685. #ifdef OPENGL_SWAP_COLORS
  1686. int col = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
  1687. #elif defined( CELL_GCM_SWAP_COLORS )
  1688. int col = ( c[0] << 24 ) | ( c[1] << 16 ) | ( c[2] << 8 ) | c[3];
  1689. #else
  1690. int col = c[2] | (c[1] << 8) | (c[0] << 16) | (c[3] << 24);
  1691. #endif
  1692. *(int*)pSpecular = col;
  1693. }
  1694. //-----------------------------------------------------------------------------
  1695. // Texture coordinate setting methods
  1696. //-----------------------------------------------------------------------------
  1697. inline void CVertexBuilder::TexCoord1f( int nStage, float s )
  1698. {
  1699. Assert( m_pTexCoord[nStage] && m_pCurrTexCoord[nStage] );
  1700. Assert( IsFinite(s) );
  1701. float *pDst = m_pCurrTexCoord[nStage];
  1702. *pDst = s;
  1703. }
  1704. inline void CVertexBuilder::TexCoord2f( int nStage, float s, float t )
  1705. {
  1706. Assert( m_pTexCoord[nStage] && m_pCurrTexCoord[nStage] );
  1707. Assert( IsFinite(s) && IsFinite(t) );
  1708. float *pDst = m_pCurrTexCoord[nStage];
  1709. *pDst++ = s;
  1710. *pDst = t;
  1711. }
  1712. inline void CVertexBuilder::TexCoord2f( int nVertexOffset, int nStage, float s, float t )
  1713. {
  1714. Assert( m_pTexCoord[nStage] && m_pCurrTexCoord[nStage] );
  1715. Assert( IsFinite(s) && IsFinite(t) );
  1716. float *pDst = OffsetFloatPointer( m_pCurrTexCoord[nStage], nVertexOffset, m_VertexSize_TexCoord[nStage] );
  1717. *pDst++ = s;
  1718. *pDst = t;
  1719. }
  1720. inline void CVertexBuilder::TexCoord2fv( int nStage, const float *st )
  1721. {
  1722. Assert(st);
  1723. Assert( m_pTexCoord[nStage] && m_pCurrTexCoord[nStage] );
  1724. Assert( IsFinite(st[0]) && IsFinite(st[1]) );
  1725. float *pDst = m_pCurrTexCoord[nStage];
  1726. *pDst++ = *st++;
  1727. *pDst = *st;
  1728. }
  1729. inline void CVertexBuilder::TexCoord3f( int stage, float s, float t, float u )
  1730. {
  1731. // Tried to add too much!
  1732. Assert( m_pTexCoord[stage] && m_pCurrTexCoord[stage] );
  1733. Assert( IsFinite(s) && IsFinite(t) && IsFinite(u) );
  1734. float *pDst = m_pCurrTexCoord[stage];
  1735. *pDst++ = s;
  1736. *pDst++ = t;
  1737. *pDst = u;
  1738. }
  1739. inline void CVertexBuilder::TexCoord3f( int nVertexOffset, int stage, float s, float t, float u )
  1740. {
  1741. // Tried to add too much!
  1742. Assert( m_pTexCoord[stage] && m_pCurrTexCoord[stage] );
  1743. Assert( IsFinite(s) && IsFinite(t) && IsFinite(u) );
  1744. float *pDst = OffsetFloatPointer( m_pCurrTexCoord[stage], nVertexOffset, m_VertexSize_TexCoord[stage] );
  1745. *pDst++ = s;
  1746. *pDst++ = t;
  1747. *pDst = u;
  1748. }
  1749. inline void CVertexBuilder::TexCoord3fv( int stage, const float *stu )
  1750. {
  1751. Assert(stu);
  1752. Assert( m_pTexCoord[stage] && m_pCurrTexCoord[stage] );
  1753. Assert( IsFinite(stu[0]) && IsFinite(stu[1]) && IsFinite(stu[2]) );
  1754. float *pDst = m_pCurrTexCoord[stage];
  1755. *pDst++ = *stu++;
  1756. *pDst++ = *stu++;
  1757. *pDst = *stu;
  1758. }
  1759. inline void CVertexBuilder::TexCoord3fv( int nVertexOffset, int stage, const float *stu )
  1760. {
  1761. Assert(stu);
  1762. Assert( m_pTexCoord[stage] && m_pCurrTexCoord[stage] );
  1763. Assert( IsFinite(stu[0]) && IsFinite(stu[1]) && IsFinite(stu[2]) );
  1764. float *pDst = OffsetFloatPointer( m_pCurrTexCoord[stage], nVertexOffset, m_VertexSize_TexCoord[stage] );
  1765. *pDst++ = *stu++;
  1766. *pDst++ = *stu++;
  1767. *pDst = *stu;
  1768. }
  1769. inline void CVertexBuilder::TexCoord4f( int stage, float s, float t, float u, float v )
  1770. {
  1771. // Tried to add too much!
  1772. Assert( m_pTexCoord[stage] && m_pCurrTexCoord[stage] );
  1773. Assert( IsFinite(s) && IsFinite(t) && IsFinite(u) );
  1774. float *pDst = m_pCurrTexCoord[stage];
  1775. *pDst++ = s;
  1776. *pDst++ = t;
  1777. *pDst++ = u;
  1778. *pDst = v;
  1779. }
  1780. inline void CVertexBuilder::TexCoord4f( int nStage, const fltx4 &fl4stuv )
  1781. {
  1782. #ifdef _GAMECONSOLE
  1783. // can't storeUnaligned4SIMD into write combined memory on the 360 unless
  1784. // the address is actually aligned.
  1785. // The same thing happens on PS3: you can't write into RSX local memory using stvlx/stvrx
  1786. // unless the effective address (EA) is actually 16-byte aligned, or it crashes.
  1787. float *pDst = m_pCurrTexCoord[nStage];
  1788. float *pSrc = (float *)(&fl4stuv);
  1789. *pDst++ = *pSrc++;
  1790. *pDst++ = *pSrc++;
  1791. *pDst++ = *pSrc++;
  1792. *pDst = *pSrc;
  1793. #else
  1794. StoreUnalignedSIMD( m_pCurrTexCoord[nStage], fl4stuv );
  1795. #endif
  1796. }
  1797. inline void CVertexBuilder::TexCoord4fv( int stage, const float *stuv )
  1798. {
  1799. Assert(stuv);
  1800. Assert( m_pTexCoord[stage] && m_pCurrTexCoord[stage] );
  1801. Assert( IsFinite(stuv[0]) && IsFinite(stuv[1]) && IsFinite(stuv[2]) );
  1802. float *pDst = m_pCurrTexCoord[stage];
  1803. *pDst++ = *stuv++;
  1804. *pDst++ = *stuv++;
  1805. *pDst++ = *stuv++;
  1806. *pDst = *stuv;
  1807. }
  1808. inline void CVertexBuilder::TexCoord4f( int nVertexOffset, int stage, float s, float t, float u, float v )
  1809. {
  1810. // Tried to add too much!
  1811. Assert( m_pTexCoord[stage] && m_pCurrTexCoord[stage] );
  1812. Assert( IsFinite(s) && IsFinite(t) && IsFinite(u) );
  1813. float *pDst = OffsetFloatPointer( m_pCurrTexCoord[stage], nVertexOffset, m_VertexSize_TexCoord[stage] );
  1814. *pDst++ = s;
  1815. *pDst++ = t;
  1816. *pDst++ = u;
  1817. *pDst = v;
  1818. }
  1819. inline void CVertexBuilder::TexCoord4fv( int nVertexOffset, int stage, const float *stuv )
  1820. {
  1821. Assert(stuv);
  1822. Assert( m_pTexCoord[stage] && m_pCurrTexCoord[stage] );
  1823. Assert( IsFinite(stuv[0]) && IsFinite(stuv[1]) && IsFinite(stuv[2]) );
  1824. float *pDst = OffsetFloatPointer( m_pCurrTexCoord[stage], nVertexOffset, m_VertexSize_TexCoord[stage] );
  1825. *pDst++ = *stuv++;
  1826. *pDst++ = *stuv++;
  1827. *pDst++ = *stuv++;
  1828. *pDst = *stuv;
  1829. }
  1830. inline void CVertexBuilder::TexCoordSubRect2f( int stage, float s, float t, float offsetS, float offsetT, float scaleS, float scaleT )
  1831. {
  1832. Assert( m_pTexCoord[stage] && m_pCurrTexCoord[stage] );
  1833. Assert( IsFinite(s) && IsFinite(t) );
  1834. float *pDst = m_pCurrTexCoord[stage];
  1835. *pDst++ = ( s * scaleS ) + offsetS;
  1836. *pDst = ( t * scaleT ) + offsetT;
  1837. }
  1838. inline void CVertexBuilder::TexCoordSubRect2fv( int stage, const float *st, const float *offset, const float *scale )
  1839. {
  1840. Assert(st);
  1841. Assert( m_pTexCoord[stage] && m_pCurrTexCoord[stage] );
  1842. Assert( IsFinite(st[0]) && IsFinite(st[1]) );
  1843. float *pDst = m_pCurrTexCoord[stage];
  1844. *pDst++ = ( *st++ * *scale++ ) + *offset++;
  1845. *pDst = ( *st * *scale ) + *offset;
  1846. }
  1847. //-----------------------------------------------------------------------------
  1848. // Tangent space setting methods
  1849. //-----------------------------------------------------------------------------
  1850. inline void CVertexBuilder::TangentS3f( float sx, float sy, float sz )
  1851. {
  1852. Assert( m_pTangentS );
  1853. Assert( IsFinite(sx) && IsFinite(sy) && IsFinite(sz) );
  1854. float* pTangentS = OffsetFloatPointer( m_pTangentS, m_nCurrentVertex, m_VertexSize_TangentS );
  1855. *pTangentS++ = sx;
  1856. *pTangentS++ = sy;
  1857. *pTangentS = sz;
  1858. }
  1859. inline void CVertexBuilder::TangentS3fv( const float* s )
  1860. {
  1861. Assert( s );
  1862. Assert( m_pTangentS );
  1863. Assert( IsFinite(s[0]) && IsFinite(s[1]) && IsFinite(s[2]) );
  1864. float* pTangentS = OffsetFloatPointer( m_pTangentS, m_nCurrentVertex, m_VertexSize_TangentS );
  1865. *pTangentS++ = *s++;
  1866. *pTangentS++ = *s++;
  1867. *pTangentS = *s;
  1868. }
  1869. inline void CVertexBuilder::TangentT3f( float tx, float ty, float tz )
  1870. {
  1871. Assert( m_pTangentT );
  1872. Assert( IsFinite(tx) && IsFinite(ty) && IsFinite(tz) );
  1873. float* pTangentT = OffsetFloatPointer( m_pTangentT, m_nCurrentVertex, m_VertexSize_TangentT );
  1874. *pTangentT++ = tx;
  1875. *pTangentT++ = ty;
  1876. *pTangentT = tz;
  1877. }
  1878. inline void CVertexBuilder::TangentT3fv( const float* t )
  1879. {
  1880. Assert( t );
  1881. Assert( m_pTangentT );
  1882. Assert( IsFinite(t[0]) && IsFinite(t[1]) && IsFinite(t[2]) );
  1883. float* pTangentT = OffsetFloatPointer( m_pTangentT, m_nCurrentVertex, m_VertexSize_TangentT );
  1884. *pTangentT++ = *t++;
  1885. *pTangentT++ = *t++;
  1886. *pTangentT = *t;
  1887. }
  1888. //-----------------------------------------------------------------------------
  1889. // Wrinkle setting methods
  1890. //-----------------------------------------------------------------------------
  1891. inline void CVertexBuilder::Wrinkle1f( float flWrinkle )
  1892. {
  1893. Assert( m_pWrinkle );
  1894. Assert( IsFinite(flWrinkle) );
  1895. float *pWrinkle = OffsetFloatPointer( m_pWrinkle, m_nCurrentVertex, m_VertexSize_Wrinkle );
  1896. *pWrinkle = flWrinkle;
  1897. }
  1898. //-----------------------------------------------------------------------------
  1899. // Bone weight setting methods
  1900. //-----------------------------------------------------------------------------
  1901. inline void CVertexBuilder::BoneWeight( int idx, float weight )
  1902. {
  1903. Assert( m_pBoneWeight );
  1904. Assert( IsFinite( weight ) );
  1905. Assert( idx >= 0 );
  1906. AssertOnce( m_NumBoneWeights == 2 );
  1907. // This test is here because we store N-1 bone weights (the Nth is computed in
  1908. // the vertex shader as "1 - C", where C is the sum of the (N-1) other weights)
  1909. if ( idx < m_NumBoneWeights )
  1910. {
  1911. float* pBoneWeight = OffsetFloatPointer( m_pBoneWeight, m_nCurrentVertex, m_VertexSize_BoneWeight );
  1912. pBoneWeight[idx] = weight;
  1913. }
  1914. }
  1915. inline void CVertexBuilder::BoneWeights2( float weight1, float weight2 )
  1916. {
  1917. Assert( m_pBoneWeight );
  1918. Assert( IsFinite( weight1 ) && IsFinite( weight2 ) );
  1919. AssertOnce( m_NumBoneWeights == 2 );
  1920. // This test is here because we store N-1 bone weights (the Nth is computed in
  1921. // the vertex shader as "1 - C", where C is the sum of the (N-1) other weights)
  1922. float* pBoneWeight = OffsetFloatPointer( m_pBoneWeight, m_nCurrentVertex, m_VertexSize_BoneWeight );
  1923. pBoneWeight[0] = weight1;
  1924. pBoneWeight[1] = weight2;
  1925. }
  1926. static int sg_IndexSwap[4] = { 2, 1, 0, 3 };
  1927. inline void CVertexBuilder::BoneMatrix( int idx, int matrixIdx )
  1928. {
  1929. Assert( m_pBoneMatrixIndex );
  1930. Assert( idx >= 0 );
  1931. Assert( idx < 4 );
  1932. // garymcthack
  1933. if ( matrixIdx == BONE_MATRIX_INDEX_INVALID )
  1934. {
  1935. matrixIdx = 0;
  1936. }
  1937. Assert( (matrixIdx >= 0) && (matrixIdx < 53) );
  1938. #ifdef OPENGL_SWAP_COLORS
  1939. idx = sg_IndexSwap[idx];
  1940. #endif
  1941. #ifndef NEW_SKINNING
  1942. unsigned char* pBoneMatrix = &m_pBoneMatrixIndex[m_nCurrentVertex * m_VertexSize_BoneMatrixIndex];
  1943. if ( IsX360() )
  1944. {
  1945. // store sequentially as wzyx order, gpu delivers as xyzw
  1946. idx = 3-idx;
  1947. }
  1948. pBoneMatrix[idx] = (unsigned char)matrixIdx;
  1949. #else
  1950. float* pBoneMatrix = &m_pBoneMatrixIndex[m_nCurrentVertex * m_VertexSize_BoneMatrixIndex];
  1951. pBoneMatrix[idx] = matrixIdx;
  1952. #endif
  1953. }
  1954. inline void CVertexBuilder::BoneMatrices4( int matrixIdx0, int matrixIdx1, int matrixIdx2, int matrixIdx3 )
  1955. {
  1956. Assert( m_pBoneMatrixIndex );
  1957. // garymcthack
  1958. Assert( matrixIdx0 != BONE_MATRIX_INDEX_INVALID );
  1959. Assert( matrixIdx1 != BONE_MATRIX_INDEX_INVALID );
  1960. Assert( matrixIdx2 != BONE_MATRIX_INDEX_INVALID );
  1961. Assert( matrixIdx3 != BONE_MATRIX_INDEX_INVALID );
  1962. #ifndef NEW_SKINNING
  1963. int nVal;
  1964. if ( IsX360() )
  1965. {
  1966. // store sequentially as wzyx order, gpu delivers as xyzw
  1967. nVal = matrixIdx3 | ( matrixIdx2 << 8 ) | ( matrixIdx1 << 16 ) | ( matrixIdx0 << 24 );
  1968. }
  1969. else
  1970. {
  1971. nVal = matrixIdx0 | ( matrixIdx1 << 8 ) | ( matrixIdx2 << 16 ) | ( matrixIdx3 << 24 );
  1972. }
  1973. int* pBoneMatrix = (int*)( &m_pBoneMatrixIndex[m_nCurrentVertex * m_VertexSize_BoneMatrixIndex] );
  1974. *pBoneMatrix = nVal;
  1975. #else
  1976. float* pBoneMatrix = &m_pBoneMatrixIndex[m_nCurrentVertex * m_VertexSize_BoneMatrixIndex];
  1977. pBoneMatrix[0] = matrixIdx0;
  1978. pBoneMatrix[1] = matrixIdx1;
  1979. pBoneMatrix[2] = matrixIdx2;
  1980. pBoneMatrix[3] = matrixIdx3;
  1981. #endif
  1982. }
  1983. //-----------------------------------------------------------------------------
  1984. // Templatized bone weight setting methods which support compressed vertices
  1985. //-----------------------------------------------------------------------------
  1986. template <VertexCompressionType_t T> inline void CVertexBuilder::CompressedBoneWeight3fv( const float * pWeights )
  1987. {
  1988. Assert( T == m_CompressionType );
  1989. Assert( m_pBoneWeight );
  1990. Assert( pWeights );
  1991. float *pDestWeights = OffsetFloatPointer( m_pBoneWeight, m_nCurrentVertex, m_VertexSize_BoneWeight );
  1992. if ( T == VERTEX_COMPRESSION_ON )
  1993. {
  1994. // Quantize to 15 bits per weight (we use D3DDECLTYPE_SHORT2)
  1995. // NOTE: we perform careful normalization (weights sum to 1.0f in the vertex shader), so
  1996. // as to avoid cracking at boundaries between meshes with different numbers of weights
  1997. // per vertex. For example, (1) needs to yield the same normalized weights as (1,0),
  1998. // and (0.5,0.49) needs to normalize the same normalized weights as (0.5,0.49,0).
  1999. // The key is that values which are *computed* in the shader (e.g. the second weight
  2000. // in a 2-weight mesh) must exactly equal values which are *read* from the vertex
  2001. // stream (e.g. the second weight in a 3-weight mesh).
  2002. // Only 1 or 2 weights (SHORT2N) supported for compressed verts so far
  2003. Assert( m_NumBoneWeights <= 2 );
  2004. const int WEIGHT0_SHIFT = IsX360() ? 16 : 0;
  2005. const int WEIGHT1_SHIFT = IsX360() ? 0 : 16;
  2006. unsigned int *weights = (unsigned int *)pDestWeights;
  2007. // We scale our weights so that they sum to 32768, then subtract 1 (which gets added
  2008. // back in the shader), because dividing by 32767 introduces nasty rounding issues.
  2009. Assert( IsFinite( pWeights[0] ) && ( pWeights[0] >= 0.0f ) && ( pWeights[0] <= 1.0f ) );
  2010. unsigned int weight0 = Float2Int( pWeights[0] * 32768.0f );
  2011. *weights = ( 0x0000FFFF & (weight0 - 1) ) << WEIGHT0_SHIFT;
  2012. #ifdef DEBUG
  2013. if ( m_NumBoneWeights == 1 )
  2014. {
  2015. // Double-check the validity of the values that were passed in
  2016. Assert( IsFinite( pWeights[1] ) && ( pWeights[1] >= 0.0f ) && ( pWeights[1] <= 1.0f ) );
  2017. unsigned int weight1 = Float2Int( pWeights[1] * 32768.0f );
  2018. Assert( ( weight0 + weight1 ) <= 32768 );
  2019. }
  2020. #endif
  2021. if ( m_NumBoneWeights > 1 )
  2022. {
  2023. // This path for 3 weights per vert (2 are stored and the 3rd is computed
  2024. // in the shader - we do post-quantization normalization here in such a
  2025. // way as to avoid mesh-boundary cracking)
  2026. Assert( m_NumBoneWeights == 2 );
  2027. Assert( IsFinite( pWeights[1] ) && ( pWeights[1] >= 0.0f ) && ( pWeights[1] <= 1.0f ) );
  2028. Assert( IsFinite( pWeights[2] ) && ( pWeights[2] >= 0.0f ) && ( pWeights[2] <= 1.0f ) );
  2029. unsigned int weight1 = Float2Int( pWeights[1] * 32768.0f );
  2030. unsigned int weight2 = Float2Int( pWeights[2] * 32768.0f );
  2031. Assert( ( weight0 + weight1 + weight2 ) <= 32768 );
  2032. unsigned int residual = 32768 - ( weight0 + weight1 + weight2 );
  2033. weight1 += residual; // Normalize
  2034. *weights |= ( 0x0000FFFF & ( weight1 - 1 ) ) << WEIGHT1_SHIFT;
  2035. }
  2036. }
  2037. else // Uncompressed path
  2038. {
  2039. pDestWeights[0] = pWeights[0];
  2040. pDestWeights[1] = pWeights[1];
  2041. }
  2042. }
  2043. //-----------------------------------------------------------------------------
  2044. // Generic per-vertex data setting method
  2045. //-----------------------------------------------------------------------------
  2046. inline void CVertexBuilder::UserData( const float* pData )
  2047. {
  2048. Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // Use the templatized version if you want to support compression
  2049. Assert( pData );
  2050. int userDataSize = 4; // garymcthack
  2051. float *pUserData = OffsetFloatPointer( m_pUserData, m_nCurrentVertex, m_VertexSize_UserData );
  2052. memcpy( pUserData, pData, sizeof( float ) * userDataSize );
  2053. }
  2054. //-----------------------------------------------------------------------------
  2055. // Templatized generic per-vertex data setting method which supports compressed vertices
  2056. //-----------------------------------------------------------------------------
  2057. template <VertexCompressionType_t T> inline void CVertexBuilder::CompressedUserData( const float* pData )
  2058. {
  2059. Assert( T == m_CompressionType );
  2060. Assert( pData );
  2061. // This is always in fact a tangent vector, not generic 'userdata'
  2062. Assert( IsFinite(pData[0]) && IsFinite(pData[1]) && IsFinite(pData[2]) );
  2063. Assert( pData[0] >= -1.05f && pData[0] <= 1.05f );
  2064. Assert( pData[1] >= -1.05f && pData[1] <= 1.05f );
  2065. Assert( pData[2] >= -1.05f && pData[2] <= 1.05f );
  2066. Assert( pData[3] == +1.0f || pData[3] == -1.0f );
  2067. // FIXME: studiorender is passing in non-unit normals
  2068. //float lengthSqd = pData[0]*pData[0] + pData[1]*pData[1] + pData[2]*pData[2];
  2069. //Assert( lengthSqd >= 0.95f && lengthSqd <= 1.05f );
  2070. if ( T == VERTEX_COMPRESSION_ON )
  2071. {
  2072. float binormalSign = pData[3];
  2073. #if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 )
  2074. float *pUserData = OffsetFloatPointer( m_pUserData, m_nCurrentVertex, m_VertexSize_UserData );
  2075. PackNormal_SHORT2( pData, (unsigned int *)pUserData, binormalSign );
  2076. #else //( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 )
  2077. // FIXME: add a combined CompressedNormalAndTangent() accessor, to avoid reading back from write-combined memory here
  2078. // The normal should have already been written into the lower 16
  2079. // bits - here, we OR in the tangent into the upper 16 bits
  2080. unsigned int existingNormalData = *(unsigned int *)m_pCurrNormal;
  2081. Assert( ( existingNormalData & 0xFFFF0000 ) == 0 );
  2082. #ifdef _DEBUG
  2083. Assert( m_bWrittenNormal == true );
  2084. m_bWrittenUserData = true;
  2085. #endif
  2086. bool bIsTangent = true;
  2087. unsigned int tangentData = 0;
  2088. PackNormal_UBYTE4( pData, &tangentData, bIsTangent, binormalSign );
  2089. *(unsigned int *)m_pCurrNormal = existingNormalData | tangentData;
  2090. #endif
  2091. }
  2092. else
  2093. {
  2094. int userDataSize = 4; // garymcthack
  2095. float *pUserData = OffsetFloatPointer( m_pUserData, m_nCurrentVertex, m_VertexSize_UserData );
  2096. memcpy( pUserData, pData, sizeof( float ) * userDataSize );
  2097. }
  2098. }
  2099. //-----------------------------------------------------------------------------
  2100. //
  2101. // Helper class used to define index buffers
  2102. //
  2103. //-----------------------------------------------------------------------------
  2104. class CIndexBuilder : private IndexDesc_t
  2105. {
  2106. public:
  2107. CIndexBuilder();
  2108. CIndexBuilder( IIndexBuffer *pIndexBuffer, MaterialIndexFormat_t fmt = MATERIAL_INDEX_FORMAT_UNKNOWN );
  2109. ~CIndexBuilder();
  2110. // Begins, ends modification of the index buffer (returns true if the lock succeeded)
  2111. // A lock may not succeed if append is set to true and there isn't enough room
  2112. // NOTE: Append is only used with dynamic index buffers; it's ignored for static buffers
  2113. bool Lock( int nMaxIndexCount, int nIndexOffset, bool bAppend = false );
  2114. void Unlock();
  2115. // Spews the current data
  2116. // NOTE: Can only be called during a lock/unlock block
  2117. void SpewData();
  2118. // Returns the number of indices we can fit into the buffer without needing to discard
  2119. int GetRoomRemaining() const;
  2120. // Binds this index buffer
  2121. void Bind( IMatRenderContext *pContext );
  2122. // Returns the byte offset
  2123. int Offset() const;
  2124. // Begins, ends modification of the index buffer
  2125. // NOTE: IndexOffset is the number to add to all indices written into the buffer;
  2126. // useful when using dynamic vertex buffers.
  2127. void Begin( IIndexBuffer *pIndexBuffer, int nMaxIndexCount, int nIndexOffset = 0 );
  2128. void End( bool bSpewData = false );
  2129. // Locks the index buffer to modify existing data
  2130. // Passing nVertexCount == -1 says to lock all the vertices for modification.
  2131. // Pass 0 for nIndexCount to not lock the index buffer.
  2132. void BeginModify( IIndexBuffer *pIndexBuffer, int nFirstIndex = 0, int nIndexCount = 0, int nIndexOffset = 0 );
  2133. void EndModify( bool bSpewData = false );
  2134. // returns the number of indices
  2135. int IndexCount() const;
  2136. // Returns the total number of indices across all Locks()
  2137. int TotalIndexCount() const;
  2138. // Resets the mesh builder so it points to the start of everything again
  2139. void Reset();
  2140. // Selects the nth Index
  2141. void SelectIndex( int nBufferIndex );
  2142. // Advances the current index by one
  2143. void AdvanceIndex();
  2144. void AdvanceIndices( int nIndexCount );
  2145. int GetCurrentIndex()const;
  2146. int GetIndexOffset() const;
  2147. int GetFirstIndex() const;
  2148. unsigned short const* Index() const;
  2149. unsigned short *BaseIndexData() const;
  2150. unsigned short * IndexBuffer_InterlockedAdd(int numberOfIndices);
  2151. // Used to define the indices (only used if you aren't using primitives)
  2152. void Index( unsigned short nIndex );
  2153. // Fast Index! No need to call advance index, and no random access allowed
  2154. void FastIndex( unsigned short nIndex );
  2155. void FastIndex( int nIndexOffset, unsigned short nIndex );
  2156. // NOTE: This version is the one you really want to achieve write-combining;
  2157. // Write combining only works if you write in 4 bytes chunks.
  2158. void FastIndex2( unsigned short nIndex1, unsigned short nIndex2 );
  2159. void FastIndex2( int nIndexOffset, unsigned short nIndex1, unsigned short nIndex2 );
  2160. // Generates indices for a particular primitive type
  2161. void GenerateIndices( MaterialPrimitiveType_t primitiveType, int nIndexCount );
  2162. // FIXME: Remove! Backward compat so we can use this from a CMeshBuilder.
  2163. void AttachBegin( IMesh* pMesh, int nMaxIndexCount, const MeshDesc_t &desc );
  2164. void AttachEnd();
  2165. void AttachBeginModify( IMesh* pMesh, int nFirstIndex, int nIndexCount, const MeshDesc_t &desc );
  2166. void AttachEndModify();
  2167. void FastTriangle( int startVert );
  2168. void FastQuad( int startVert );
  2169. void FastQuad( int nIndexOffset, int startVert );
  2170. void FastPolygon( int startVert, int numTriangles );
  2171. void FastPolygon( int nVertexOffset, int startVert, int numTriangles );
  2172. void FastPolygonList( int startVert, int *pVertexCount, int polygonCount );
  2173. void FastIndexList( const unsigned short *pIndexList, int startVert, int indexCount );
  2174. private:
  2175. // The mesh we're modifying
  2176. IIndexBuffer *m_pIndexBuffer;
  2177. // Max number of indices
  2178. int m_nMaxIndexCount;
  2179. // Number of indices
  2180. int m_nIndexCount;
  2181. // Offset to add to each index as it's written into the buffer
  2182. int m_nIndexOffset;
  2183. // The current index
  2184. mutable int m_nCurrentIndex;
  2185. // Total number of indices appended
  2186. int m_nTotalIndexCount;
  2187. // First index buffer offset + first index
  2188. unsigned int m_nBufferOffset;
  2189. unsigned int m_nBufferFirstIndex;
  2190. // Used to make sure Begin/End calls and BeginModify/EndModify calls match.
  2191. bool m_bModify;
  2192. };
  2193. //-----------------------------------------------------------------------------
  2194. //
  2195. // Inline methods related to CIndexBuilder
  2196. //
  2197. //-----------------------------------------------------------------------------
  2198. //-----------------------------------------------------------------------------
  2199. // Constructor
  2200. //-----------------------------------------------------------------------------
  2201. inline CIndexBuilder::CIndexBuilder() : m_pIndexBuffer(0), m_nIndexCount(0),
  2202. m_nCurrentIndex(0), m_nMaxIndexCount(0)
  2203. {
  2204. m_nTotalIndexCount = 0;
  2205. m_nBufferOffset = INVALID_BUFFER_OFFSET;
  2206. m_nBufferFirstIndex = 0;
  2207. #ifdef _DEBUG
  2208. m_bModify = false;
  2209. #endif
  2210. }
  2211. inline CIndexBuilder::CIndexBuilder( IIndexBuffer *pIndexBuffer, MaterialIndexFormat_t fmt )
  2212. {
  2213. m_pIndexBuffer = pIndexBuffer;
  2214. m_nBufferOffset = INVALID_BUFFER_OFFSET;
  2215. m_nBufferFirstIndex = 0;
  2216. m_nIndexCount = 0;
  2217. m_nCurrentIndex = 0;
  2218. m_nMaxIndexCount = 0;
  2219. m_nTotalIndexCount = 0;
  2220. if ( m_pIndexBuffer->IsDynamic() )
  2221. {
  2222. m_pIndexBuffer->BeginCastBuffer( fmt );
  2223. }
  2224. else
  2225. {
  2226. Assert( m_pIndexBuffer->IndexFormat() == fmt );
  2227. }
  2228. #ifdef _DEBUG
  2229. m_bModify = false;
  2230. #endif
  2231. }
  2232. inline CIndexBuilder::~CIndexBuilder()
  2233. {
  2234. if ( m_pIndexBuffer && m_pIndexBuffer->IsDynamic() )
  2235. {
  2236. m_pIndexBuffer->EndCastBuffer();
  2237. }
  2238. }
  2239. //-----------------------------------------------------------------------------
  2240. // Begins, ends modification of the index buffer
  2241. //-----------------------------------------------------------------------------
  2242. inline bool CIndexBuilder::Lock( int nMaxIndexCount, int nIndexOffset, bool bAppend )
  2243. {
  2244. Assert( m_pIndexBuffer );
  2245. m_bModify = false;
  2246. m_nIndexOffset = nIndexOffset;
  2247. m_nMaxIndexCount = nMaxIndexCount;
  2248. m_nIndexCount = 0;
  2249. bool bFirstLock = ( m_nBufferOffset == INVALID_BUFFER_OFFSET );
  2250. if ( bFirstLock )
  2251. {
  2252. bAppend = false;
  2253. }
  2254. if ( !bAppend )
  2255. {
  2256. m_nTotalIndexCount = 0;
  2257. }
  2258. Reset();
  2259. // Lock the index buffer
  2260. if ( !m_pIndexBuffer->Lock( m_nMaxIndexCount, bAppend, *this ) )
  2261. {
  2262. m_nMaxIndexCount = 0;
  2263. return false;
  2264. }
  2265. if ( bFirstLock )
  2266. {
  2267. m_nBufferOffset = m_nOffset;
  2268. m_nBufferFirstIndex = m_nFirstIndex;
  2269. }
  2270. return true;
  2271. }
  2272. inline void CIndexBuilder::Unlock()
  2273. {
  2274. Assert( !m_bModify && m_pIndexBuffer );
  2275. m_pIndexBuffer->Unlock( m_nIndexCount, *this );
  2276. m_nTotalIndexCount += m_nIndexCount;
  2277. m_nMaxIndexCount = 0;
  2278. #ifdef _DEBUG
  2279. // Null out our data...
  2280. memset( (IndexDesc_t*)this, 0, sizeof(IndexDesc_t) );
  2281. #endif
  2282. }
  2283. inline void CIndexBuilder::SpewData()
  2284. {
  2285. m_pIndexBuffer->Spew( m_nIndexCount, *this );
  2286. }
  2287. //-----------------------------------------------------------------------------
  2288. // Binds this index buffer
  2289. //-----------------------------------------------------------------------------
  2290. inline void CIndexBuilder::Bind( IMatRenderContext *pContext )
  2291. {
  2292. if ( m_pIndexBuffer && ( m_nBufferOffset != INVALID_BUFFER_OFFSET ) )
  2293. {
  2294. pContext->BindIndexBuffer( m_pIndexBuffer, m_nBufferOffset );
  2295. }
  2296. else
  2297. {
  2298. pContext->BindIndexBuffer( NULL, 0 );
  2299. }
  2300. }
  2301. //-----------------------------------------------------------------------------
  2302. // Returns the byte offset
  2303. //-----------------------------------------------------------------------------
  2304. inline int CIndexBuilder::Offset() const
  2305. {
  2306. return m_nBufferOffset;
  2307. }
  2308. inline int CIndexBuilder::GetFirstIndex() const
  2309. {
  2310. return m_nBufferFirstIndex;
  2311. }
  2312. //-----------------------------------------------------------------------------
  2313. // Begins, ends modification of the index buffer
  2314. //-----------------------------------------------------------------------------
  2315. inline void CIndexBuilder::Begin( IIndexBuffer *pIndexBuffer, int nMaxIndexCount, int nIndexOffset )
  2316. {
  2317. Assert( pIndexBuffer && (!m_pIndexBuffer) );
  2318. m_pIndexBuffer = pIndexBuffer;
  2319. m_nIndexCount = 0;
  2320. m_nMaxIndexCount = nMaxIndexCount;
  2321. m_nIndexOffset = nIndexOffset;
  2322. m_bModify = false;
  2323. // Lock the index buffer
  2324. m_pIndexBuffer->Lock( m_nMaxIndexCount, false, *this );
  2325. // Point to the start of the buffers..
  2326. Reset();
  2327. }
  2328. inline void CIndexBuilder::End( bool bSpewData )
  2329. {
  2330. // Make sure they called Begin()
  2331. Assert( !m_bModify );
  2332. if ( bSpewData )
  2333. {
  2334. m_pIndexBuffer->Spew( m_nIndexCount, *this );
  2335. }
  2336. // Unlock our buffers
  2337. m_pIndexBuffer->Unlock( m_nIndexCount, *this );
  2338. m_pIndexBuffer = 0;
  2339. m_nMaxIndexCount = 0;
  2340. #ifdef _DEBUG
  2341. // Null out our data...
  2342. memset( (IndexDesc_t*)this, 0, sizeof(IndexDesc_t) );
  2343. #endif
  2344. }
  2345. //-----------------------------------------------------------------------------
  2346. // Begins, ends modification of an existing index buffer which has already been filled out
  2347. //-----------------------------------------------------------------------------
  2348. inline void CIndexBuilder::BeginModify( IIndexBuffer* pIndexBuffer, int nFirstIndex, int nIndexCount, int nIndexOffset )
  2349. {
  2350. m_pIndexBuffer = pIndexBuffer;
  2351. m_nIndexCount = nIndexCount;
  2352. m_nMaxIndexCount = nIndexCount;
  2353. m_nIndexOffset = nIndexOffset;
  2354. m_bModify = true;
  2355. // Lock the vertex and index buffer
  2356. m_pIndexBuffer->ModifyBegin( false, nFirstIndex, nIndexCount, *this );
  2357. // Point to the start of the buffers..
  2358. Reset();
  2359. }
  2360. inline void CIndexBuilder::EndModify( bool bSpewData )
  2361. {
  2362. Assert( m_pIndexBuffer );
  2363. Assert( m_bModify ); // Make sure they called BeginModify.
  2364. if ( bSpewData )
  2365. {
  2366. m_pIndexBuffer->Spew( m_nIndexCount, *this );
  2367. }
  2368. // Unlock our buffers
  2369. m_pIndexBuffer->ModifyEnd( *this );
  2370. m_pIndexBuffer = 0;
  2371. m_nMaxIndexCount = 0;
  2372. #ifdef _DEBUG
  2373. // Null out our data...
  2374. memset( (IndexDesc_t*)this, 0, sizeof(IndexDesc_t) );
  2375. #endif
  2376. }
  2377. //-----------------------------------------------------------------------------
  2378. // FIXME: Remove! Backward compat so we can use this from a CMeshBuilder.
  2379. //-----------------------------------------------------------------------------
  2380. inline void CIndexBuilder::AttachBegin( IMesh* pMesh, int nMaxIndexCount, const MeshDesc_t &desc )
  2381. {
  2382. m_pIndexBuffer = pMesh;
  2383. m_nIndexCount = 0;
  2384. m_nMaxIndexCount = nMaxIndexCount;
  2385. m_bModify = false;
  2386. // Copy relevant data from the mesh desc
  2387. m_nIndexOffset = desc.m_nFirstVertex;
  2388. m_pIndices = desc.m_pIndices;
  2389. m_nIndexSize = desc.m_nIndexSize;
  2390. // Point to the start of the buffers..
  2391. Reset();
  2392. }
  2393. inline void CIndexBuilder::AttachEnd()
  2394. {
  2395. Assert( m_pIndexBuffer );
  2396. Assert( !m_bModify ); // Make sure they called AttachBegin.
  2397. m_pIndexBuffer = 0;
  2398. m_nMaxIndexCount = 0;
  2399. #ifdef _DEBUG
  2400. // Null out our data...
  2401. memset( (IndexDesc_t*)this, 0, sizeof(IndexDesc_t) );
  2402. #endif
  2403. }
  2404. inline void CIndexBuilder::AttachBeginModify( IMesh* pMesh, int nFirstIndex, int nIndexCount, const MeshDesc_t &desc )
  2405. {
  2406. m_pIndexBuffer = pMesh;
  2407. m_nIndexCount = nIndexCount;
  2408. m_nMaxIndexCount = nIndexCount;
  2409. m_bModify = true;
  2410. // Copy relevant data from the mesh desc
  2411. m_nIndexOffset = desc.m_nFirstVertex;
  2412. m_pIndices = desc.m_pIndices;
  2413. m_nIndexSize = desc.m_nIndexSize;
  2414. // Point to the start of the buffers..
  2415. Reset();
  2416. }
  2417. inline void CIndexBuilder::AttachEndModify()
  2418. {
  2419. Assert( m_pIndexBuffer );
  2420. Assert( m_bModify ); // Make sure they called AttachBeginModify.
  2421. m_pIndexBuffer = 0;
  2422. m_nMaxIndexCount = 0;
  2423. #ifdef _DEBUG
  2424. // Null out our data...
  2425. memset( (IndexDesc_t*)this, 0, sizeof(IndexDesc_t) );
  2426. #endif
  2427. }
  2428. //-----------------------------------------------------------------------------
  2429. // Resets the index buffer builder so it points to the start of everything again
  2430. //-----------------------------------------------------------------------------
  2431. inline void CIndexBuilder::Reset()
  2432. {
  2433. m_nCurrentIndex = 0;
  2434. }
  2435. //-----------------------------------------------------------------------------
  2436. // returns the number of indices
  2437. //-----------------------------------------------------------------------------
  2438. inline int CIndexBuilder::IndexCount() const
  2439. {
  2440. return m_nIndexCount;
  2441. }
  2442. //-----------------------------------------------------------------------------
  2443. // Returns the total number of indices across all Locks()
  2444. //-----------------------------------------------------------------------------
  2445. inline int CIndexBuilder::TotalIndexCount() const
  2446. {
  2447. return m_nTotalIndexCount;
  2448. }
  2449. //-----------------------------------------------------------------------------
  2450. // Advances the current index
  2451. //-----------------------------------------------------------------------------
  2452. inline void CIndexBuilder::AdvanceIndex()
  2453. {
  2454. m_nCurrentIndex += m_nIndexSize;
  2455. if ( m_nCurrentIndex > m_nIndexCount )
  2456. {
  2457. m_nIndexCount = m_nCurrentIndex;
  2458. }
  2459. }
  2460. inline void CIndexBuilder::AdvanceIndices( int nIndices )
  2461. {
  2462. m_nCurrentIndex += nIndices * m_nIndexSize;
  2463. if ( m_nCurrentIndex > m_nIndexCount )
  2464. {
  2465. m_nIndexCount = m_nCurrentIndex;
  2466. }
  2467. }
  2468. //-----------------------------------------------------------------------------
  2469. // Returns the current index
  2470. //-----------------------------------------------------------------------------
  2471. inline int CIndexBuilder::GetCurrentIndex() const
  2472. {
  2473. return m_nCurrentIndex;
  2474. }
  2475. inline int CIndexBuilder::GetIndexOffset() const
  2476. {
  2477. return m_nIndexOffset;
  2478. }
  2479. inline unsigned short const* CIndexBuilder::Index() const
  2480. {
  2481. Assert( m_nCurrentIndex < m_nMaxIndexCount );
  2482. return &m_pIndices[m_nCurrentIndex];
  2483. }
  2484. inline unsigned short *CIndexBuilder::BaseIndexData() const
  2485. {
  2486. return m_pIndices;
  2487. }
  2488. inline unsigned short * CIndexBuilder::IndexBuffer_InterlockedAdd(int numberOfIndices)
  2489. {
  2490. Assert( m_nCurrentIndex + numberOfIndices < m_nMaxIndexCount );
  2491. int oldValue = ThreadInterlockedExchangeAdd(&m_nCurrentIndex, numberOfIndices);
  2492. // ThreadInterlockedExchangeAdd() returns the result *before* the addition
  2493. return &m_pIndices[oldValue];
  2494. }
  2495. inline void CIndexBuilder::SelectIndex( int nIndex )
  2496. {
  2497. Assert( ( nIndex >= 0 ) && ( nIndex < m_nIndexCount ) );
  2498. m_nCurrentIndex = nIndex * m_nIndexSize;
  2499. }
  2500. //-----------------------------------------------------------------------------
  2501. // Used to write data into the index buffer
  2502. //-----------------------------------------------------------------------------
  2503. inline void CIndexBuilder::Index( unsigned short nIndex )
  2504. {
  2505. Assert( m_pIndices );
  2506. Assert( m_nCurrentIndex < m_nMaxIndexCount );
  2507. m_pIndices[ m_nCurrentIndex ] = (unsigned short)( m_nIndexOffset + nIndex );
  2508. }
  2509. // Fast Index! No need to call advance index
  2510. inline void CIndexBuilder::FastIndex( unsigned short nIndex )
  2511. {
  2512. Assert( m_pIndices );
  2513. Assert( m_nCurrentIndex < m_nMaxIndexCount );
  2514. m_pIndices[m_nCurrentIndex] = (unsigned short)( m_nIndexOffset + nIndex );
  2515. m_nCurrentIndex += m_nIndexSize;
  2516. m_nIndexCount = m_nCurrentIndex;
  2517. }
  2518. inline void CIndexBuilder::FastIndex( int nIndexOffset, unsigned short nIndex )
  2519. {
  2520. Assert( m_pIndices );
  2521. Assert( nIndexOffset < m_nMaxIndexCount );
  2522. m_pIndices[m_nCurrentIndex + nIndexOffset] = (unsigned short)( m_nIndexOffset + nIndex );
  2523. }
  2524. FORCEINLINE void CIndexBuilder::FastTriangle( int startVert )
  2525. {
  2526. startVert += m_nIndexOffset;
  2527. unsigned short *pIndices = &m_pIndices[m_nCurrentIndex];
  2528. *pIndices++ = startVert++;
  2529. *pIndices++ = startVert++;
  2530. *pIndices++ = startVert;
  2531. AdvanceIndices(3);
  2532. }
  2533. FORCEINLINE void CIndexBuilder::FastQuad( int startVert )
  2534. {
  2535. FastQuad( m_nCurrentIndex, startVert );
  2536. AdvanceIndices(6);
  2537. }
  2538. FORCEINLINE void CIndexBuilder::FastQuad( int nIndexOffset, int startVert )
  2539. {
  2540. startVert += m_nIndexOffset;
  2541. unsigned short *pIndices = &m_pIndices[ nIndexOffset ];
  2542. *pIndices++ = startVert++;
  2543. *pIndices++ = startVert++;
  2544. *pIndices++ = startVert;
  2545. *pIndices++ = startVert - 2;
  2546. *pIndices++ = startVert++;
  2547. *pIndices++ = startVert;
  2548. }
  2549. inline void CIndexBuilder::FastPolygon( int startVert, int triangleCount )
  2550. {
  2551. unsigned short *pIndex = &m_pIndices[m_nCurrentIndex];
  2552. startVert += m_nIndexOffset;
  2553. if ( !IsX360() )
  2554. {
  2555. // NOTE: IndexSize is 1 or 0 (0 for alt-tab)
  2556. // This prevents us from writing into bogus memory
  2557. Assert( m_nIndexSize == 0 || m_nIndexSize == 1 );
  2558. triangleCount *= m_nIndexSize;
  2559. }
  2560. for ( int v = 0; v < triangleCount; ++v )
  2561. {
  2562. *pIndex++ = startVert;
  2563. *pIndex++ = startVert + v + 1;
  2564. *pIndex++ = startVert + v + 2;
  2565. }
  2566. AdvanceIndices(triangleCount*3);
  2567. }
  2568. inline void CIndexBuilder::FastPolygon( int nIndexOffset, int startVert, int triangleCount )
  2569. {
  2570. unsigned short *pIndex = &m_pIndices[m_nCurrentIndex + nIndexOffset];
  2571. startVert += m_nIndexOffset;
  2572. if ( !IsX360() )
  2573. {
  2574. // NOTE: IndexSize is 1 or 0 (0 for alt-tab)
  2575. // This prevents us from writing into bogus memory
  2576. Assert( m_nIndexSize == 0 || m_nIndexSize == 1 );
  2577. triangleCount *= m_nIndexSize;
  2578. }
  2579. for ( int v = 0; v < triangleCount; ++v )
  2580. {
  2581. *pIndex++ = startVert;
  2582. *pIndex++ = startVert + v + 1;
  2583. *pIndex++ = startVert + v + 2;
  2584. }
  2585. }
  2586. inline void CIndexBuilder::FastPolygonList( int startVert, int *pVertexCount, int polygonCount )
  2587. {
  2588. unsigned short *pIndex = &m_pIndices[m_nCurrentIndex];
  2589. startVert += m_nIndexOffset;
  2590. int indexOut = 0;
  2591. if ( !IsX360() )
  2592. {
  2593. // NOTE: IndexSize is 1 or 0 (0 for alt-tab)
  2594. // This prevents us from writing into bogus memory
  2595. Assert( m_nIndexSize == 0 || m_nIndexSize == 1 );
  2596. polygonCount *= m_nIndexSize;
  2597. }
  2598. for ( int i = 0; i < polygonCount; i++ )
  2599. {
  2600. int vertexCount = pVertexCount[i];
  2601. int triangleCount = vertexCount-2;
  2602. for ( int v = 0; v < triangleCount; ++v )
  2603. {
  2604. *pIndex++ = startVert;
  2605. *pIndex++ = startVert + v + 1;
  2606. *pIndex++ = startVert + v + 2;
  2607. }
  2608. startVert += vertexCount;
  2609. indexOut += triangleCount * 3;
  2610. }
  2611. AdvanceIndices(indexOut);
  2612. }
  2613. inline void CIndexBuilder::FastIndexList( const unsigned short *pIndexList, int startVert, int indexCount )
  2614. {
  2615. unsigned short *pIndexOut = &m_pIndices[m_nCurrentIndex];
  2616. startVert += m_nIndexOffset;
  2617. if ( !IsX360() )
  2618. {
  2619. // NOTE: IndexSize is 1 or 0 (0 for alt-tab)
  2620. // This prevents us from writing into bogus memory
  2621. Assert( m_nIndexSize == 0 || m_nIndexSize == 1 );
  2622. indexCount *= m_nIndexSize;
  2623. }
  2624. for ( int i = 0; i < indexCount; ++i )
  2625. {
  2626. pIndexOut[i] = startVert + pIndexList[i];
  2627. }
  2628. AdvanceIndices(indexCount);
  2629. }
  2630. FORCEINLINE unsigned int TwoIndices( unsigned int nIndex1, unsigned int nIndex2 )
  2631. {
  2632. #ifdef PLAT_LITTLE_ENDIAN
  2633. return ( (unsigned int)nIndex1 ) | ( ( (unsigned int)nIndex2 ) << 16 );
  2634. #else
  2635. return ( (unsigned int)nIndex2 ) | ( ( (unsigned int)nIndex1 ) << 16 );
  2636. #endif
  2637. }
  2638. //-----------------------------------------------------------------------------
  2639. // NOTE: This version is the one you really want to achieve write-combining;
  2640. // Write combining only works if you write in 4 bytes chunks.
  2641. //-----------------------------------------------------------------------------
  2642. inline void CIndexBuilder::FastIndex2( unsigned short nIndex1, unsigned short nIndex2 )
  2643. {
  2644. Assert( m_pIndices );
  2645. Assert( m_nCurrentIndex < m_nMaxIndexCount - 1 );
  2646. // Assert( ( (int)( &m_pIndices[m_nCurrentIndex] ) & 0x3 ) == 0 );
  2647. *(int*)( &m_pIndices[m_nCurrentIndex] ) = TwoIndices( (unsigned int)nIndex1 + m_nIndexOffset, (unsigned int)nIndex2 + m_nIndexOffset );
  2648. m_nCurrentIndex += m_nIndexSize + m_nIndexSize;
  2649. m_nIndexCount = m_nCurrentIndex;
  2650. }
  2651. //-----------------------------------------------------------------------------
  2652. inline void CIndexBuilder::FastIndex2( int nIndexOffset, unsigned short nIndex1, unsigned short nIndex2 )
  2653. {
  2654. Assert( m_pIndices );
  2655. Assert( m_nCurrentIndex < m_nMaxIndexCount - 1 );
  2656. // Assert( ( (int)( &m_pIndices[m_nCurrentIndex] ) & 0x3 ) == 0 );
  2657. *(int*)( &m_pIndices[nIndexOffset] ) = TwoIndices( (unsigned int)nIndex1 + m_nIndexOffset, (unsigned int)nIndex2 + m_nIndexOffset );
  2658. }
  2659. //-----------------------------------------------------------------------------
  2660. // Generates indices for a particular primitive type
  2661. //-----------------------------------------------------------------------------
  2662. inline void CIndexBuilder::GenerateIndices( MaterialPrimitiveType_t primitiveType, int nIndexCount )
  2663. {
  2664. // FIXME: How to make this work with short vs int sized indices?
  2665. // Don't generate indices if we've got an empty buffer
  2666. if ( m_nIndexSize == 0 )
  2667. return;
  2668. int nMaxIndices = m_nMaxIndexCount - m_nCurrentIndex;
  2669. nIndexCount = MIN( nMaxIndices, nIndexCount );
  2670. if ( nIndexCount == 0 )
  2671. return;
  2672. unsigned short *pIndices = &m_pIndices[m_nCurrentIndex];
  2673. switch( primitiveType )
  2674. {
  2675. case MATERIAL_INSTANCED_QUADS:
  2676. Assert(0); // Shouldn't get here (this primtype is unindexed)
  2677. break;
  2678. case MATERIAL_QUADS:
  2679. GenerateQuadIndexBuffer( pIndices, nIndexCount, m_nIndexOffset );
  2680. break;
  2681. case MATERIAL_POLYGON:
  2682. GeneratePolygonIndexBuffer( pIndices, nIndexCount, m_nIndexOffset );
  2683. break;
  2684. case MATERIAL_LINE_STRIP:
  2685. GenerateLineStripIndexBuffer( pIndices, nIndexCount, m_nIndexOffset );
  2686. break;
  2687. case MATERIAL_LINE_LOOP:
  2688. GenerateLineLoopIndexBuffer( pIndices, nIndexCount, m_nIndexOffset );
  2689. break;
  2690. case MATERIAL_POINTS:
  2691. Assert(0); // Shouldn't get here (this primtype is unindexed)
  2692. break;
  2693. case MATERIAL_SUBD_QUADS_EXTRA:
  2694. case MATERIAL_SUBD_QUADS_REG:
  2695. default:
  2696. GenerateSequentialIndexBuffer( pIndices, nIndexCount, m_nIndexOffset );
  2697. break;
  2698. }
  2699. AdvanceIndices( nIndexCount );
  2700. }
  2701. //-----------------------------------------------------------------------------
  2702. //
  2703. // Helper class used to define meshes
  2704. //
  2705. //-----------------------------------------------------------------------------
  2706. //class CMeshBuilder : private MeshDesc_t
  2707. // hack fixme
  2708. class CMeshBuilder : public MeshDesc_t
  2709. {
  2710. public:
  2711. CMeshBuilder();
  2712. ~CMeshBuilder() { Assert(!m_pMesh); } // if this fires you did a Begin() without an End()
  2713. operator CIndexBuilder&() { return m_IndexBuilder; }
  2714. // This must be called before Begin, if a vertex buffer with a compressed format is to be used
  2715. void SetCompressionType( VertexCompressionType_t compressionType );
  2716. // Locks the vertex buffer
  2717. // (*cannot* use the Index() call below)
  2718. void Begin( IMesh *pMesh, MaterialPrimitiveType_t type, int numPrimitives );
  2719. // Locks the vertex buffer, can specify arbitrary index lists
  2720. // (must use the Index() call below)
  2721. void Begin( IMesh *pMesh, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount, int *nFirstVertex );
  2722. void Begin( IMesh *pMesh, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount, MeshBuffersAllocationSettings_t *pSettings = 0 );
  2723. // forward compat
  2724. void Begin( IVertexBuffer *pVertexBuffer, MaterialPrimitiveType_t type, int numPrimitives );
  2725. void Begin( IVertexBuffer *pVertexBuffer, IIndexBuffer *pIndexBuffer, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount, int *nFirstVertex );
  2726. void Begin( IVertexBuffer *pVertexBuffer, IIndexBuffer *pIndexBuffer, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount );
  2727. // Use this when you're done writing
  2728. // Set bDraw to true to call m_pMesh->Draw automatically.
  2729. void End( bool bSpewData = false, bool bDraw = false );
  2730. // Locks the vertex buffer to modify existing data
  2731. // Passing nVertexCount == -1 says to lock all the vertices for modification.
  2732. // Pass 0 for nIndexCount to not lock the index buffer.
  2733. void BeginModify( IMesh *pMesh, int nFirstVertex = 0, int nVertexCount = -1, int nFirstIndex = 0, int nIndexCount = 0 );
  2734. void EndModify( bool bSpewData = false );
  2735. // A helper method since this seems to be done a whole bunch.
  2736. void DrawQuad( IMesh* pMesh, const float *v1, const float *v2,
  2737. const float *v3, const float *v4, unsigned char const *pColor, bool wireframe = false );
  2738. // returns the number of indices and vertices
  2739. int VertexCount() const;
  2740. int IndexCount() const;
  2741. // Resets the mesh builder so it points to the start of everything again
  2742. void Reset();
  2743. // Returns the size of the vertex
  2744. int VertexSize() { return m_ActualVertexSize; }
  2745. // returns the data size of a given texture coordinate
  2746. int TextureCoordinateSize( int nTexCoordNumber ) { return m_VertexSize_TexCoord[ nTexCoordNumber ]; }
  2747. // Returns the base vertex memory pointer
  2748. void* BaseVertexData();
  2749. // Returns the base index memory pointer
  2750. unsigned short* BaseIndexData();
  2751. // Selects the nth Vertex and Index
  2752. void SelectVertex( int idx );
  2753. void SelectIndex( int idx );
  2754. // Given an index, point to the associated vertex
  2755. void SelectVertexFromIndex( int idx );
  2756. // Advances the current vertex and index by one
  2757. void AdvanceVertex();
  2758. template<int nFlags, int nNumTexCoords> void AdvanceVertexF();
  2759. void AdvanceVertices( int nVerts );
  2760. template<int nFlags, int nNumTexCoords> void AdvanceVerticesF(int nVerts);
  2761. void AdvanceIndex();
  2762. void AdvanceIndices( int nIndices );
  2763. int GetCurrentVertex() const;
  2764. int GetCurrentIndex() const;
  2765. int GetIndexOffset() const;
  2766. // Data retrieval...
  2767. const float *Position() const;
  2768. const float *Normal() const;
  2769. unsigned int Color() const;
  2770. unsigned char *Specular() const;
  2771. const float *TexCoord( int stage ) const;
  2772. const float *TangentS() const;
  2773. const float *TangentT() const;
  2774. const float *BoneWeight() const;
  2775. float Wrinkle() const;
  2776. int NumBoneWeights() const;
  2777. #ifndef NEW_SKINNING
  2778. unsigned char *BoneMatrix() const;
  2779. #else
  2780. float *BoneMatrix() const;
  2781. #endif
  2782. unsigned short const *Index() const;
  2783. unsigned short * IndexBuffer_InterlockedAdd(int numberOfIndices);
  2784. // position setting
  2785. void Position3f( float x, float y, float z );
  2786. void Position3f( int nVertexOffset, float x, float y, float z );
  2787. void Position3f( const fltx4 &f4Position );
  2788. void Position3fv( const float *v );
  2789. void Position3fv( int nVertexOffset, const float *v );
  2790. // normal setting
  2791. void Normal3f( float nx, float ny, float nz );
  2792. void Normal3f( const fltx4 &f4Normal );
  2793. void Normal3fv( const float *n );
  2794. void NormalDelta3fv( const float *n );
  2795. void NormalDelta3f( float nx, float ny, float nz );
  2796. // normal setting (templatized for code which needs to support compressed vertices)
  2797. template <VertexCompressionType_t T> void CompressedNormal3f( float nx, float ny, float nz );
  2798. template <VertexCompressionType_t T> void CompressedNormal3fv( const float *n );
  2799. // color setting
  2800. void Color3f( float r, float g, float b );
  2801. void Color3fv( const float *rgb );
  2802. void Color4f( float r, float g, float b, float a );
  2803. void Color4fv( const float *rgba );
  2804. // Faster versions of color
  2805. void Color3ub( unsigned char r, unsigned char g, unsigned char b );
  2806. void Color3ubv( unsigned char const* rgb );
  2807. void Color4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a );
  2808. void Color4ub( int nVertexoffset, unsigned char r, unsigned char g, unsigned char b, unsigned char a );
  2809. void Color4ubv( unsigned char const* rgba );
  2810. void Color4Packed( int packedColor );
  2811. int PackColor4( unsigned char r, unsigned char g, unsigned char b, unsigned char a );
  2812. // specular color setting
  2813. void Specular3f( float r, float g, float b );
  2814. void Specular3fv( const float *rgb );
  2815. void Specular4f( float r, float g, float b, float a );
  2816. void Specular4fv( const float *rgba );
  2817. // Faster version of specular
  2818. void Specular3ub( unsigned char r, unsigned char g, unsigned char b );
  2819. void Specular3ubv( unsigned char const *c );
  2820. void Specular4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a );
  2821. void Specular4ubv( unsigned char const *c );
  2822. // texture coordinate setting
  2823. void TexCoord1f( int stage, float s );
  2824. void TexCoord2f( int stage, float s, float t );
  2825. void TexCoord2f( int nVertexOffset, int stage, float s, float t );
  2826. void TexCoord2fv( int stage, const float *st );
  2827. void TexCoord3f( int stage, float s, float t, float u );
  2828. void TexCoord3f( int nVertexOffset, int stage, float s, float t, float u );
  2829. void TexCoord3fv( int stage, const float *stu );
  2830. void TexCoord3fv( int nVertexOffset, int stage, const float *stu );
  2831. void TexCoord4f( int stage, float s, float t, float u, float w );
  2832. void TexCoord4f( int nStage, const fltx4 &f4stuv );
  2833. void TexCoord4fv( int stage, const float *stuv );
  2834. void TexCoord4f( int nVertexOffset, int stage, float s, float t, float u, float w );
  2835. void TexCoord4fv( int nVertexOffset, int stage, const float *stuv );
  2836. void TexCoordSubRect2f( int stage, float s, float t, float offsetS, float offsetT, float scaleS, float scaleT );
  2837. void TexCoordSubRect2fv( int stage, const float *st, const float *offset, const float *scale );
  2838. // tangent space
  2839. void TangentS3f( float sx, float sy, float sz );
  2840. void TangentS3fv( const float *s );
  2841. void TangentT3f( float tx, float ty, float tz );
  2842. void TangentT3fv( const float *t );
  2843. // Wrinkle
  2844. void Wrinkle1f( float flWrinkle );
  2845. // bone weights
  2846. void BoneWeight( int idx, float weight );
  2847. void BoneWeights2( float weight1, float weight2 );
  2848. // bone weights (templatized for code which needs to support compressed vertices)
  2849. template <VertexCompressionType_t T> void CompressedBoneWeight3fv( const float * pWeights );
  2850. // bone matrix index
  2851. void BoneMatrix( int idx, int matrixIndex );
  2852. void BoneMatrices4( int matrixIdx0, int matrixIdx1, int matrixIdx2, int matrixIdx3 );
  2853. // Generic per-vertex data
  2854. void UserData( const float *pData );
  2855. // Generic per-vertex data (templatized for code which needs to support compressed vertices)
  2856. template <VertexCompressionType_t T> void CompressedUserData( const float* pData );
  2857. // Used to define the indices (only used if you aren't using primitives)
  2858. void Index( unsigned short index );
  2859. // NOTE: Use this one to get write combining! Much faster than the other version of FastIndex
  2860. // Fast Index! No need to call advance index, and no random access allowed
  2861. void FastIndex2( unsigned short nIndex1, unsigned short nIndex2 );
  2862. void FastIndex2( int nIndexOffset, unsigned short nIndex1, unsigned short nIndex2 );
  2863. // Fast Index! No need to call advance index, and no random access allowed
  2864. void FastIndex( unsigned short index );
  2865. void FastQuad( int index );
  2866. void FastIndex( int nIndexOffset, unsigned short index );
  2867. void FastQuad( int nIndexOffset, int index );
  2868. // Fast Vertex! No need to call advance vertex, and no random access allowed.
  2869. // WARNING - these are low level functions that are intended only for use
  2870. // in the software vertex skinner.
  2871. void FastVertex( const ModelVertexDX8_t &vertex );
  2872. void FastVertexSSE( const ModelVertexDX8_t &vertex );
  2873. void FastQuadVertexSSE( const QuadTessVertex_t &vertex );
  2874. // Add number of verts and current vert since FastVertexxx routines do not update.
  2875. void FastAdvanceNVertices(int n);
  2876. #if defined( _X360 )
  2877. void VertexDX8ToX360( const ModelVertexDX8_t &vertex );
  2878. #endif
  2879. // this low level function gets you a pointer to the vertex output data. It is dangerous - any
  2880. // caller using it must understand the vertex layout that it is building. It is for optimized
  2881. // meshbuilding loops like particle drawing that use special shaders. After writing to the output
  2882. // data, you shuodl call FastAdvanceNVertices
  2883. FORCEINLINE void *GetVertexDataPtr( int nWhatSizeIThinkItIs )
  2884. {
  2885. if ( m_VertexBuilder.m_VertexSize_Position != nWhatSizeIThinkItIs )
  2886. return NULL;
  2887. return m_VertexBuilder.m_pCurrPosition;
  2888. }
  2889. private:
  2890. // Computes number of verts and indices
  2891. void ComputeNumVertsAndIndices( int *pMaxVertices, int *pMaxIndices,
  2892. MaterialPrimitiveType_t type, int nPrimitiveCount );
  2893. int IndicesFromVertices( MaterialPrimitiveType_t type, int nVertexCount );
  2894. // The mesh we're modifying
  2895. IMesh *m_pMesh;
  2896. MaterialPrimitiveType_t m_Type;
  2897. // Generate indices?
  2898. bool m_bGenerateIndices;
  2899. CIndexBuilder m_IndexBuilder;
  2900. CVertexBuilder m_VertexBuilder;
  2901. };
  2902. //-----------------------------------------------------------------------------
  2903. // Forward compat
  2904. //-----------------------------------------------------------------------------
  2905. inline void CMeshBuilder::Begin( IVertexBuffer* pVertexBuffer, MaterialPrimitiveType_t type, int numPrimitives )
  2906. {
  2907. Assert( 0 );
  2908. // Begin( pVertexBuffer->GetMesh(), type, numPrimitives );
  2909. }
  2910. inline void CMeshBuilder::Begin( IVertexBuffer* pVertexBuffer, IIndexBuffer *pIndexBuffer, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount, int *nFirstVertex )
  2911. {
  2912. Assert( 0 );
  2913. // Begin( pVertexBuffer->GetMesh(), type, nVertexCount, nIndexCount, nFirstVertex );
  2914. }
  2915. inline void CMeshBuilder::Begin( IVertexBuffer* pVertexBuffer, IIndexBuffer *pIndexBuffer, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount )
  2916. {
  2917. Assert( 0 );
  2918. // Begin( pVertexBuffer->GetMesh(), type, nVertexCount, nIndexCount );
  2919. }
  2920. //-----------------------------------------------------------------------------
  2921. // Constructor
  2922. //-----------------------------------------------------------------------------
  2923. inline CMeshBuilder::CMeshBuilder() : m_pMesh(0), m_bGenerateIndices(false)
  2924. {
  2925. VertexDesc_t::m_nOffset = 0;
  2926. VertexDesc_t::m_CompressionType = VERTEX_COMPRESSION_NONE;
  2927. }
  2928. //-----------------------------------------------------------------------------
  2929. // Computes the number of verts and indices based on primitive type and count
  2930. //-----------------------------------------------------------------------------
  2931. inline void CMeshBuilder::ComputeNumVertsAndIndices( int *pMaxVertices, int *pMaxIndices,
  2932. MaterialPrimitiveType_t type, int nPrimitiveCount )
  2933. {
  2934. switch(type)
  2935. {
  2936. case MATERIAL_POINTS:
  2937. *pMaxVertices = *pMaxIndices = nPrimitiveCount;
  2938. break;
  2939. case MATERIAL_LINES:
  2940. *pMaxVertices = *pMaxIndices = nPrimitiveCount * 2;
  2941. break;
  2942. case MATERIAL_LINE_STRIP:
  2943. *pMaxVertices = nPrimitiveCount + 1;
  2944. *pMaxIndices = nPrimitiveCount * 2;
  2945. break;
  2946. case MATERIAL_LINE_LOOP:
  2947. *pMaxVertices = nPrimitiveCount;
  2948. *pMaxIndices = nPrimitiveCount * 2;
  2949. break;
  2950. case MATERIAL_TRIANGLES:
  2951. *pMaxVertices = *pMaxIndices = nPrimitiveCount * 3;
  2952. break;
  2953. case MATERIAL_TRIANGLE_STRIP:
  2954. *pMaxVertices = *pMaxIndices = nPrimitiveCount + 2;
  2955. break;
  2956. case MATERIAL_QUADS:
  2957. *pMaxVertices = nPrimitiveCount * 4;
  2958. *pMaxIndices = nPrimitiveCount * 6;
  2959. break;
  2960. case MATERIAL_INSTANCED_QUADS:
  2961. *pMaxVertices = nPrimitiveCount;
  2962. *pMaxIndices = 0; // This primtype is unindexed
  2963. break;
  2964. case MATERIAL_POLYGON:
  2965. *pMaxVertices = nPrimitiveCount;
  2966. *pMaxIndices = (nPrimitiveCount - 2) * 3;
  2967. break;
  2968. default:
  2969. Assert(0);
  2970. }
  2971. // FIXME: need to get this from meshdx8.cpp, or move it to somewhere common
  2972. Assert( *pMaxVertices <= 32768 );
  2973. Assert( *pMaxIndices <= 32768 );
  2974. }
  2975. inline int CMeshBuilder::IndicesFromVertices( MaterialPrimitiveType_t type, int nVertexCount )
  2976. {
  2977. switch( type )
  2978. {
  2979. case MATERIAL_QUADS:
  2980. Assert( (nVertexCount & 0x3) == 0 );
  2981. return (nVertexCount * 6) / 4;
  2982. case MATERIAL_INSTANCED_QUADS:
  2983. // This primtype is unindexed
  2984. return 0;
  2985. case MATERIAL_POLYGON:
  2986. Assert( nVertexCount >= 3 );
  2987. return (nVertexCount - 2) * 3;
  2988. case MATERIAL_LINE_STRIP:
  2989. Assert( nVertexCount >= 2 );
  2990. return (nVertexCount - 1) * 2;
  2991. case MATERIAL_LINE_LOOP:
  2992. Assert( nVertexCount >= 3 );
  2993. return nVertexCount * 2;
  2994. default:
  2995. return nVertexCount;
  2996. }
  2997. }
  2998. //-----------------------------------------------------------------------------
  2999. // Specify the type of vertex compression that this CMeshBuilder will perform
  3000. //-----------------------------------------------------------------------------
  3001. inline void CMeshBuilder::SetCompressionType( VertexCompressionType_t vertexCompressionType )
  3002. {
  3003. m_CompressionType = vertexCompressionType;
  3004. m_VertexBuilder.SetCompressionType( vertexCompressionType );
  3005. }
  3006. //-----------------------------------------------------------------------------
  3007. // Begins modifying the mesh
  3008. //-----------------------------------------------------------------------------
  3009. inline void CMeshBuilder::Begin( IMesh *pMesh, MaterialPrimitiveType_t type, int numPrimitives )
  3010. {
  3011. Assert( pMesh && (!m_pMesh) );
  3012. Assert( type != MATERIAL_HETEROGENOUS );
  3013. m_pMesh = pMesh;
  3014. m_bGenerateIndices = true;
  3015. m_Type = type;
  3016. int nMaxVertexCount = 0, nMaxIndexCount = 0;
  3017. ComputeNumVertsAndIndices( &nMaxVertexCount, &nMaxIndexCount, type, numPrimitives );
  3018. switch( type )
  3019. {
  3020. case MATERIAL_INSTANCED_QUADS:
  3021. m_pMesh->SetPrimitiveType( MATERIAL_INSTANCED_QUADS );
  3022. break;
  3023. case MATERIAL_QUADS:
  3024. case MATERIAL_POLYGON:
  3025. m_pMesh->SetPrimitiveType( MATERIAL_TRIANGLES );
  3026. break;
  3027. case MATERIAL_LINE_STRIP:
  3028. case MATERIAL_LINE_LOOP:
  3029. m_pMesh->SetPrimitiveType( MATERIAL_LINES );
  3030. break;
  3031. default:
  3032. m_pMesh->SetPrimitiveType( type );
  3033. }
  3034. // Lock the mesh
  3035. m_pMesh->LockMesh( nMaxVertexCount, nMaxIndexCount, *this );
  3036. m_IndexBuilder.AttachBegin( pMesh, nMaxIndexCount, *this );
  3037. m_VertexBuilder.AttachBegin( pMesh, nMaxVertexCount, *this );
  3038. // Point to the start of the index and vertex buffers
  3039. Reset();
  3040. }
  3041. inline void CMeshBuilder::Begin( IMesh *pMesh, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount, int *nFirstVertex )
  3042. {
  3043. Begin( pMesh, type, nVertexCount, nIndexCount );
  3044. *nFirstVertex = m_VertexBuilder.m_nFirstVertex * m_VertexBuilder.VertexSize();
  3045. }
  3046. inline void CMeshBuilder::Begin( IMesh* pMesh, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount, MeshBuffersAllocationSettings_t *pMeshSettings )
  3047. {
  3048. Assert( pMesh && (!m_pMesh) );
  3049. // NOTE: We can't specify the indices when we use quads, polygons, or
  3050. // linestrips; they aren't actually directly supported by
  3051. // the material system
  3052. Assert( (type != MATERIAL_QUADS) && (type != MATERIAL_INSTANCED_QUADS) && (type != MATERIAL_POLYGON) &&
  3053. (type != MATERIAL_LINE_STRIP) && (type != MATERIAL_LINE_LOOP));
  3054. // Dx8 doesn't support indexed points...
  3055. Assert( type != MATERIAL_POINTS );
  3056. m_pMesh = pMesh;
  3057. m_bGenerateIndices = false;
  3058. m_Type = type;
  3059. // Set the primitive type
  3060. m_pMesh->SetPrimitiveType( type );
  3061. // Lock the vertex and index buffer
  3062. m_pMesh->LockMesh( nVertexCount, nIndexCount, *this, pMeshSettings );
  3063. m_IndexBuilder.AttachBegin( pMesh, nIndexCount, *this );
  3064. m_VertexBuilder.AttachBegin( pMesh, nVertexCount, *this );
  3065. // Point to the start of the buffers..
  3066. Reset();
  3067. }
  3068. //-----------------------------------------------------------------------------
  3069. // Use this when you're done modifying the mesh
  3070. //-----------------------------------------------------------------------------
  3071. inline void CMeshBuilder::End( bool bSpewData, bool bDraw )
  3072. {
  3073. if ( m_bGenerateIndices )
  3074. {
  3075. int nIndexCount = IndicesFromVertices( m_Type, m_VertexBuilder.VertexCount() );
  3076. m_IndexBuilder.GenerateIndices( m_Type, nIndexCount );
  3077. }
  3078. if ( bSpewData )
  3079. {
  3080. m_pMesh->Spew( m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this );
  3081. }
  3082. #ifdef _DEBUG
  3083. m_pMesh->ValidateData( m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this );
  3084. #endif
  3085. // Unlock our buffers
  3086. m_pMesh->UnlockMesh( m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this );
  3087. m_IndexBuilder.AttachEnd();
  3088. m_VertexBuilder.AttachEnd();
  3089. if ( bDraw )
  3090. {
  3091. m_pMesh->Draw();
  3092. }
  3093. m_pMesh = 0;
  3094. #ifdef _DEBUG
  3095. memset( (MeshDesc_t*)this, 0, sizeof(MeshDesc_t) );
  3096. #endif
  3097. }
  3098. //-----------------------------------------------------------------------------
  3099. // Locks the vertex buffer to modify existing data
  3100. //-----------------------------------------------------------------------------
  3101. inline void CMeshBuilder::BeginModify( IMesh* pMesh, int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount )
  3102. {
  3103. Assert( pMesh && (!m_pMesh) );
  3104. if (nVertexCount < 0)
  3105. {
  3106. nVertexCount = pMesh->VertexCount();
  3107. }
  3108. m_pMesh = pMesh;
  3109. m_bGenerateIndices = false;
  3110. // Locks mesh for modifying
  3111. pMesh->ModifyBeginEx( false, nFirstVertex, nVertexCount, nFirstIndex, nIndexCount, *this );
  3112. m_IndexBuilder.AttachBeginModify( pMesh, nFirstIndex, nIndexCount, *this );
  3113. m_VertexBuilder.AttachBeginModify( pMesh, nFirstVertex, nVertexCount, *this );
  3114. // Point to the start of the buffers..
  3115. Reset();
  3116. }
  3117. inline void CMeshBuilder::EndModify( bool bSpewData )
  3118. {
  3119. Assert( m_pMesh );
  3120. if (bSpewData)
  3121. {
  3122. m_pMesh->Spew( m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this );
  3123. }
  3124. #ifdef _DEBUG
  3125. m_pMesh->ValidateData( m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this );
  3126. #endif
  3127. // Unlocks mesh
  3128. m_pMesh->ModifyEnd( *this );
  3129. m_pMesh = 0;
  3130. m_IndexBuilder.AttachEndModify();
  3131. m_VertexBuilder.AttachEndModify();
  3132. #ifdef _DEBUG
  3133. // Null out our pointers...
  3134. memset( (MeshDesc_t*)this, 0, sizeof(MeshDesc_t) );
  3135. #endif
  3136. }
  3137. //-----------------------------------------------------------------------------
  3138. // Resets the mesh builder so it points to the start of everything again
  3139. //-----------------------------------------------------------------------------
  3140. inline void CMeshBuilder::Reset()
  3141. {
  3142. m_IndexBuilder.Reset();
  3143. m_VertexBuilder.Reset();
  3144. }
  3145. //-----------------------------------------------------------------------------
  3146. // Selects the current Vertex and Index
  3147. //-----------------------------------------------------------------------------
  3148. FORCEINLINE void CMeshBuilder::SelectVertex( int nIndex )
  3149. {
  3150. m_VertexBuilder.SelectVertex( nIndex );
  3151. }
  3152. inline void CMeshBuilder::SelectVertexFromIndex( int idx )
  3153. {
  3154. // NOTE: This index is expected to be relative
  3155. int vertIdx = idx - m_nFirstVertex;
  3156. SelectVertex( vertIdx );
  3157. }
  3158. FORCEINLINE void CMeshBuilder::SelectIndex( int idx )
  3159. {
  3160. m_IndexBuilder.SelectIndex( idx );
  3161. }
  3162. //-----------------------------------------------------------------------------
  3163. // Advances the current vertex and index by one
  3164. //-----------------------------------------------------------------------------
  3165. template<int nFlags, int nNumTexCoords> FORCEINLINE void CMeshBuilder::AdvanceVertexF()
  3166. {
  3167. m_VertexBuilder.AdvanceVertexF<nFlags, nNumTexCoords>();
  3168. }
  3169. FORCEINLINE void CMeshBuilder::AdvanceVertex()
  3170. {
  3171. m_VertexBuilder.AdvanceVertex();
  3172. }
  3173. template <int nFlags, int nNumCoords> FORCEINLINE void CMeshBuilder::AdvanceVerticesF( int nVertexCount )
  3174. {
  3175. m_VertexBuilder.AdvanceVerticesF<nFlags, nNumCoords>( nVertexCount );
  3176. }
  3177. FORCEINLINE void CMeshBuilder::AdvanceVertices( int nVertexCount )
  3178. {
  3179. m_VertexBuilder.AdvanceVertices( nVertexCount );
  3180. }
  3181. FORCEINLINE void CMeshBuilder::AdvanceIndex()
  3182. {
  3183. m_IndexBuilder.AdvanceIndex();
  3184. }
  3185. FORCEINLINE void CMeshBuilder::AdvanceIndices( int nIndices )
  3186. {
  3187. m_IndexBuilder.AdvanceIndices( nIndices );
  3188. }
  3189. FORCEINLINE int CMeshBuilder::GetCurrentVertex() const
  3190. {
  3191. return m_VertexBuilder.GetCurrentVertex();
  3192. }
  3193. FORCEINLINE int CMeshBuilder::GetCurrentIndex() const
  3194. {
  3195. return m_IndexBuilder.GetCurrentIndex();
  3196. }
  3197. FORCEINLINE int CMeshBuilder::GetIndexOffset() const
  3198. {
  3199. return m_IndexBuilder.GetIndexOffset();
  3200. }
  3201. //-----------------------------------------------------------------------------
  3202. // A helper method since this seems to be done a whole bunch.
  3203. //-----------------------------------------------------------------------------
  3204. inline void CMeshBuilder::DrawQuad( IMesh* pMesh, const float* v1, const float* v2,
  3205. const float* v3, const float* v4, unsigned char const* pColor, bool wireframe )
  3206. {
  3207. if (!wireframe)
  3208. {
  3209. Begin( pMesh, MATERIAL_TRIANGLE_STRIP, 2 );
  3210. Position3fv (v1);
  3211. Color4ubv( pColor );
  3212. AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>();
  3213. Position3fv (v2);
  3214. Color4ubv( pColor );
  3215. AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>();
  3216. Position3fv (v4);
  3217. Color4ubv( pColor );
  3218. AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>();
  3219. Position3fv (v3);
  3220. Color4ubv( pColor );
  3221. AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>();
  3222. }
  3223. else
  3224. {
  3225. Begin( pMesh, MATERIAL_LINE_LOOP, 4 );
  3226. Position3fv (v1);
  3227. Color4ubv( pColor );
  3228. AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>();
  3229. Position3fv (v2);
  3230. Color4ubv( pColor );
  3231. AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>();
  3232. Position3fv (v3);
  3233. Color4ubv( pColor );
  3234. AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>();
  3235. Position3fv (v4);
  3236. Color4ubv( pColor );
  3237. AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>();
  3238. }
  3239. End();
  3240. pMesh->Draw();
  3241. }
  3242. //-----------------------------------------------------------------------------
  3243. // returns the number of indices and vertices
  3244. //-----------------------------------------------------------------------------
  3245. FORCEINLINE int CMeshBuilder::VertexCount() const
  3246. {
  3247. return m_VertexBuilder.VertexCount();
  3248. }
  3249. FORCEINLINE int CMeshBuilder::IndexCount() const
  3250. {
  3251. return m_IndexBuilder.IndexCount();
  3252. }
  3253. //-----------------------------------------------------------------------------
  3254. // Returns the base vertex memory pointer
  3255. //-----------------------------------------------------------------------------
  3256. FORCEINLINE void* CMeshBuilder::BaseVertexData()
  3257. {
  3258. return m_VertexBuilder.BaseVertexData();
  3259. }
  3260. //-----------------------------------------------------------------------------
  3261. // Returns the base index memory pointer
  3262. //-----------------------------------------------------------------------------
  3263. FORCEINLINE unsigned short* CMeshBuilder::BaseIndexData()
  3264. {
  3265. return m_IndexBuilder.BaseIndexData();
  3266. }
  3267. //-----------------------------------------------------------------------------
  3268. // Data retrieval...
  3269. //-----------------------------------------------------------------------------
  3270. FORCEINLINE const float* CMeshBuilder::Position() const
  3271. {
  3272. return m_VertexBuilder.Position();
  3273. }
  3274. FORCEINLINE const float* CMeshBuilder::Normal() const
  3275. {
  3276. return m_VertexBuilder.Normal();
  3277. }
  3278. FORCEINLINE unsigned int CMeshBuilder::Color() const
  3279. {
  3280. return m_VertexBuilder.Color();
  3281. }
  3282. FORCEINLINE unsigned char *CMeshBuilder::Specular() const
  3283. {
  3284. return m_VertexBuilder.Specular();
  3285. }
  3286. FORCEINLINE const float* CMeshBuilder::TexCoord( int nStage ) const
  3287. {
  3288. return m_VertexBuilder.TexCoord( nStage );
  3289. }
  3290. FORCEINLINE const float* CMeshBuilder::TangentS() const
  3291. {
  3292. return m_VertexBuilder.TangentS();
  3293. }
  3294. FORCEINLINE const float* CMeshBuilder::TangentT() const
  3295. {
  3296. return m_VertexBuilder.TangentT();
  3297. }
  3298. FORCEINLINE float CMeshBuilder::Wrinkle() const
  3299. {
  3300. return m_VertexBuilder.Wrinkle();
  3301. }
  3302. FORCEINLINE const float* CMeshBuilder::BoneWeight() const
  3303. {
  3304. return m_VertexBuilder.BoneWeight();
  3305. }
  3306. FORCEINLINE int CMeshBuilder::NumBoneWeights() const
  3307. {
  3308. return m_VertexBuilder.NumBoneWeights();
  3309. }
  3310. FORCEINLINE unsigned short const* CMeshBuilder::Index() const
  3311. {
  3312. return m_IndexBuilder.Index();
  3313. }
  3314. FORCEINLINE unsigned short * CMeshBuilder::IndexBuffer_InterlockedAdd(int numberOfIndices)
  3315. {
  3316. return m_IndexBuilder.IndexBuffer_InterlockedAdd(numberOfIndices);
  3317. }
  3318. //-----------------------------------------------------------------------------
  3319. // Index
  3320. //-----------------------------------------------------------------------------
  3321. FORCEINLINE void CMeshBuilder::Index( unsigned short idx )
  3322. {
  3323. m_IndexBuilder.Index( idx );
  3324. }
  3325. //-----------------------------------------------------------------------------
  3326. // Fast Index! No need to call advance index
  3327. //-----------------------------------------------------------------------------
  3328. FORCEINLINE void CMeshBuilder::FastIndex( unsigned short idx )
  3329. {
  3330. m_IndexBuilder.FastIndex( idx );
  3331. }
  3332. FORCEINLINE void CMeshBuilder::FastIndex( int nIndexOffset, unsigned short index )
  3333. {
  3334. m_IndexBuilder.FastIndex( nIndexOffset, index );
  3335. }
  3336. // NOTE: Use this one to get write combining! Much faster than the other version of FastIndex
  3337. // Fast Index! No need to call advance index, and no random access allowed
  3338. FORCEINLINE void CMeshBuilder::FastIndex2( unsigned short nIndex1, unsigned short nIndex2 )
  3339. {
  3340. m_IndexBuilder.FastIndex2( nIndex1, nIndex2 );
  3341. }
  3342. FORCEINLINE void CMeshBuilder::FastIndex2( int nIndexOffset, unsigned short nIndex1, unsigned short nIndex2 )
  3343. {
  3344. m_IndexBuilder.FastIndex2( nIndexOffset, nIndex1, nIndex2 );
  3345. }
  3346. FORCEINLINE void CMeshBuilder::FastQuad( int nIndex )
  3347. {
  3348. m_IndexBuilder.FastQuad( nIndex );
  3349. }
  3350. FORCEINLINE void CMeshBuilder::FastQuad( int nIndexOffset, int nIndex )
  3351. {
  3352. m_IndexBuilder.FastQuad( nIndexOffset, nIndex );
  3353. }
  3354. //-----------------------------------------------------------------------------
  3355. // For use with the FastVertex methods, advances the current vertex by N
  3356. //-----------------------------------------------------------------------------
  3357. FORCEINLINE void CMeshBuilder::FastAdvanceNVertices( int nVertexCount )
  3358. {
  3359. m_VertexBuilder.FastAdvanceNVertices( nVertexCount );
  3360. }
  3361. //-----------------------------------------------------------------------------
  3362. // Fast Vertex! No need to call advance vertex, and no random access allowed
  3363. //-----------------------------------------------------------------------------
  3364. FORCEINLINE void CMeshBuilder::FastVertex( const ModelVertexDX8_t &vertex )
  3365. {
  3366. m_VertexBuilder.FastVertex( vertex );
  3367. }
  3368. FORCEINLINE void CMeshBuilder::FastVertexSSE( const ModelVertexDX8_t &vertex )
  3369. {
  3370. m_VertexBuilder.FastVertexSSE( vertex );
  3371. }
  3372. FORCEINLINE void CMeshBuilder::FastQuadVertexSSE( const QuadTessVertex_t &vertex )
  3373. {
  3374. m_VertexBuilder.FastQuadVertexSSE( vertex );
  3375. }
  3376. //-----------------------------------------------------------------------------
  3377. // Copies a vertex into the x360 format
  3378. //-----------------------------------------------------------------------------
  3379. #if defined( _X360 )
  3380. inline void CMeshBuilder::VertexDX8ToX360( const ModelVertexDX8_t &vertex )
  3381. {
  3382. m_VertexBuilder.VertexDX8ToX360( vertex );
  3383. }
  3384. #endif
  3385. //-----------------------------------------------------------------------------
  3386. // Vertex field setting methods
  3387. //-----------------------------------------------------------------------------
  3388. FORCEINLINE void CMeshBuilder::Position3f( float x, float y, float z )
  3389. {
  3390. m_VertexBuilder.Position3f( x, y, z );
  3391. }
  3392. FORCEINLINE void CMeshBuilder::Position3f( int nVertexOffset, float x, float y, float z )
  3393. {
  3394. m_VertexBuilder.Position3f( nVertexOffset, x, y, z );
  3395. }
  3396. FORCEINLINE void CMeshBuilder::Position3f( const fltx4 &f4Position )
  3397. {
  3398. m_VertexBuilder.Position3f( f4Position );
  3399. }
  3400. FORCEINLINE void CMeshBuilder::Position3fv( const float *v )
  3401. {
  3402. m_VertexBuilder.Position3fv( v );
  3403. }
  3404. FORCEINLINE void CMeshBuilder::Position3fv( int nVertexOffset, const float *v )
  3405. {
  3406. m_VertexBuilder.Position3fv( nVertexOffset, v );
  3407. }
  3408. FORCEINLINE void CMeshBuilder::Normal3f( float nx, float ny, float nz )
  3409. {
  3410. m_VertexBuilder.Normal3f( nx, ny, nz );
  3411. }
  3412. FORCEINLINE void CMeshBuilder::Normal3f( const fltx4 &f4Normal )
  3413. {
  3414. m_VertexBuilder.Normal3f( f4Normal );
  3415. }
  3416. FORCEINLINE void CMeshBuilder::Normal3fv( const float *n )
  3417. {
  3418. m_VertexBuilder.Normal3fv( n );
  3419. }
  3420. FORCEINLINE void CMeshBuilder::NormalDelta3f( float nx, float ny, float nz )
  3421. {
  3422. m_VertexBuilder.NormalDelta3f( nx, ny, nz );
  3423. }
  3424. FORCEINLINE void CMeshBuilder::NormalDelta3fv( const float *n )
  3425. {
  3426. m_VertexBuilder.NormalDelta3fv( n );
  3427. }
  3428. FORCEINLINE void CMeshBuilder::Color3f( float r, float g, float b )
  3429. {
  3430. m_VertexBuilder.Color3f( r, g, b );
  3431. }
  3432. FORCEINLINE void CMeshBuilder::Color3fv( const float *rgb )
  3433. {
  3434. m_VertexBuilder.Color3fv( rgb );
  3435. }
  3436. FORCEINLINE void CMeshBuilder::Color4f( float r, float g, float b, float a )
  3437. {
  3438. m_VertexBuilder.Color4f( r, g ,b, a );
  3439. }
  3440. FORCEINLINE void CMeshBuilder::Color4fv( const float *rgba )
  3441. {
  3442. m_VertexBuilder.Color4fv( rgba );
  3443. }
  3444. FORCEINLINE void CMeshBuilder::Color3ub( unsigned char r, unsigned char g, unsigned char b )
  3445. {
  3446. m_VertexBuilder.Color3ub( r, g, b );
  3447. }
  3448. FORCEINLINE void CMeshBuilder::Color3ubv( unsigned char const* rgb )
  3449. {
  3450. m_VertexBuilder.Color3ubv( rgb );
  3451. }
  3452. FORCEINLINE void CMeshBuilder::Color4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a )
  3453. {
  3454. m_VertexBuilder.Color4ub( r, g, b, a );
  3455. }
  3456. FORCEINLINE void CMeshBuilder::Color4ub( int nVertexOffset, unsigned char r, unsigned char g, unsigned char b, unsigned char a )
  3457. {
  3458. m_VertexBuilder.Color4ub( nVertexOffset, r, g, b, a );
  3459. }
  3460. FORCEINLINE void CMeshBuilder::Color4ubv( unsigned char const* rgba )
  3461. {
  3462. m_VertexBuilder.Color4ubv( rgba );
  3463. }
  3464. FORCEINLINE void CMeshBuilder::Color4Packed( int packedColor )
  3465. {
  3466. m_VertexBuilder.Color4Packed(packedColor);
  3467. }
  3468. FORCEINLINE int CMeshBuilder::PackColor4( unsigned char r, unsigned char g, unsigned char b, unsigned char a )
  3469. {
  3470. return m_VertexBuilder.PackColor4(r,g,b,a);
  3471. }
  3472. FORCEINLINE void CMeshBuilder::Specular3f( float r, float g, float b )
  3473. {
  3474. m_VertexBuilder.Specular3f( r, g, b );
  3475. }
  3476. FORCEINLINE void CMeshBuilder::Specular3fv( const float *rgb )
  3477. {
  3478. m_VertexBuilder.Specular3fv( rgb );
  3479. }
  3480. FORCEINLINE void CMeshBuilder::Specular4f( float r, float g, float b, float a )
  3481. {
  3482. m_VertexBuilder.Specular4f( r, g, b, a );
  3483. }
  3484. FORCEINLINE void CMeshBuilder::Specular4fv( const float *rgba )
  3485. {
  3486. m_VertexBuilder.Specular4fv( rgba );
  3487. }
  3488. FORCEINLINE void CMeshBuilder::Specular3ub( unsigned char r, unsigned char g, unsigned char b )
  3489. {
  3490. m_VertexBuilder.Specular3ub( r, g, b );
  3491. }
  3492. FORCEINLINE void CMeshBuilder::Specular3ubv( unsigned char const *c )
  3493. {
  3494. m_VertexBuilder.Specular3ubv( c );
  3495. }
  3496. FORCEINLINE void CMeshBuilder::Specular4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a )
  3497. {
  3498. m_VertexBuilder.Specular4ub( r, g, b, a );
  3499. }
  3500. FORCEINLINE void CMeshBuilder::Specular4ubv( unsigned char const *c )
  3501. {
  3502. m_VertexBuilder.Specular4ubv( c );
  3503. }
  3504. FORCEINLINE void CMeshBuilder::TexCoord1f( int nStage, float s )
  3505. {
  3506. m_VertexBuilder.TexCoord1f( nStage, s );
  3507. }
  3508. FORCEINLINE void CMeshBuilder::TexCoord2f( int nStage, float s, float t )
  3509. {
  3510. m_VertexBuilder.TexCoord2f( nStage, s, t );
  3511. }
  3512. FORCEINLINE void CMeshBuilder::TexCoord2f( int nVertexOffset, int nStage, float s, float t )
  3513. {
  3514. m_VertexBuilder.TexCoord2f( nVertexOffset, nStage, s, t );
  3515. }
  3516. FORCEINLINE void CMeshBuilder::TexCoord2fv( int nStage, const float *st )
  3517. {
  3518. m_VertexBuilder.TexCoord2fv( nStage, st );
  3519. }
  3520. FORCEINLINE void CMeshBuilder::TexCoord3f( int nStage, float s, float t, float u )
  3521. {
  3522. m_VertexBuilder.TexCoord3f( nStage, s, t, u );
  3523. }
  3524. FORCEINLINE void CMeshBuilder::TexCoord3f( int nVertexOffset, int nStage, float s, float t, float u )
  3525. {
  3526. m_VertexBuilder.TexCoord3f( nVertexOffset, nStage, s, t, u );
  3527. }
  3528. FORCEINLINE void CMeshBuilder::TexCoord3fv( int nStage, const float *stu )
  3529. {
  3530. m_VertexBuilder.TexCoord3fv( nStage, stu );
  3531. }
  3532. FORCEINLINE void CMeshBuilder::TexCoord3fv( int nVertexOffset, int nStage, const float *stu )
  3533. {
  3534. m_VertexBuilder.TexCoord3fv( nVertexOffset, nStage, stu );
  3535. }
  3536. FORCEINLINE void CMeshBuilder::TexCoord4f( int nStage, float s, float t, float u, float v )
  3537. {
  3538. m_VertexBuilder.TexCoord4f( nStage, s, t, u, v );
  3539. }
  3540. FORCEINLINE void CMeshBuilder::TexCoord4f( int nStage, const fltx4 &f4stuv )
  3541. {
  3542. m_VertexBuilder.TexCoord4f( nStage, f4stuv );
  3543. }
  3544. FORCEINLINE void CMeshBuilder::TexCoord4fv( int nStage, const float *stuv )
  3545. {
  3546. m_VertexBuilder.TexCoord4fv( nStage, stuv );
  3547. }
  3548. FORCEINLINE void CMeshBuilder::TexCoord4f( int nVertexOffset, int nStage, float s, float t, float u, float v )
  3549. {
  3550. m_VertexBuilder.TexCoord4f( nVertexOffset, nStage, s, t, u, v );
  3551. }
  3552. FORCEINLINE void CMeshBuilder::TexCoord4fv( int nVertexOffset, int nStage, const float *stuv )
  3553. {
  3554. m_VertexBuilder.TexCoord4fv( nVertexOffset, nStage, stuv );
  3555. }
  3556. FORCEINLINE void CMeshBuilder::TexCoordSubRect2f( int nStage, float s, float t, float offsetS, float offsetT, float scaleS, float scaleT )
  3557. {
  3558. m_VertexBuilder.TexCoordSubRect2f( nStage, s, t, offsetS, offsetT, scaleS, scaleT );
  3559. }
  3560. FORCEINLINE void CMeshBuilder::TexCoordSubRect2fv( int nStage, const float *st, const float *offset, const float *scale )
  3561. {
  3562. m_VertexBuilder.TexCoordSubRect2fv( nStage, st, offset, scale );
  3563. }
  3564. FORCEINLINE void CMeshBuilder::TangentS3f( float sx, float sy, float sz )
  3565. {
  3566. m_VertexBuilder.TangentS3f( sx, sy, sz );
  3567. }
  3568. FORCEINLINE void CMeshBuilder::TangentS3fv( const float* s )
  3569. {
  3570. m_VertexBuilder.TangentS3fv( s );
  3571. }
  3572. FORCEINLINE void CMeshBuilder::TangentT3f( float tx, float ty, float tz )
  3573. {
  3574. m_VertexBuilder.TangentT3f( tx, ty, tz );
  3575. }
  3576. FORCEINLINE void CMeshBuilder::TangentT3fv( const float* t )
  3577. {
  3578. m_VertexBuilder.TangentT3fv( t );
  3579. }
  3580. FORCEINLINE void CMeshBuilder::Wrinkle1f( float flWrinkle )
  3581. {
  3582. m_VertexBuilder.Wrinkle1f( flWrinkle );
  3583. }
  3584. FORCEINLINE void CMeshBuilder::BoneWeight( int nIndex, float flWeight )
  3585. {
  3586. m_VertexBuilder.BoneWeight( nIndex, flWeight );
  3587. }
  3588. FORCEINLINE void CMeshBuilder::BoneWeights2( float weight1, float weight2 )
  3589. {
  3590. m_VertexBuilder.BoneWeights2( weight1, weight2 );
  3591. }
  3592. template <VertexCompressionType_t T> FORCEINLINE void CMeshBuilder::CompressedBoneWeight3fv( const float * pWeights )
  3593. {
  3594. m_VertexBuilder.CompressedBoneWeight3fv<T>( pWeights );
  3595. }
  3596. FORCEINLINE void CMeshBuilder::BoneMatrix( int nIndex, int nMatrixIdx )
  3597. {
  3598. m_VertexBuilder.BoneMatrix( nIndex, nMatrixIdx );
  3599. }
  3600. FORCEINLINE void CMeshBuilder::BoneMatrices4( int matrixIdx0, int matrixIdx1, int matrixIdx2, int matrixIdx3 )
  3601. {
  3602. m_VertexBuilder.BoneMatrices4( matrixIdx0, matrixIdx1, matrixIdx2, matrixIdx3 );
  3603. }
  3604. FORCEINLINE void CMeshBuilder::UserData( const float* pData )
  3605. {
  3606. m_VertexBuilder.UserData( pData );
  3607. }
  3608. template <VertexCompressionType_t T> FORCEINLINE void CMeshBuilder::CompressedUserData( const float* pData )
  3609. {
  3610. m_VertexBuilder.CompressedUserData<T>( pData );
  3611. }
  3612. //-----------------------------------------------------------------------------
  3613. // Templatized vertex field setting methods which support compression
  3614. //-----------------------------------------------------------------------------
  3615. template <VertexCompressionType_t T> FORCEINLINE void CMeshBuilder::CompressedNormal3f( float nx, float ny, float nz )
  3616. {
  3617. m_VertexBuilder.CompressedNormal3f<T>( nx, ny, nz );
  3618. }
  3619. template <VertexCompressionType_t T> FORCEINLINE void CMeshBuilder::CompressedNormal3fv( const float *n )
  3620. {
  3621. m_VertexBuilder.CompressedNormal3fv<T>( n );
  3622. }
  3623. #endif // IMESH_H