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

389 lines
12 KiB

  1. //===== Copyright � 1996-2005, 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. struct VertexStreamSpec_t;
  16. //-----------------------------------------------------------------------------
  17. // Base vertex buffer
  18. //-----------------------------------------------------------------------------
  19. abstract_class CVertexBufferBase : public IVertexBuffer
  20. {
  21. // Methods of IVertexBuffer
  22. public:
  23. virtual void Spew( int nVertexCount, const VertexDesc_t &desc );
  24. virtual void ValidateData( int nVertexCount, const VertexDesc_t& desc );
  25. public:
  26. // constructor, destructor
  27. CVertexBufferBase( const char *pBudgetGroupName );
  28. virtual ~CVertexBufferBase();
  29. // Displays the vertex format
  30. static void PrintVertexFormat( VertexFormat_t vertexFormat );
  31. // Used to construct vertex data
  32. static void ComputeVertexDescription( unsigned char *pBuffer, VertexFormat_t vertexFormat, VertexDesc_t &desc );
  33. // Returns the vertex format size
  34. static int VertexFormatSize( VertexFormat_t vertexFormat );
  35. protected:
  36. const char *m_pBudgetGroupName;
  37. };
  38. //-----------------------------------------------------------------------------
  39. // Base index buffer
  40. //-----------------------------------------------------------------------------
  41. abstract_class CIndexBufferBase : public IIndexBuffer
  42. {
  43. // Methods of IIndexBuffer
  44. public:
  45. virtual void Spew( int nIndexCount, const IndexDesc_t &desc );
  46. virtual void ValidateData( int nIndexCount, const IndexDesc_t& desc );
  47. virtual IMesh* GetMesh() { return NULL; }
  48. // Other public methods
  49. public:
  50. // constructor, destructor
  51. CIndexBufferBase( const char *pBudgetGroupName );
  52. virtual ~CIndexBufferBase() {}
  53. protected:
  54. const char *m_pBudgetGroupName;
  55. };
  56. //-----------------------------------------------------------------------------
  57. // Base mesh
  58. //-----------------------------------------------------------------------------
  59. class CMeshBase : public IMesh
  60. {
  61. // Methods of IMesh
  62. public:
  63. // Other public methods that need to be overridden
  64. public:
  65. // Begins a pass
  66. virtual void BeginPass( ) = 0;
  67. // Draws a single pass of the mesh
  68. virtual void RenderPass( const unsigned char *pInstanceCommandBuffer ) = 0;
  69. // DrawPrims
  70. virtual void DrawPrims( const unsigned char *pInstanceCommandBuffer ) = 0;
  71. // Does it have a color mesh?
  72. virtual bool HasColorMesh() const = 0;
  73. // Does it have a flex mesh?
  74. virtual bool HasFlexMesh() const = 0;
  75. // Is it using a vertex ID?
  76. virtual bool IsUsingVertexID() const = 0;
  77. // Is it using tessellation for higher-order surfaces?
  78. #if ENABLE_TESSELLATION
  79. virtual TessellationMode_t GetTessellationType() const = 0;
  80. #else
  81. TessellationMode_t GetTessellationType() const { return TESSELLATION_MODE_DISABLED; }
  82. #endif
  83. // Are vertex data streams specified in a custom manner?
  84. virtual VertexStreamSpec_t *GetVertexStreamSpec() const = 0;
  85. virtual IMesh *GetMesh() { return this; }
  86. virtual void * AccessRawHardwareDataStream( uint8 nRawStreamIndex, uint32 numBytes, uint32 uiFlags, void *pvContext ) { return NULL; }
  87. virtual ICachedPerFrameMeshData *GetCachedPerFrameMeshData() { return NULL; }
  88. virtual void ReconstructFromCachedPerFrameMeshData( ICachedPerFrameMeshData *pData ) {}
  89. public:
  90. // constructor, destructor
  91. CMeshBase();
  92. virtual ~CMeshBase();
  93. };
  94. //-----------------------------------------------------------------------------
  95. // Utility method for VertexDesc_t (don't want to expose it in public, in imesh.h)
  96. // We've split this into two versions, one for computing size-only, and the standard
  97. // version which computes field offsets and sizes.
  98. // The code would be cleaner if we split it into two functions, but for now we'll keep
  99. // all of the if( !bSizeOnly ) for easier maintenance if we need to change any of the fields.
  100. //-----------------------------------------------------------------------------
  101. template< bool bSizeOnly >
  102. inline int ComputeVertexDesc( unsigned char * pBuffer, VertexFormat_t vertexFormat, VertexDesc_t & desc )
  103. {
  104. int i;
  105. int *pVertexSizesToSet[64];
  106. int nVertexSizesToSet = 0;
  107. static ALIGN32 ModelVertexDX8_t temp[4];
  108. float *dummyData = (float*)&temp; // should be larger than any CMeshBuilder command can set.
  109. // Determine which vertex compression type this format specifies (affects element sizes/decls):
  110. VertexCompressionType_t compression = CompressionType( vertexFormat );
  111. int nNumBoneWeights = NumBoneWeights( vertexFormat );
  112. if ( !bSizeOnly )
  113. {
  114. desc.m_CompressionType = compression;
  115. desc.m_NumBoneWeights = nNumBoneWeights;
  116. }
  117. // We use fvf instead of flags here because we may pad out the fvf
  118. // vertex structure to optimize performance
  119. int offset = 0;
  120. // NOTE: At the moment, we assume that if you specify wrinkle, you also specify position
  121. Assert( ( ( vertexFormat & VERTEX_WRINKLE ) == 0 ) || ( ( vertexFormat & VERTEX_POSITION ) != 0 ) );
  122. if ( vertexFormat & VERTEX_POSITION )
  123. {
  124. if ( !bSizeOnly )
  125. {
  126. // UNDONE: compress position+wrinkle to SHORT4N, and roll the scale into the transform matrices
  127. desc.m_pPosition = reinterpret_cast<float*>(pBuffer);
  128. pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_Position;
  129. }
  130. VertexElement_t posElement = (vertexFormat & VERTEX_FORMAT_PAD_POS_NORM ) != 0 ? VERTEX_ELEMENT_POSITION4D : VERTEX_ELEMENT_POSITION;
  131. offset += GetVertexElementSize( posElement, compression );
  132. if ( vertexFormat & VERTEX_WRINKLE )
  133. {
  134. if ( !bSizeOnly )
  135. {
  136. desc.m_pWrinkle = reinterpret_cast<float*>( pBuffer + offset );
  137. pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_Wrinkle;
  138. }
  139. offset += GetVertexElementSize( VERTEX_ELEMENT_WRINKLE, compression );
  140. }
  141. else if ( !bSizeOnly )
  142. {
  143. desc.m_pWrinkle = dummyData;
  144. desc.m_VertexSize_Wrinkle = 0;
  145. }
  146. }
  147. else if ( !bSizeOnly )
  148. {
  149. desc.m_pPosition = dummyData;
  150. desc.m_VertexSize_Position = 0;
  151. desc.m_pWrinkle = dummyData;
  152. desc.m_VertexSize_Wrinkle = 0;
  153. }
  154. // Bone weights/matrix indices
  155. Assert( ( nNumBoneWeights == 2 ) || ( nNumBoneWeights == 0 ) );
  156. // We assume that if you have any indices/weights, you have exactly two of them
  157. Assert( ( ( nNumBoneWeights == 2 ) && ( ( vertexFormat & VERTEX_BONE_INDEX ) != 0 ) ) ||
  158. ( ( nNumBoneWeights == 0 ) && ( ( vertexFormat & VERTEX_BONE_INDEX ) == 0 ) ) );
  159. if ( ( vertexFormat & VERTEX_BONE_INDEX ) != 0 )
  160. {
  161. if ( nNumBoneWeights > 0 )
  162. {
  163. // Always exactly two weights
  164. Assert( nNumBoneWeights == 2 );
  165. if ( !bSizeOnly )
  166. {
  167. desc.m_pBoneWeight = reinterpret_cast<float*>(pBuffer + offset);
  168. pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_BoneWeight;
  169. }
  170. offset += GetVertexElementSize( VERTEX_ELEMENT_BONEWEIGHTS2, compression );
  171. }
  172. else if ( !bSizeOnly )
  173. {
  174. desc.m_pBoneWeight = dummyData;
  175. desc.m_VertexSize_BoneWeight = 0;
  176. }
  177. if ( !bSizeOnly )
  178. {
  179. desc.m_pBoneMatrixIndex = pBuffer + offset;
  180. pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_BoneMatrixIndex;
  181. }
  182. offset += GetVertexElementSize( VERTEX_ELEMENT_BONEINDEX, compression );
  183. }
  184. else if ( !bSizeOnly )
  185. {
  186. desc.m_pBoneWeight = dummyData;
  187. desc.m_VertexSize_BoneWeight = 0;
  188. desc.m_pBoneMatrixIndex = (unsigned char*)dummyData;
  189. desc.m_VertexSize_BoneMatrixIndex = 0;
  190. }
  191. if ( vertexFormat & VERTEX_NORMAL )
  192. {
  193. if ( !bSizeOnly )
  194. {
  195. desc.m_pNormal = reinterpret_cast<float*>(pBuffer + offset);
  196. pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_Normal;
  197. }
  198. // See PackNormal_[SHORT2|UBYTE4|HEND3N] in mathlib.h for the compression algorithm
  199. VertexElement_t normalElement = (vertexFormat & VERTEX_FORMAT_PAD_POS_NORM ) != 0 ? VERTEX_ELEMENT_NORMAL4D : VERTEX_ELEMENT_NORMAL;
  200. offset += GetVertexElementSize( normalElement, compression );
  201. }
  202. else if ( !bSizeOnly )
  203. {
  204. desc.m_pNormal = dummyData;
  205. desc.m_VertexSize_Normal = 0;
  206. }
  207. if ( vertexFormat & VERTEX_COLOR )
  208. {
  209. if ( !bSizeOnly )
  210. {
  211. desc.m_pColor = pBuffer + offset;
  212. pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_Color;
  213. }
  214. offset += GetVertexElementSize( VERTEX_ELEMENT_COLOR, compression );
  215. }
  216. else if ( !bSizeOnly )
  217. {
  218. desc.m_pColor = (unsigned char*)dummyData;
  219. desc.m_VertexSize_Color = 0;
  220. }
  221. if ( vertexFormat & VERTEX_SPECULAR )
  222. {
  223. if ( !bSizeOnly )
  224. {
  225. desc.m_pSpecular = pBuffer + offset;
  226. pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_Specular;
  227. }
  228. offset += GetVertexElementSize( VERTEX_ELEMENT_SPECULAR, compression );
  229. }
  230. else if ( !bSizeOnly )
  231. {
  232. desc.m_pSpecular = (unsigned char*)dummyData;
  233. desc.m_VertexSize_Specular = 0;
  234. }
  235. // Set up texture coordinates
  236. static const VertexElement_t texCoordElements[4] = { VERTEX_ELEMENT_TEXCOORD1D_0, VERTEX_ELEMENT_TEXCOORD2D_0, VERTEX_ELEMENT_TEXCOORD3D_0, VERTEX_ELEMENT_TEXCOORD4D_0 };
  237. for ( i = 0; i < VERTEX_MAX_TEXTURE_COORDINATES; ++i )
  238. {
  239. // FIXME: compress texcoords to SHORT2N/SHORT4N, with a scale rolled into the texture transform
  240. int nSize = TexCoordSize( i, vertexFormat );
  241. if ( nSize != 0 )
  242. {
  243. if ( !bSizeOnly )
  244. {
  245. desc.m_pTexCoord[i] = reinterpret_cast<float*>(pBuffer + offset);
  246. pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_TexCoord[i];
  247. }
  248. VertexElement_t texCoordElement = (VertexElement_t)( texCoordElements[ nSize - 1 ] + i );
  249. offset += GetVertexElementSize( texCoordElement, compression );
  250. }
  251. else if ( !bSizeOnly )
  252. {
  253. desc.m_pTexCoord[i] = dummyData;
  254. desc.m_VertexSize_TexCoord[i] = 0;
  255. }
  256. }
  257. // Binormal + tangent...
  258. // Note we have to put these at the end so the vertex is FVF + stuff at end
  259. if ( vertexFormat & VERTEX_TANGENT_S )
  260. {
  261. // UNDONE: use normal compression here (use mem_dumpvballocs to see if this uses much memory)
  262. if ( !bSizeOnly )
  263. {
  264. desc.m_pTangentS = reinterpret_cast<float*>(pBuffer + offset);
  265. pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_TangentS;
  266. }
  267. offset += GetVertexElementSize( VERTEX_ELEMENT_TANGENT_S, compression );
  268. }
  269. else if ( !bSizeOnly )
  270. {
  271. desc.m_pTangentS = dummyData;
  272. desc.m_VertexSize_TangentS = 0;
  273. }
  274. if ( vertexFormat & VERTEX_TANGENT_T )
  275. {
  276. // UNDONE: use normal compression here (use mem_dumpvballocs to see if this uses much memory)
  277. if ( !bSizeOnly )
  278. {
  279. desc.m_pTangentT = reinterpret_cast<float*>(pBuffer + offset);
  280. pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_TangentT;
  281. }
  282. offset += GetVertexElementSize( VERTEX_ELEMENT_TANGENT_T, compression );
  283. }
  284. else if ( !bSizeOnly )
  285. {
  286. desc.m_pTangentT = dummyData;
  287. desc.m_VertexSize_TangentT = 0;
  288. }
  289. // User data..
  290. int userDataSize = UserDataSize( vertexFormat );
  291. if ( userDataSize > 0 )
  292. {
  293. if ( !bSizeOnly )
  294. {
  295. desc.m_pUserData = reinterpret_cast<float*>(pBuffer + offset);
  296. pVertexSizesToSet[nVertexSizesToSet++] = &desc.m_VertexSize_UserData;
  297. }
  298. VertexElement_t userDataElement = (VertexElement_t)( VERTEX_ELEMENT_USERDATA1 + ( userDataSize - 1 ) );
  299. // See PackNormal_[SHORT2|UBYTE4|HEND3N] in mathlib.h for the compression algorithm
  300. offset += GetVertexElementSize( userDataElement, compression );
  301. }
  302. else if ( !bSizeOnly )
  303. {
  304. desc.m_pUserData = dummyData;
  305. desc.m_VertexSize_UserData = 0;
  306. }
  307. // We always use vertex sizes which are half-cache aligned (16 bytes)
  308. // x360 compressed vertexes are not compatible with forced alignments
  309. bool bCacheAlign = ( vertexFormat & VERTEX_FORMAT_USE_EXACT_FORMAT ) == 0;
  310. if ( bCacheAlign && ( offset > 16 ) && IsPC() )
  311. {
  312. offset = (offset + 0xF) & (~0xF);
  313. }
  314. desc.m_ActualVertexSize = offset;
  315. if ( !bSizeOnly )
  316. {
  317. // Now set the m_VertexSize for all the members that were actually valid.
  318. Assert( nVertexSizesToSet < sizeof(pVertexSizesToSet)/sizeof(pVertexSizesToSet[0]) );
  319. for ( int iElement=0; iElement < nVertexSizesToSet; iElement++ )
  320. {
  321. *pVertexSizesToSet[iElement] = offset;
  322. }
  323. }
  324. return offset;
  325. }
  326. #endif // MESHBASE_H