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.

576 lines
19 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #undef PROTECTED_THINGS_ENABLE
  9. #include "vertexdecl.h" // this includes <windows.h> inside the dx headers
  10. #define PROTECTED_THINGS_ENABLE
  11. #include "materialsystem/imaterialsystemhardwareconfig.h"
  12. #include "shaderapidx8_global.h"
  13. #include "tier0/dbg.h"
  14. #include "utlrbtree.h"
  15. #include "recording.h"
  16. #include "tier1/strtools.h"
  17. #include "tier0/vprof.h"
  18. #include "materialsystem/imesh.h"
  19. #include "shaderdevicedx8.h"
  20. // NOTE: This has to be the last file included!
  21. #include "tier0/memdbgon.h"
  22. //-----------------------------------------------------------------------------
  23. // Computes the DX8 vertex specification
  24. //-----------------------------------------------------------------------------
  25. static const char *DeclTypeToString( BYTE type )
  26. {
  27. switch( type )
  28. {
  29. case D3DDECLTYPE_FLOAT1:
  30. return "D3DDECLTYPE_FLOAT1";
  31. case D3DDECLTYPE_FLOAT2:
  32. return "D3DDECLTYPE_FLOAT2";
  33. case D3DDECLTYPE_FLOAT3:
  34. return "D3DDECLTYPE_FLOAT3";
  35. case D3DDECLTYPE_FLOAT4:
  36. return "D3DDECLTYPE_FLOAT4";
  37. case D3DDECLTYPE_D3DCOLOR:
  38. return "D3DDECLTYPE_D3DCOLOR";
  39. case D3DDECLTYPE_UBYTE4:
  40. return "D3DDECLTYPE_UBYTE4";
  41. case D3DDECLTYPE_SHORT2:
  42. return "D3DDECLTYPE_SHORT2";
  43. case D3DDECLTYPE_SHORT4:
  44. return "D3DDECLTYPE_SHORT4";
  45. case D3DDECLTYPE_UBYTE4N:
  46. return "D3DDECLTYPE_UBYTE4N";
  47. case D3DDECLTYPE_SHORT2N:
  48. return "D3DDECLTYPE_SHORT2N";
  49. case D3DDECLTYPE_SHORT4N:
  50. return "D3DDECLTYPE_SHORT4N";
  51. case D3DDECLTYPE_USHORT2N:
  52. return "D3DDECLTYPE_USHORT2N";
  53. case D3DDECLTYPE_USHORT4N:
  54. return "D3DDECLTYPE_USHORT4N";
  55. case D3DDECLTYPE_UDEC3:
  56. return "D3DDECLTYPE_UDEC3";
  57. case D3DDECLTYPE_DEC3N:
  58. return "D3DDECLTYPE_DEC3N";
  59. case D3DDECLTYPE_FLOAT16_2:
  60. return "D3DDECLTYPE_FLOAT16_2";
  61. case D3DDECLTYPE_FLOAT16_4:
  62. return "D3DDECLTYPE_FLOAT16_4";
  63. default:
  64. Assert( 0 );
  65. return "ERROR";
  66. }
  67. }
  68. static const char *DeclMethodToString( BYTE method )
  69. {
  70. switch( method )
  71. {
  72. case D3DDECLMETHOD_DEFAULT:
  73. return "D3DDECLMETHOD_DEFAULT";
  74. case D3DDECLMETHOD_PARTIALU:
  75. return "D3DDECLMETHOD_PARTIALU";
  76. case D3DDECLMETHOD_PARTIALV:
  77. return "D3DDECLMETHOD_PARTIALV";
  78. case D3DDECLMETHOD_CROSSUV:
  79. return "D3DDECLMETHOD_CROSSUV";
  80. case D3DDECLMETHOD_UV:
  81. return "D3DDECLMETHOD_UV";
  82. case D3DDECLMETHOD_LOOKUP:
  83. return "D3DDECLMETHOD_LOOKUP";
  84. case D3DDECLMETHOD_LOOKUPPRESAMPLED:
  85. return "D3DDECLMETHOD_LOOKUPPRESAMPLED";
  86. default:
  87. Assert( 0 );
  88. return "ERROR";
  89. }
  90. }
  91. static const char *DeclUsageToString( BYTE usage )
  92. {
  93. switch( usage )
  94. {
  95. case D3DDECLUSAGE_POSITION:
  96. return "D3DDECLUSAGE_POSITION";
  97. case D3DDECLUSAGE_BLENDWEIGHT:
  98. return "D3DDECLUSAGE_BLENDWEIGHT";
  99. case D3DDECLUSAGE_BLENDINDICES:
  100. return "D3DDECLUSAGE_BLENDINDICES";
  101. case D3DDECLUSAGE_NORMAL:
  102. return "D3DDECLUSAGE_NORMAL";
  103. case D3DDECLUSAGE_PSIZE:
  104. return "D3DDECLUSAGE_PSIZE";
  105. case D3DDECLUSAGE_COLOR:
  106. return "D3DDECLUSAGE_COLOR";
  107. case D3DDECLUSAGE_TEXCOORD:
  108. return "D3DDECLUSAGE_TEXCOORD";
  109. case D3DDECLUSAGE_TANGENT:
  110. return "D3DDECLUSAGE_TANGENT";
  111. case D3DDECLUSAGE_BINORMAL:
  112. return "D3DDECLUSAGE_BINORMAL";
  113. case D3DDECLUSAGE_TESSFACTOR:
  114. return "D3DDECLUSAGE_TESSFACTOR";
  115. // case D3DDECLUSAGE_POSITIONTL:
  116. // return "D3DDECLUSAGE_POSITIONTL";
  117. default:
  118. Assert( 0 );
  119. return "ERROR";
  120. }
  121. }
  122. static D3DDECLTYPE VertexElementToDeclType( VertexElement_t element, VertexCompressionType_t compressionType )
  123. {
  124. Detect_VertexElement_t_Changes( element );
  125. if ( compressionType == VERTEX_COMPRESSION_ON )
  126. {
  127. // Compressed-vertex element sizes
  128. switch ( element )
  129. {
  130. #if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 )
  131. case VERTEX_ELEMENT_NORMAL: return D3DDECLTYPE_SHORT2;
  132. case VERTEX_ELEMENT_USERDATA4: return D3DDECLTYPE_SHORT2;
  133. #else //( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 )
  134. case VERTEX_ELEMENT_NORMAL: return D3DDECLTYPE_UBYTE4;
  135. case VERTEX_ELEMENT_USERDATA4: return D3DDECLTYPE_UBYTE4;
  136. #endif
  137. case VERTEX_ELEMENT_BONEWEIGHTS1: return D3DDECLTYPE_SHORT2;
  138. case VERTEX_ELEMENT_BONEWEIGHTS2: return D3DDECLTYPE_SHORT2;
  139. default:
  140. break;
  141. }
  142. }
  143. // Uncompressed-vertex element sizes
  144. switch ( element )
  145. {
  146. case VERTEX_ELEMENT_POSITION: return D3DDECLTYPE_FLOAT3;
  147. case VERTEX_ELEMENT_NORMAL: return D3DDECLTYPE_FLOAT3;
  148. case VERTEX_ELEMENT_COLOR: return D3DDECLTYPE_D3DCOLOR;
  149. case VERTEX_ELEMENT_SPECULAR: return D3DDECLTYPE_D3DCOLOR;
  150. case VERTEX_ELEMENT_TANGENT_S: return D3DDECLTYPE_FLOAT3;
  151. case VERTEX_ELEMENT_TANGENT_T: return D3DDECLTYPE_FLOAT3;
  152. case VERTEX_ELEMENT_WRINKLE:
  153. // Wrinkle is packed into Position.W, it is not specified as a separate vertex element
  154. Assert( 0 );
  155. return D3DDECLTYPE_UNUSED;
  156. #if !defined( _X360 )
  157. case VERTEX_ELEMENT_BONEINDEX: return D3DDECLTYPE_D3DCOLOR;
  158. #else
  159. // UBYTE4 comes in as [0,255] in the shader, which is ideal for bone indices
  160. // (unfortunately, UBYTE4 is not universally supported on PC DX8 GPUs)
  161. case VERTEX_ELEMENT_BONEINDEX: return D3DDECLTYPE_UBYTE4;
  162. #endif
  163. case VERTEX_ELEMENT_BONEWEIGHTS1: return D3DDECLTYPE_FLOAT1;
  164. case VERTEX_ELEMENT_BONEWEIGHTS2: return D3DDECLTYPE_FLOAT2;
  165. case VERTEX_ELEMENT_BONEWEIGHTS3: return D3DDECLTYPE_FLOAT3;
  166. case VERTEX_ELEMENT_BONEWEIGHTS4: return D3DDECLTYPE_FLOAT4;
  167. case VERTEX_ELEMENT_USERDATA1: return D3DDECLTYPE_FLOAT1;
  168. case VERTEX_ELEMENT_USERDATA2: return D3DDECLTYPE_FLOAT2;
  169. case VERTEX_ELEMENT_USERDATA3: return D3DDECLTYPE_FLOAT3;
  170. case VERTEX_ELEMENT_USERDATA4: return D3DDECLTYPE_FLOAT4;
  171. case VERTEX_ELEMENT_TEXCOORD1D_0: return D3DDECLTYPE_FLOAT1;
  172. case VERTEX_ELEMENT_TEXCOORD1D_1: return D3DDECLTYPE_FLOAT1;
  173. case VERTEX_ELEMENT_TEXCOORD1D_2: return D3DDECLTYPE_FLOAT1;
  174. case VERTEX_ELEMENT_TEXCOORD1D_3: return D3DDECLTYPE_FLOAT1;
  175. case VERTEX_ELEMENT_TEXCOORD1D_4: return D3DDECLTYPE_FLOAT1;
  176. case VERTEX_ELEMENT_TEXCOORD1D_5: return D3DDECLTYPE_FLOAT1;
  177. case VERTEX_ELEMENT_TEXCOORD1D_6: return D3DDECLTYPE_FLOAT1;
  178. case VERTEX_ELEMENT_TEXCOORD1D_7: return D3DDECLTYPE_FLOAT1;
  179. case VERTEX_ELEMENT_TEXCOORD2D_0: return D3DDECLTYPE_FLOAT2;
  180. case VERTEX_ELEMENT_TEXCOORD2D_1: return D3DDECLTYPE_FLOAT2;
  181. case VERTEX_ELEMENT_TEXCOORD2D_2: return D3DDECLTYPE_FLOAT2;
  182. case VERTEX_ELEMENT_TEXCOORD2D_3: return D3DDECLTYPE_FLOAT2;
  183. case VERTEX_ELEMENT_TEXCOORD2D_4: return D3DDECLTYPE_FLOAT2;
  184. case VERTEX_ELEMENT_TEXCOORD2D_5: return D3DDECLTYPE_FLOAT2;
  185. case VERTEX_ELEMENT_TEXCOORD2D_6: return D3DDECLTYPE_FLOAT2;
  186. case VERTEX_ELEMENT_TEXCOORD2D_7: return D3DDECLTYPE_FLOAT2;
  187. case VERTEX_ELEMENT_TEXCOORD3D_0: return D3DDECLTYPE_FLOAT3;
  188. case VERTEX_ELEMENT_TEXCOORD3D_1: return D3DDECLTYPE_FLOAT3;
  189. case VERTEX_ELEMENT_TEXCOORD3D_2: return D3DDECLTYPE_FLOAT3;
  190. case VERTEX_ELEMENT_TEXCOORD3D_3: return D3DDECLTYPE_FLOAT3;
  191. case VERTEX_ELEMENT_TEXCOORD3D_4: return D3DDECLTYPE_FLOAT3;
  192. case VERTEX_ELEMENT_TEXCOORD3D_5: return D3DDECLTYPE_FLOAT3;
  193. case VERTEX_ELEMENT_TEXCOORD3D_6: return D3DDECLTYPE_FLOAT3;
  194. case VERTEX_ELEMENT_TEXCOORD3D_7: return D3DDECLTYPE_FLOAT3;
  195. case VERTEX_ELEMENT_TEXCOORD4D_0: return D3DDECLTYPE_FLOAT4;
  196. case VERTEX_ELEMENT_TEXCOORD4D_1: return D3DDECLTYPE_FLOAT4;
  197. case VERTEX_ELEMENT_TEXCOORD4D_2: return D3DDECLTYPE_FLOAT4;
  198. case VERTEX_ELEMENT_TEXCOORD4D_3: return D3DDECLTYPE_FLOAT4;
  199. case VERTEX_ELEMENT_TEXCOORD4D_4: return D3DDECLTYPE_FLOAT4;
  200. case VERTEX_ELEMENT_TEXCOORD4D_5: return D3DDECLTYPE_FLOAT4;
  201. case VERTEX_ELEMENT_TEXCOORD4D_6: return D3DDECLTYPE_FLOAT4;
  202. case VERTEX_ELEMENT_TEXCOORD4D_7: return D3DDECLTYPE_FLOAT4;
  203. default:
  204. Assert(0);
  205. return D3DDECLTYPE_UNUSED;
  206. };
  207. }
  208. void PrintVertexDeclaration( const D3DVERTEXELEMENT9 *pDecl )
  209. {
  210. int i;
  211. static D3DVERTEXELEMENT9 declEnd = D3DDECL_END();
  212. for ( i = 0; ; i++ )
  213. {
  214. if ( memcmp( &pDecl[i], &declEnd, sizeof( declEnd ) ) == 0 )
  215. {
  216. Warning( "D3DDECL_END\n" );
  217. break;
  218. }
  219. Msg( "%d: Stream: %d, Offset: %d, Type: %s, Method: %s, Usage: %s, UsageIndex: %d\n",
  220. i, ( int )pDecl[i].Stream, ( int )pDecl[i].Offset,
  221. DeclTypeToString( pDecl[i].Type ),
  222. DeclMethodToString( pDecl[i].Method ),
  223. DeclUsageToString( pDecl[i].Usage ),
  224. ( int )pDecl[i].UsageIndex );
  225. }
  226. }
  227. //-----------------------------------------------------------------------------
  228. // Converts format to a vertex decl
  229. //-----------------------------------------------------------------------------
  230. void ComputeVertexSpec( VertexFormat_t fmt, D3DVERTEXELEMENT9 *pDecl, bool bStaticLit, bool bUsingFlex, bool bUsingMorph )
  231. {
  232. int i = 0;
  233. int offset = 0;
  234. VertexCompressionType_t compressionType = CompressionType( fmt );
  235. if ( IsX360() )
  236. {
  237. // On 360, there's a performance penalty for reading more than 2 streams in the vertex shader
  238. // (we don't do this yet, but we should be aware if we start doing it)
  239. #ifdef _DEBUG
  240. int numStreams = 1 + ( bStaticLit ? 1 : 0 ) + ( bUsingFlex ? 1 : 0 ) + ( bUsingMorph ? 1 : 0 );
  241. Assert( numStreams <= 2 );
  242. #endif
  243. }
  244. if ( fmt & VERTEX_POSITION )
  245. {
  246. pDecl[i].Stream = 0;
  247. pDecl[i].Offset = offset;
  248. pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
  249. pDecl[i].Usage = D3DDECLUSAGE_POSITION;
  250. pDecl[i].UsageIndex = 0;
  251. pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_POSITION, compressionType );
  252. offset += GetVertexElementSize( VERTEX_ELEMENT_POSITION, compressionType );
  253. ++i;
  254. }
  255. int numBones = NumBoneWeights(fmt);
  256. if ( numBones > 0 )
  257. {
  258. pDecl[i].Stream = 0;
  259. pDecl[i].Offset = offset;
  260. pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
  261. pDecl[i].Usage = D3DDECLUSAGE_BLENDWEIGHT;
  262. pDecl[i].UsageIndex = 0;
  263. // Always exactly two weights
  264. pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_BONEWEIGHTS2, compressionType );
  265. offset += GetVertexElementSize( VERTEX_ELEMENT_BONEWEIGHTS2, compressionType );
  266. ++i;
  267. }
  268. if ( fmt & VERTEX_BONE_INDEX )
  269. {
  270. // this isn't FVF!!!!!
  271. pDecl[i].Stream = 0;
  272. pDecl[i].Offset = offset;
  273. pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
  274. pDecl[i].Usage = D3DDECLUSAGE_BLENDINDICES;
  275. pDecl[i].UsageIndex = 0;
  276. pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_BONEINDEX, compressionType );
  277. offset += GetVertexElementSize( VERTEX_ELEMENT_BONEINDEX, compressionType );
  278. ++i;
  279. }
  280. int normalOffset = -1;
  281. if ( fmt & VERTEX_NORMAL )
  282. {
  283. pDecl[i].Stream = 0;
  284. pDecl[i].Offset = offset;
  285. normalOffset = offset;
  286. pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
  287. pDecl[i].Usage = D3DDECLUSAGE_NORMAL;
  288. pDecl[i].UsageIndex = 0;
  289. pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_NORMAL, compressionType );
  290. offset += GetVertexElementSize( VERTEX_ELEMENT_NORMAL, compressionType );
  291. ++i;
  292. }
  293. if ( fmt & VERTEX_COLOR )
  294. {
  295. pDecl[i].Stream = 0;
  296. pDecl[i].Offset = offset;
  297. pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
  298. pDecl[i].Usage = D3DDECLUSAGE_COLOR;
  299. pDecl[i].UsageIndex = 0;
  300. pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_COLOR, compressionType );
  301. offset += GetVertexElementSize( VERTEX_ELEMENT_COLOR, compressionType );
  302. ++i;
  303. }
  304. if ( fmt & VERTEX_SPECULAR )
  305. {
  306. Assert( !bStaticLit );
  307. pDecl[i].Stream = 0;
  308. pDecl[i].Offset = offset;
  309. pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
  310. pDecl[i].Usage = D3DDECLUSAGE_COLOR;
  311. pDecl[i].UsageIndex = 1; // SPECULAR goes in the second COLOR slot
  312. pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_SPECULAR, compressionType );
  313. offset += GetVertexElementSize( VERTEX_ELEMENT_SPECULAR, compressionType );
  314. ++i;
  315. }
  316. VertexElement_t texCoordDimensions[4] = { VERTEX_ELEMENT_TEXCOORD1D_0,
  317. VERTEX_ELEMENT_TEXCOORD2D_0,
  318. VERTEX_ELEMENT_TEXCOORD3D_0,
  319. VERTEX_ELEMENT_TEXCOORD4D_0 };
  320. for ( int j = 0; j < VERTEX_MAX_TEXTURE_COORDINATES; ++j )
  321. {
  322. int nCoordSize = TexCoordSize( j, fmt );
  323. if ( nCoordSize <= 0 )
  324. continue;
  325. Assert( nCoordSize <= 4 );
  326. pDecl[i].Stream = 0;
  327. pDecl[i].Offset = offset;
  328. pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
  329. pDecl[i].Usage = D3DDECLUSAGE_TEXCOORD;
  330. pDecl[i].UsageIndex = j;
  331. VertexElement_t texCoordElement = (VertexElement_t)( texCoordDimensions[ nCoordSize - 1 ] + j );
  332. pDecl[i].Type = VertexElementToDeclType( texCoordElement, compressionType );
  333. offset += GetVertexElementSize( texCoordElement, compressionType );
  334. ++i;
  335. }
  336. if ( fmt & VERTEX_TANGENT_S )
  337. {
  338. pDecl[i].Stream = 0;
  339. pDecl[i].Offset = offset;
  340. pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
  341. pDecl[i].Usage = D3DDECLUSAGE_TANGENT;
  342. pDecl[i].UsageIndex = 0;
  343. // NOTE: this is currently *not* compressed
  344. pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_TANGENT_S, compressionType );
  345. offset += GetVertexElementSize( VERTEX_ELEMENT_TANGENT_S, compressionType );
  346. ++i;
  347. }
  348. if ( fmt & VERTEX_TANGENT_T )
  349. {
  350. pDecl[i].Stream = 0;
  351. pDecl[i].Offset = offset;
  352. pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
  353. pDecl[i].Usage = D3DDECLUSAGE_BINORMAL;
  354. pDecl[i].UsageIndex = 0;
  355. // NOTE: this is currently *not* compressed
  356. pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_TANGENT_T, compressionType );
  357. offset += GetVertexElementSize( VERTEX_ELEMENT_TANGENT_T, compressionType );
  358. ++i;
  359. }
  360. int userDataSize = UserDataSize(fmt);
  361. if ( userDataSize > 0 )
  362. {
  363. Assert( userDataSize == 4 ); // This is actually only ever used for tangents
  364. pDecl[i].Stream = 0;
  365. if ( ( compressionType == VERTEX_COMPRESSION_ON ) &&
  366. ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) )
  367. {
  368. // FIXME: Normals and tangents are packed together into a single UBYTE4 element,
  369. // so just point this back at the same data while we're testing UBYTE4 out.
  370. pDecl[i].Offset = normalOffset;
  371. }
  372. else
  373. {
  374. pDecl[i].Offset = offset;
  375. }
  376. pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
  377. pDecl[i].Usage = D3DDECLUSAGE_TANGENT;
  378. pDecl[i].UsageIndex = 0;
  379. VertexElement_t userDataElement = (VertexElement_t)( VERTEX_ELEMENT_USERDATA1 + ( userDataSize - 1 ) );
  380. pDecl[i].Type = VertexElementToDeclType( userDataElement, compressionType );
  381. offset += GetVertexElementSize( userDataElement, compressionType );
  382. ++i;
  383. }
  384. if ( bStaticLit )
  385. {
  386. // force stream 1 to have specular color in it, which is used for baked static lighting
  387. pDecl[i].Stream = 1;
  388. pDecl[i].Offset = 0;
  389. pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
  390. pDecl[i].Usage = D3DDECLUSAGE_COLOR;
  391. pDecl[i].UsageIndex = 1; // SPECULAR goes into the second COLOR slot
  392. pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_SPECULAR, compressionType );
  393. ++i;
  394. }
  395. if ( HardwareConfig()->SupportsVertexAndPixelShaders() )
  396. {
  397. // FIXME: There needs to be a better way of doing this
  398. // In 2.0b, assume position is 4d, storing wrinkle in pos.w.
  399. bool bUseWrinkle = HardwareConfig()->SupportsPixelShaders_2_b();
  400. // Force stream 2 to have flex deltas in it
  401. pDecl[i].Stream = 2;
  402. pDecl[i].Offset = 0;
  403. pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
  404. pDecl[i].Usage = D3DDECLUSAGE_POSITION;
  405. pDecl[i].UsageIndex = 1;
  406. // FIXME: unify this with VertexElementToDeclType():
  407. pDecl[i].Type = bUseWrinkle ? D3DDECLTYPE_FLOAT4 : D3DDECLTYPE_FLOAT3;
  408. ++i;
  409. int normalOffset = GetVertexElementSize( VERTEX_ELEMENT_POSITION, compressionType );
  410. if ( bUseWrinkle )
  411. {
  412. normalOffset += GetVertexElementSize( VERTEX_ELEMENT_WRINKLE, compressionType );
  413. }
  414. // Normal deltas
  415. pDecl[i].Stream = 2;
  416. pDecl[i].Offset = normalOffset;
  417. pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
  418. pDecl[i].Usage = D3DDECLUSAGE_NORMAL;
  419. pDecl[i].UsageIndex = 1;
  420. // NOTE: this is currently *not* compressed
  421. pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_NORMAL, VERTEX_COMPRESSION_NONE );
  422. ++i;
  423. }
  424. if ( bUsingMorph )
  425. {
  426. // force stream 3 to have vertex index in it, which is used for doing vertex texture reads
  427. pDecl[i].Stream = 3;
  428. pDecl[i].Offset = 0;
  429. pDecl[i].Method = D3DDECLMETHOD_DEFAULT;
  430. pDecl[i].Usage = D3DDECLUSAGE_POSITION;
  431. pDecl[i].UsageIndex = 2;
  432. pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_USERDATA1, compressionType );
  433. ++i;
  434. }
  435. static D3DVERTEXELEMENT9 declEnd = D3DDECL_END();
  436. pDecl[i] = declEnd;
  437. //PrintVertexDeclaration( pDecl );
  438. }
  439. //-----------------------------------------------------------------------------
  440. // Gets the declspec associated with a vertex format
  441. //-----------------------------------------------------------------------------
  442. struct VertexDeclLookup_t
  443. {
  444. enum LookupFlags_t
  445. {
  446. STATIC_LIT = 0x1,
  447. USING_MORPH = 0x2,
  448. USING_FLEX = 0x4,
  449. };
  450. VertexFormat_t m_VertexFormat;
  451. int m_nFlags;
  452. IDirect3DVertexDeclaration9 *m_pDecl;
  453. bool operator==( const VertexDeclLookup_t &src ) const
  454. {
  455. return ( m_VertexFormat == src.m_VertexFormat ) && ( m_nFlags == src.m_nFlags );
  456. }
  457. };
  458. //-----------------------------------------------------------------------------
  459. // Dictionary of vertex decls
  460. // FIXME: stick this in the class?
  461. // FIXME: Does anything cause this to get flushed?
  462. //-----------------------------------------------------------------------------
  463. static bool VertexDeclLessFunc( const VertexDeclLookup_t &src1, const VertexDeclLookup_t &src2 )
  464. {
  465. if ( src1.m_nFlags == src2.m_nFlags )
  466. return src1.m_VertexFormat < src2.m_VertexFormat;
  467. return ( src1.m_nFlags < src2.m_nFlags );
  468. }
  469. static CUtlRBTree<VertexDeclLookup_t, int> s_VertexDeclDict( 0, 256, VertexDeclLessFunc );
  470. //-----------------------------------------------------------------------------
  471. // Gets the declspec associated with a vertex format
  472. //-----------------------------------------------------------------------------
  473. IDirect3DVertexDeclaration9 *FindOrCreateVertexDecl( VertexFormat_t fmt, bool bStaticLit, bool bUsingFlex, bool bUsingMorph )
  474. {
  475. MEM_ALLOC_D3D_CREDIT();
  476. VertexDeclLookup_t lookup;
  477. lookup.m_VertexFormat = fmt;
  478. lookup.m_nFlags = 0;
  479. if ( bStaticLit )
  480. {
  481. lookup.m_nFlags |= VertexDeclLookup_t::STATIC_LIT;
  482. }
  483. if ( bUsingMorph )
  484. {
  485. lookup.m_nFlags |= VertexDeclLookup_t::USING_MORPH;
  486. }
  487. if ( bUsingFlex )
  488. {
  489. lookup.m_nFlags |= VertexDeclLookup_t::USING_FLEX;
  490. }
  491. int i = s_VertexDeclDict.Find( lookup );
  492. if ( i != s_VertexDeclDict.InvalidIndex() )
  493. {
  494. // found
  495. return s_VertexDeclDict[i].m_pDecl;
  496. }
  497. D3DVERTEXELEMENT9 decl[32];
  498. ComputeVertexSpec( fmt, decl, bStaticLit, bUsingFlex, bUsingMorph );
  499. HRESULT hr =
  500. Dx9Device()->CreateVertexDeclaration( decl, &lookup.m_pDecl );
  501. // NOTE: can't record until we have m_pDecl!
  502. RECORD_COMMAND( DX8_CREATE_VERTEX_DECLARATION, 2 );
  503. RECORD_INT( ( int )lookup.m_pDecl );
  504. RECORD_STRUCT( decl, sizeof( decl ) );
  505. COMPILE_TIME_ASSERT( sizeof( decl ) == sizeof( D3DVERTEXELEMENT9 ) * 32 );
  506. Assert( hr == D3D_OK );
  507. if ( hr != D3D_OK )
  508. {
  509. Warning( " ERROR: failed to create vertex decl for vertex format 0x%08llX! You'll probably see messed-up mesh rendering - to diagnose, build shaderapidx9.dll in debug.\n", fmt );
  510. }
  511. s_VertexDeclDict.Insert( lookup );
  512. return lookup.m_pDecl;
  513. }
  514. //-----------------------------------------------------------------------------
  515. // Clears out all declspecs
  516. //-----------------------------------------------------------------------------
  517. void ReleaseAllVertexDecl()
  518. {
  519. int i = s_VertexDeclDict.FirstInorder();
  520. while ( i != s_VertexDeclDict.InvalidIndex() )
  521. {
  522. if ( s_VertexDeclDict[i].m_pDecl )
  523. s_VertexDeclDict[i].m_pDecl->Release();
  524. i = s_VertexDeclDict.NextInorder( i );
  525. }
  526. }