Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4049 lines
126 KiB

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