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.

309 lines
9.6 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #ifndef MESHBASE_H
  9. #define MESHBASE_H
  10. #ifdef _WIN32
  11. #pragma once
  12. #endif
  13. #include "materialsystem/imesh.h"
  14. #include "materialsystem/imaterial.h"
  15. //-----------------------------------------------------------------------------
  16. // Base vertex buffer
  17. //-----------------------------------------------------------------------------
  18. abstract_class CVertexBufferBase : public IVertexBuffer
  19. {
  20. // Methods of IVertexBuffer
  21. public:
  22. virtual void Spew( int nVertexCount, const VertexDesc_t &desc );
  23. virtual void ValidateData( int nVertexCount, const VertexDesc_t& desc );
  24. public:
  25. // constructor, destructor
  26. CVertexBufferBase( const char *pBudgetGroupName );
  27. virtual ~CVertexBufferBase();
  28. // Displays the vertex format
  29. static void PrintVertexFormat( VertexFormat_t vertexFormat );
  30. // Used to construct vertex data
  31. static void ComputeVertexDescription( unsigned char *pBuffer, VertexFormat_t vertexFormat, VertexDesc_t &desc );
  32. // Returns the vertex format size
  33. static int VertexFormatSize( VertexFormat_t vertexFormat );
  34. protected:
  35. const char *m_pBudgetGroupName;
  36. };
  37. //-----------------------------------------------------------------------------
  38. // Base index buffer
  39. //-----------------------------------------------------------------------------
  40. abstract_class CIndexBufferBase : public IIndexBuffer
  41. {
  42. // Methods of IIndexBuffer
  43. public:
  44. virtual void Spew( int nIndexCount, const IndexDesc_t &desc );
  45. virtual void ValidateData( int nIndexCount, const IndexDesc_t& desc );
  46. // Other public methods
  47. public:
  48. // constructor, destructor
  49. CIndexBufferBase( const char *pBudgetGroupName );
  50. virtual ~CIndexBufferBase() {}
  51. protected:
  52. const char *m_pBudgetGroupName;
  53. };
  54. //-----------------------------------------------------------------------------
  55. // Base mesh
  56. //-----------------------------------------------------------------------------
  57. class CMeshBase : public IMesh
  58. {
  59. // Methods of IMesh
  60. public:
  61. // Other public methods that need to be overridden
  62. public:
  63. // Begins a pass
  64. virtual void BeginPass( ) = 0;
  65. // Draws a single pass of the mesh
  66. virtual void RenderPass() = 0;
  67. // Does it have a color mesh?
  68. virtual bool HasColorMesh() const = 0;
  69. // Am I using morph data?
  70. virtual bool IsUsingMorphData() const = 0;
  71. virtual bool HasFlexMesh() const = 0;
  72. virtual IMesh *GetMesh() { return this; }
  73. public:
  74. // constructor, destructor
  75. CMeshBase();
  76. virtual ~CMeshBase();
  77. };
  78. //-----------------------------------------------------------------------------
  79. // Utility method for VertexDesc_t (don't want to expose it in public, in imesh.h)
  80. //-----------------------------------------------------------------------------
  81. inline void ComputeVertexDesc( unsigned char * pBuffer, VertexFormat_t vertexFormat, VertexDesc_t & desc )
  82. {
  83. int i;
  84. int *pVertexSizesToSet[64];
  85. int nVertexSizesToSet = 0;
  86. static ALIGN32 ModelVertexDX8_t temp[4];
  87. float *dummyData = (float*)&temp; // should be larger than any CMeshBuilder command can set.
  88. // Determine which vertex compression type this format specifies (affects element sizes/decls):
  89. VertexCompressionType_t compression = CompressionType( vertexFormat );
  90. desc.m_CompressionType = compression;
  91. // We use fvf instead of flags here because we may pad out the fvf
  92. // vertex structure to optimize performance
  93. int offset = 0;
  94. // NOTE: At the moment, we assume that if you specify wrinkle, you also specify position
  95. Assert( ( ( vertexFormat & VERTEX_WRINKLE ) == 0 ) || ( ( vertexFormat & VERTEX_POSITION ) != 0 ) );
  96. if ( vertexFormat & VERTEX_POSITION )
  97. {
  98. // UNDONE: compress position+wrinkle to SHORT4N, and roll the scale into the transform matrices
  99. desc.m_pPosition = reinterpret_cast<float*>(pBuffer);
  100. offset += GetVertexElementSize( VERTEX_ELEMENT_POSITION, compression );
  101. pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_Position;
  102. if ( vertexFormat & VERTEX_WRINKLE )
  103. {
  104. desc.m_pWrinkle = reinterpret_cast<float*>( pBuffer + offset );
  105. offset += GetVertexElementSize( VERTEX_ELEMENT_WRINKLE, compression );
  106. pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_Wrinkle;
  107. }
  108. else
  109. {
  110. desc.m_pWrinkle = dummyData;
  111. desc.m_VertexSize_Wrinkle = 0;
  112. }
  113. }
  114. else
  115. {
  116. desc.m_pPosition = dummyData;
  117. desc.m_VertexSize_Position = 0;
  118. desc.m_pWrinkle = dummyData;
  119. desc.m_VertexSize_Wrinkle = 0;
  120. }
  121. // Bone weights/matrix indices
  122. desc.m_NumBoneWeights = NumBoneWeights( vertexFormat );
  123. Assert( ( desc.m_NumBoneWeights == 2 ) || ( desc.m_NumBoneWeights == 0 ) );
  124. // We assume that if you have any indices/weights, you have exactly two of them
  125. Assert( ( ( desc.m_NumBoneWeights == 2 ) && ( ( vertexFormat & VERTEX_BONE_INDEX ) != 0 ) ) ||
  126. ( ( desc.m_NumBoneWeights == 0 ) && ( ( vertexFormat & VERTEX_BONE_INDEX ) == 0 ) ) );
  127. if ( ( vertexFormat & VERTEX_BONE_INDEX ) != 0 )
  128. {
  129. if ( desc.m_NumBoneWeights > 0 )
  130. {
  131. Assert( desc.m_NumBoneWeights == 2 );
  132. // Always exactly two weights
  133. desc.m_pBoneWeight = reinterpret_cast<float*>(pBuffer + offset);
  134. offset += GetVertexElementSize( VERTEX_ELEMENT_BONEWEIGHTS2, compression );
  135. pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_BoneWeight;
  136. }
  137. else
  138. {
  139. desc.m_pBoneWeight = dummyData;
  140. desc.m_VertexSize_BoneWeight = 0;
  141. }
  142. desc.m_pBoneMatrixIndex = pBuffer + offset;
  143. offset += GetVertexElementSize( VERTEX_ELEMENT_BONEINDEX, compression );
  144. pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_BoneMatrixIndex;
  145. }
  146. else
  147. {
  148. desc.m_pBoneWeight = dummyData;
  149. desc.m_VertexSize_BoneWeight = 0;
  150. desc.m_pBoneMatrixIndex = (unsigned char*)dummyData;
  151. desc.m_VertexSize_BoneMatrixIndex = 0;
  152. }
  153. if ( vertexFormat & VERTEX_NORMAL )
  154. {
  155. desc.m_pNormal = reinterpret_cast<float*>(pBuffer + offset);
  156. // See PackNormal_[SHORT2|UBYTE4|HEND3N] in mathlib.h for the compression algorithm
  157. offset += GetVertexElementSize( VERTEX_ELEMENT_NORMAL, compression );
  158. pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_Normal;
  159. }
  160. else
  161. {
  162. desc.m_pNormal = dummyData;
  163. desc.m_VertexSize_Normal = 0;
  164. }
  165. if ( vertexFormat & VERTEX_COLOR )
  166. {
  167. desc.m_pColor = pBuffer + offset;
  168. offset += GetVertexElementSize( VERTEX_ELEMENT_COLOR, compression );
  169. pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_Color;
  170. }
  171. else
  172. {
  173. desc.m_pColor = (unsigned char*)dummyData;
  174. desc.m_VertexSize_Color = 0;
  175. }
  176. if ( vertexFormat & VERTEX_SPECULAR )
  177. {
  178. desc.m_pSpecular = pBuffer + offset;
  179. offset += GetVertexElementSize( VERTEX_ELEMENT_SPECULAR, compression );
  180. pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_Specular;
  181. }
  182. else
  183. {
  184. desc.m_pSpecular = (unsigned char*)dummyData;
  185. desc.m_VertexSize_Specular = 0;
  186. }
  187. // Set up texture coordinates
  188. for ( i = 0; i < VERTEX_MAX_TEXTURE_COORDINATES; ++i )
  189. {
  190. // FIXME: compress texcoords to SHORT2N/SHORT4N, with a scale rolled into the texture transform
  191. VertexElement_t texCoordElements[4] = { VERTEX_ELEMENT_TEXCOORD1D_0, VERTEX_ELEMENT_TEXCOORD2D_0, VERTEX_ELEMENT_TEXCOORD3D_0, VERTEX_ELEMENT_TEXCOORD4D_0 };
  192. int nSize = TexCoordSize( i, vertexFormat );
  193. if ( nSize != 0 )
  194. {
  195. desc.m_pTexCoord[i] = reinterpret_cast<float*>(pBuffer + offset);
  196. VertexElement_t texCoordElement = (VertexElement_t)( texCoordElements[ nSize - 1 ] + i );
  197. offset += GetVertexElementSize( texCoordElement, compression );
  198. pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_TexCoord[i];
  199. }
  200. else
  201. {
  202. desc.m_pTexCoord[i] = dummyData;
  203. desc.m_VertexSize_TexCoord[i] = 0;
  204. }
  205. }
  206. // Binormal + tangent...
  207. // Note we have to put these at the end so the vertex is FVF + stuff at end
  208. if ( vertexFormat & VERTEX_TANGENT_S )
  209. {
  210. // UNDONE: use normal compression here (use mem_dumpvballocs to see if this uses much memory)
  211. desc.m_pTangentS = reinterpret_cast<float*>(pBuffer + offset);
  212. offset += GetVertexElementSize( VERTEX_ELEMENT_TANGENT_S, compression );
  213. pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_TangentS;
  214. }
  215. else
  216. {
  217. desc.m_pTangentS = dummyData;
  218. desc.m_VertexSize_TangentS = 0;
  219. }
  220. if ( vertexFormat & VERTEX_TANGENT_T )
  221. {
  222. // UNDONE: use normal compression here (use mem_dumpvballocs to see if this uses much memory)
  223. desc.m_pTangentT = reinterpret_cast<float*>(pBuffer + offset);
  224. offset += GetVertexElementSize( VERTEX_ELEMENT_TANGENT_T, compression );
  225. pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_TangentT;
  226. }
  227. else
  228. {
  229. desc.m_pTangentT = dummyData;
  230. desc.m_VertexSize_TangentT = 0;
  231. }
  232. // User data..
  233. int userDataSize = UserDataSize( vertexFormat );
  234. if ( userDataSize > 0 )
  235. {
  236. desc.m_pUserData = reinterpret_cast<float*>(pBuffer + offset);
  237. VertexElement_t userDataElement = (VertexElement_t)( VERTEX_ELEMENT_USERDATA1 + ( userDataSize - 1 ) );
  238. // See PackNormal_[SHORT2|UBYTE4|HEND3N] in mathlib.h for the compression algorithm
  239. offset += GetVertexElementSize( userDataElement, compression );
  240. pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_UserData;
  241. }
  242. else
  243. {
  244. desc.m_pUserData = dummyData;
  245. desc.m_VertexSize_UserData = 0;
  246. }
  247. // We always use vertex sizes which are half-cache aligned (16 bytes)
  248. // x360 compressed vertexes are not compatible with forced alignments
  249. bool bCacheAlign = ( vertexFormat & VERTEX_FORMAT_USE_EXACT_FORMAT ) == 0;
  250. if ( bCacheAlign && ( offset > 16 ) && IsPC() )
  251. {
  252. offset = (offset + 0xF) & (~0xF);
  253. }
  254. desc.m_ActualVertexSize = offset;
  255. // Now set the m_VertexSize for all the members that were actually valid.
  256. Assert( nVertexSizesToSet < sizeof(pVertexSizesToSet)/sizeof(pVertexSizesToSet[0]) );
  257. for ( int iElement=0; iElement < nVertexSizesToSet; iElement++ )
  258. {
  259. *pVertexSizesToSet[iElement] = offset;
  260. }
  261. }
  262. #endif // MESHBASE_H