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.

2454 lines
82 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include <stdlib.h>
  7. #include "tier0/platform.h"
  8. #include "studiorendercontext.h"
  9. #include "optimize.h"
  10. #include "materialsystem/imaterialvar.h"
  11. #include "materialsystem/imesh.h"
  12. #include "materialsystem/imorph.h"
  13. #include "materialsystem/ivballoctracker.h"
  14. #include "vstdlib/random.h"
  15. #include "tier0/tslist.h"
  16. #include "tier0/platform.h"
  17. #include "tier1/refcount.h"
  18. #include "tier1/callqueue.h"
  19. #include "cmodel.h"
  20. #include "tier0/vprof.h"
  21. // memdbgon must be the last include file in a .cpp file!!!
  22. #include "tier0/memdbgon.h"
  23. // garymcthack - this should go elsewhere
  24. #define MAX_NUM_BONE_INDICES 4
  25. //-----------------------------------------------------------------------------
  26. // Toggles studio queued mode
  27. //-----------------------------------------------------------------------------
  28. void StudioChangeCallback( IConVar *var, const char *pOldValue, float flOldValue )
  29. {
  30. // NOTE: This is necessary to flush the queued thread when this value changes
  31. MaterialLock_t hLock = g_pMaterialSystem->Lock();
  32. g_pMaterialSystem->Unlock( hLock );
  33. }
  34. static ConVar studio_queue_mode( "studio_queue_mode", "1", 0, "", StudioChangeCallback );
  35. //-----------------------------------------------------------------------------
  36. // Globals
  37. //-----------------------------------------------------------------------------
  38. static float s_pZeroFlexWeights[MAXSTUDIOFLEXDESC];
  39. //-----------------------------------------------------------------------------
  40. // Singleton instance
  41. //-----------------------------------------------------------------------------
  42. IStudioDataCache *g_pStudioDataCache = NULL;
  43. static CStudioRenderContext s_StudioRenderContext;
  44. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CStudioRenderContext, IStudioRender,
  45. STUDIO_RENDER_INTERFACE_VERSION, s_StudioRenderContext );
  46. //-----------------------------------------------------------------------------
  47. // Constructor, destructor
  48. //-----------------------------------------------------------------------------
  49. CStudioRenderContext::CStudioRenderContext()
  50. {
  51. // Initialize render context
  52. m_RC.m_pForcedMaterial = NULL;
  53. m_RC.m_nForcedMaterialType = OVERRIDE_NORMAL;
  54. m_RC.m_ColorMod[0] = m_RC.m_ColorMod[1] = m_RC.m_ColorMod[2] = 1.0f;
  55. m_RC.m_AlphaMod = 1.0f;
  56. m_RC.m_ViewOrigin.Init();
  57. m_RC.m_ViewRight.Init();
  58. m_RC.m_ViewUp.Init();
  59. m_RC.m_ViewPlaneNormal.Init();
  60. m_RC.m_Config.m_bEnableHWMorph = true;
  61. m_RC.m_Config.m_bStatsMode = false;
  62. m_RC.m_NumLocalLights = 0;
  63. for ( int i = 0; i < 6; ++i )
  64. {
  65. m_RC.m_LightBoxColors[i].Init( 0, 0, 0 );
  66. }
  67. }
  68. CStudioRenderContext::~CStudioRenderContext()
  69. {
  70. }
  71. //-----------------------------------------------------------------------------
  72. // Connect, disconnect
  73. //-----------------------------------------------------------------------------
  74. bool CStudioRenderContext::Connect( CreateInterfaceFn factory )
  75. {
  76. if ( !BaseClass::Connect( factory ) )
  77. return false;
  78. g_pStudioDataCache = ( IStudioDataCache * )factory( STUDIO_DATA_CACHE_INTERFACE_VERSION, NULL );
  79. if ( !g_pMaterialSystem || !g_pMaterialSystemHardwareConfig || !g_pStudioDataCache )
  80. {
  81. Msg("StudioRender failed to connect to a required system\n" );
  82. }
  83. return ( g_pMaterialSystem && g_pMaterialSystemHardwareConfig && g_pStudioDataCache );
  84. }
  85. void CStudioRenderContext::Disconnect()
  86. {
  87. g_pStudioDataCache = NULL;
  88. BaseClass::Disconnect();
  89. }
  90. //-----------------------------------------------------------------------------
  91. // Here's where systems can access other interfaces implemented by this object
  92. // Returns NULL if it doesn't implement the requested interface
  93. //-----------------------------------------------------------------------------
  94. void *CStudioRenderContext::QueryInterface( const char *pInterfaceName )
  95. {
  96. // Loading the studiorender DLL mounts *all* interfaces
  97. CreateInterfaceFn factory = Sys_GetFactoryThis(); // This silly construction is necessary
  98. return factory( pInterfaceName, NULL ); // to prevent the LTCG compiler from crashing.
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Init, shutdown
  102. //-----------------------------------------------------------------------------
  103. InitReturnVal_t CStudioRenderContext::Init()
  104. {
  105. MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f );
  106. InitReturnVal_t nRetVal = BaseClass::Init();
  107. if ( nRetVal != INIT_OK )
  108. return nRetVal;
  109. if( !g_pMaterialSystem || !g_pMaterialSystemHardwareConfig )
  110. return INIT_FAILED;
  111. return g_pStudioRenderImp->Init();
  112. }
  113. void CStudioRenderContext::Shutdown( void )
  114. {
  115. g_pStudioRenderImp->Shutdown();
  116. BaseClass::Shutdown();
  117. }
  118. //-----------------------------------------------------------------------------
  119. // Used to activate the stub material system.
  120. //-----------------------------------------------------------------------------
  121. void CStudioRenderContext::Mat_Stub( IMaterialSystem *pMatSys )
  122. {
  123. g_pMaterialSystem = pMatSys;
  124. }
  125. //-----------------------------------------------------------------------------
  126. // Determines material flags
  127. //-----------------------------------------------------------------------------
  128. void CStudioRenderContext::ComputeMaterialFlags( studiohdr_t *phdr, studioloddata_t &lodData, IMaterial *pMaterial )
  129. {
  130. // requesting info forces the initial material precache (and its build out)
  131. if ( pMaterial->UsesEnvCubemap() )
  132. {
  133. phdr->flags |= STUDIOHDR_FLAGS_USES_ENV_CUBEMAP;
  134. }
  135. if ( pMaterial->NeedsPowerOfTwoFrameBufferTexture( false ) ) // The false checks if it will ever need the frame buffer, not just this frame
  136. {
  137. phdr->flags |= STUDIOHDR_FLAGS_USES_FB_TEXTURE;
  138. }
  139. // FIXME: I'd rather know that the material is definitely using the bumpmap.
  140. // It could be in the file without actually being used.
  141. static unsigned int bumpvarCache = 0;
  142. IMaterialVar *pBumpMatVar = pMaterial->FindVarFast( "$bumpmap", &bumpvarCache );
  143. if ( pBumpMatVar && pBumpMatVar->IsDefined() && pMaterial->NeedsTangentSpace() )
  144. {
  145. phdr->flags |= STUDIOHDR_FLAGS_USES_BUMPMAPPING;
  146. }
  147. // Make sure material is treated as bump mapped if phong is set
  148. static unsigned int phongVarCache = 0;
  149. IMaterialVar *pPhongMatVar = pMaterial->FindVarFast( "$phong", &phongVarCache );
  150. if ( pPhongMatVar && pPhongMatVar->IsDefined() && ( pPhongMatVar->GetIntValue() != 0 ) )
  151. {
  152. phdr->flags |= STUDIOHDR_FLAGS_USES_BUMPMAPPING;
  153. }
  154. }
  155. //-----------------------------------------------------------------------------
  156. // Does this material use a mouth shader?
  157. //-----------------------------------------------------------------------------
  158. static bool UsesMouthShader( IMaterial *pMaterial )
  159. {
  160. // FIXME: hack, needs proper client side material system interface
  161. static unsigned int clientShaderCache = 0;
  162. IMaterialVar *clientShaderVar = pMaterial->FindVarFast( "$clientShader", &clientShaderCache );
  163. if ( clientShaderVar )
  164. return ( Q_stricmp( clientShaderVar->GetStringValue(), "MouthShader" ) == 0 );
  165. return false;
  166. }
  167. //-----------------------------------------------------------------------------
  168. // Returns the actual texture name to use on the model
  169. //-----------------------------------------------------------------------------
  170. static const char *GetTextureName( studiohdr_t *phdr, OptimizedModel::FileHeader_t *pVtxHeader,
  171. int lodID, int inMaterialID )
  172. {
  173. OptimizedModel::MaterialReplacementListHeader_t *materialReplacementList =
  174. pVtxHeader->pMaterialReplacementList( lodID );
  175. int i;
  176. for( i = 0; i < materialReplacementList->numReplacements; i++ )
  177. {
  178. OptimizedModel::MaterialReplacementHeader_t *materialReplacement =
  179. materialReplacementList->pMaterialReplacement( i );
  180. if( materialReplacement->materialID == inMaterialID )
  181. {
  182. const char *str = materialReplacement->pMaterialReplacementName();
  183. return str;
  184. }
  185. }
  186. return phdr->pTexture( inMaterialID )->pszName();
  187. }
  188. //-----------------------------------------------------------------------------
  189. // Loads materials associated with a particular LOD of a model
  190. //-----------------------------------------------------------------------------
  191. void CStudioRenderContext::LoadMaterials( studiohdr_t *phdr,
  192. OptimizedModel::FileHeader_t *pVtxHeader, studioloddata_t &lodData, int lodID )
  193. {
  194. typedef IMaterial *IMaterialPtr;
  195. Assert( phdr );
  196. lodData.numMaterials = phdr->numtextures;
  197. if ( lodData.numMaterials == 0 )
  198. {
  199. lodData.ppMaterials = NULL;
  200. return;
  201. }
  202. lodData.ppMaterials = new IMaterialPtr[lodData.numMaterials];
  203. Assert( lodData.ppMaterials );
  204. lodData.pMaterialFlags = new int[lodData.numMaterials];
  205. Assert( lodData.pMaterialFlags );
  206. int i, j;
  207. // get index of each material
  208. // set the runtime studiohdr flags that are material derived
  209. if ( phdr->textureindex == 0 )
  210. return;
  211. for ( i = 0; i < phdr->numtextures; i++ )
  212. {
  213. char szPath[MAX_PATH];
  214. IMaterial *pMaterial = NULL;
  215. // search through all specified directories until a valid material is found
  216. for ( j = 0; j < phdr->numcdtextures && IsErrorMaterial( pMaterial ); j++ )
  217. {
  218. // If we don't do this, we get filenames like "materials\\blah.vmt".
  219. const char *textureName = GetTextureName( phdr, pVtxHeader, lodID, i );
  220. if ( textureName[0] == CORRECT_PATH_SEPARATOR || textureName[0] == INCORRECT_PATH_SEPARATOR )
  221. ++textureName;
  222. // This prevents filenames like /models/blah.vmt.
  223. const char *pCdTexture = phdr->pCdtexture( j );
  224. if ( pCdTexture[0] == CORRECT_PATH_SEPARATOR || pCdTexture[0] == INCORRECT_PATH_SEPARATOR )
  225. ++pCdTexture;
  226. V_ComposeFileName( pCdTexture, textureName, szPath, sizeof( szPath ) );
  227. if ( phdr->flags & STUDIOHDR_FLAGS_OBSOLETE )
  228. {
  229. pMaterial = g_pMaterialSystem->FindMaterial( "models/obsolete/obsolete", TEXTURE_GROUP_MODEL, false );
  230. if ( IsErrorMaterial( pMaterial ) )
  231. {
  232. Warning( "StudioRender: OBSOLETE material missing: \"models/obsolete/obsolete\"\n" );
  233. }
  234. }
  235. else
  236. {
  237. pMaterial = g_pMaterialSystem->FindMaterial( szPath, TEXTURE_GROUP_MODEL, false );
  238. }
  239. }
  240. if ( IsErrorMaterial( pMaterial ) )
  241. {
  242. // hack - if it isn't found, go through the motions of looking for it again
  243. // so that the materialsystem will give an error.
  244. char szPrefix[256];
  245. Q_strncpy( szPrefix, phdr->pszName(), sizeof( szPrefix ) );
  246. Q_strncat( szPrefix, " : ", sizeof( szPrefix ), COPY_ALL_CHARACTERS );
  247. for ( j = 0; j < phdr->numcdtextures; j++ )
  248. {
  249. Q_strncpy( szPath, phdr->pCdtexture( j ), sizeof( szPath ) );
  250. const char *textureName = GetTextureName( phdr, pVtxHeader, lodID, i );
  251. Q_strncat( szPath, textureName, sizeof( szPath ), COPY_ALL_CHARACTERS );
  252. Q_FixSlashes( szPath, CORRECT_PATH_SEPARATOR );
  253. g_pMaterialSystem->FindMaterial( szPath, TEXTURE_GROUP_MODEL, true, szPrefix );
  254. }
  255. }
  256. lodData.ppMaterials[i] = pMaterial;
  257. if ( pMaterial )
  258. {
  259. // Increment the reference count for the material.
  260. pMaterial->IncrementReferenceCount();
  261. ComputeMaterialFlags( phdr, lodData, pMaterial );
  262. lodData.pMaterialFlags[i] = UsesMouthShader( pMaterial ) ? 1 : 0;
  263. }
  264. }
  265. }
  266. //-----------------------------------------------------------------------------
  267. // Suppresses all hw morphs on a model
  268. //-----------------------------------------------------------------------------
  269. static void SuppressAllHWMorphs( mstudiomodel_t *pModel, OptimizedModel::ModelLODHeader_t *pVtxLOD )
  270. {
  271. for ( int k = 0; k < pModel->nummeshes; ++k )
  272. {
  273. OptimizedModel::MeshHeader_t* pVtxMesh = pVtxLOD->pMesh(k);
  274. for (int i = 0; i < pVtxMesh->numStripGroups; ++i )
  275. {
  276. OptimizedModel::StripGroupHeader_t* pStripGroup = pVtxMesh->pStripGroup(i);
  277. if ( ( pStripGroup->flags & OptimizedModel::STRIPGROUP_IS_DELTA_FLEXED ) )
  278. {
  279. pStripGroup->flags |= OptimizedModel::STRIPGROUP_SUPPRESS_HW_MORPH;
  280. }
  281. }
  282. }
  283. }
  284. //-----------------------------------------------------------------------------
  285. // Computes the total flexes on a model
  286. //-----------------------------------------------------------------------------
  287. static int ComputeTotalFlexCount( mstudiomodel_t *pModel )
  288. {
  289. int nFlexCount = 0;
  290. for ( int k = 0; k < pModel->nummeshes; ++k )
  291. {
  292. mstudiomesh_t* pMesh = pModel->pMesh(k);
  293. nFlexCount += pMesh->numflexes;
  294. }
  295. return nFlexCount;
  296. }
  297. //-----------------------------------------------------------------------------
  298. // Count deltas affecting a particular stripgroup
  299. //-----------------------------------------------------------------------------
  300. int CStudioRenderContext::CountDeltaFlexedStripGroups( mstudiomodel_t *pModel, OptimizedModel::ModelLODHeader_t *pVtxLOD )
  301. {
  302. int nFlexedStripGroupCount = 0;
  303. for ( int k = 0; k < pModel->nummeshes; ++k )
  304. {
  305. Assert( pModel->nummeshes == pVtxLOD->numMeshes );
  306. OptimizedModel::MeshHeader_t* pVtxMesh = pVtxLOD->pMesh(k);
  307. for (int i = 0; i < pVtxMesh->numStripGroups; ++i )
  308. {
  309. OptimizedModel::StripGroupHeader_t* pStripGroup = pVtxMesh->pStripGroup(i);
  310. if ( ( pStripGroup->flags & OptimizedModel::STRIPGROUP_IS_DELTA_FLEXED ) == 0 )
  311. continue;
  312. ++nFlexedStripGroupCount;
  313. }
  314. }
  315. return nFlexedStripGroupCount;
  316. }
  317. //-----------------------------------------------------------------------------
  318. // Count vertices affected by deltas in a particular strip group
  319. //-----------------------------------------------------------------------------
  320. int CStudioRenderContext::CountFlexedVertices( mstudiomesh_t* pMesh, OptimizedModel::StripGroupHeader_t* pStripGroup )
  321. {
  322. if ( !pMesh->numflexes )
  323. return 0;
  324. // an inverse mapping from mesh index to strip group index
  325. unsigned short *pMeshIndexToGroupIndex = (unsigned short*)_alloca( pMesh->pModel()->numvertices * sizeof(unsigned short) );
  326. memset( pMeshIndexToGroupIndex, 0xFF, pMesh->pModel()->numvertices * sizeof(unsigned short) );
  327. for ( int i = 0; i < pStripGroup->numVerts; ++i )
  328. {
  329. int nMeshVert = pStripGroup->pVertex(i)->origMeshVertID;
  330. pMeshIndexToGroupIndex[ nMeshVert ] = (unsigned short)i;
  331. }
  332. int nFlexVertCount = 0;
  333. for ( int i = 0; i < pMesh->numflexes; ++i )
  334. {
  335. mstudioflex_t *pFlex = pMesh->pFlex( i );
  336. byte *pVAnim = pFlex->pBaseVertanim();
  337. int nVAnimSizeBytes = pFlex->VertAnimSizeBytes();
  338. for ( int j = 0; j < pFlex->numverts; ++j )
  339. {
  340. mstudiovertanim_t *pAnim = (mstudiovertanim_t*)( pVAnim + j * nVAnimSizeBytes );
  341. int nMeshVert = pAnim->index;
  342. unsigned short nGroupVert = pMeshIndexToGroupIndex[nMeshVert];
  343. // In this case, this vertex is not part of this meshgroup. Ignore it.
  344. if ( nGroupVert != 0xFFFF )
  345. {
  346. // Only count it once
  347. pMeshIndexToGroupIndex[nMeshVert] = 0xFFFF;
  348. ++nFlexVertCount;
  349. }
  350. }
  351. }
  352. return nFlexVertCount;
  353. }
  354. //-----------------------------------------------------------------------------
  355. // Determine if any strip groups shouldn't be morphed
  356. //-----------------------------------------------------------------------------
  357. static int* s_pVertexCount;
  358. static int SortVertCount( const void *arg1, const void *arg2 )
  359. {
  360. /* Compare all of both strings: */
  361. return s_pVertexCount[*( const int* )arg2] - s_pVertexCount[*( const int* )arg1];
  362. }
  363. #define MIN_HWMORPH_FLEX_COUNT 200
  364. void CStudioRenderContext::DetermineHWMorphing( mstudiomodel_t *pModel, OptimizedModel::ModelLODHeader_t *pVtxLOD )
  365. {
  366. if ( !g_pMaterialSystemHardwareConfig->HasFastVertexTextures() )
  367. return;
  368. // There is fixed cost to using HW morphing in the form of setting rendertargets.
  369. // Therefore if there is a low chance of there being enough work, then do it in software.
  370. int nTotalFlexCount = ComputeTotalFlexCount( pModel );
  371. if ( nTotalFlexCount == 0 )
  372. return;
  373. if ( nTotalFlexCount < MIN_HWMORPH_FLEX_COUNT )
  374. {
  375. SuppressAllHWMorphs( pModel, pVtxLOD );
  376. return;
  377. }
  378. // If we have less meshes than the most morphs we can do in a batch, we're done.
  379. int nMaxHWMorphBatchCount = g_pMaterialSystemHardwareConfig->MaxHWMorphBatchCount();
  380. bool bHWMorph = ( pModel->nummeshes <= nMaxHWMorphBatchCount );
  381. if ( bHWMorph )
  382. return;
  383. // If we have less flexed strip groups than the most we can do in a batch, we're done.
  384. int nFlexedStripGroup = CountDeltaFlexedStripGroups( pModel, pVtxLOD );
  385. if ( nFlexedStripGroup <= nMaxHWMorphBatchCount )
  386. return;
  387. // Finally, the expensive method. Do HW morphing on the N most expensive strip groups
  388. // FIXME: We should do this at studiomdl time?
  389. // Certainly counting the # of flexed vertices can be done at studiomdl time.
  390. int *pVertexCount = (int*)_alloca( nFlexedStripGroup * sizeof(int) );
  391. int nCount = 0;
  392. for ( int k = 0; k < pModel->nummeshes; ++k )
  393. {
  394. Assert( pModel->nummeshes == pVtxLOD->numMeshes );
  395. mstudiomesh_t* pMesh = pModel->pMesh(k);
  396. OptimizedModel::MeshHeader_t* pVtxMesh = pVtxLOD->pMesh(k);
  397. for (int i = 0; i < pVtxMesh->numStripGroups; ++i )
  398. {
  399. OptimizedModel::StripGroupHeader_t* pStripGroup = pVtxMesh->pStripGroup(i);
  400. if ( ( pStripGroup->flags & OptimizedModel::STRIPGROUP_IS_DELTA_FLEXED ) == 0 )
  401. continue;
  402. pVertexCount[nCount++] = CountFlexedVertices( pMesh, pStripGroup );
  403. }
  404. }
  405. int *pSortedVertexIndices = (int*)_alloca( nFlexedStripGroup * sizeof(int) );
  406. for ( int i = 0; i < nFlexedStripGroup; ++i )
  407. {
  408. pSortedVertexIndices[i] = i;
  409. }
  410. s_pVertexCount = pVertexCount;
  411. qsort( pSortedVertexIndices, nCount, sizeof(int), SortVertCount );
  412. bool *pSuppressHWMorph = (bool*)_alloca( nFlexedStripGroup * sizeof(bool) );
  413. memset( pSuppressHWMorph, 1, nFlexedStripGroup * sizeof(bool) );
  414. for ( int i = 0; i < nMaxHWMorphBatchCount; ++i )
  415. {
  416. pSuppressHWMorph[pSortedVertexIndices[i]] = false;
  417. }
  418. // Bleah. Pretty lame. We should change StripGroupHeader_t to store the flex vertex count
  419. int nIndex = 0;
  420. for ( int k = 0; k < pModel->nummeshes; ++k )
  421. {
  422. Assert( pModel->nummeshes == pVtxLOD->numMeshes );
  423. OptimizedModel::MeshHeader_t* pVtxMesh = pVtxLOD->pMesh(k);
  424. for (int i = 0; i < pVtxMesh->numStripGroups; ++i )
  425. {
  426. OptimizedModel::StripGroupHeader_t* pStripGroup = pVtxMesh->pStripGroup(i);
  427. if ( ( pStripGroup->flags & OptimizedModel::STRIPGROUP_IS_DELTA_FLEXED ) == 0 )
  428. continue;
  429. if ( pSuppressHWMorph[nIndex] )
  430. {
  431. pStripGroup->flags |= OptimizedModel::STRIPGROUP_SUPPRESS_HW_MORPH;
  432. }
  433. ++nIndex;
  434. }
  435. }
  436. }
  437. //-----------------------------------------------------------------------------
  438. // Adds a vertex to the meshbuilder. Returns false if boneweights did not sum to 1.0
  439. //-----------------------------------------------------------------------------
  440. template <VertexCompressionType_t T> bool CStudioRenderContext::R_AddVertexToMesh( const char *pModelName, bool bNeedsTangentSpace, CMeshBuilder& meshBuilder,
  441. OptimizedModel::Vertex_t* pVertex, mstudiomesh_t* pMesh, const mstudio_meshvertexdata_t *vertData, bool hwSkin )
  442. {
  443. bool bOK = true;
  444. int idx = pVertex->origMeshVertID;
  445. mstudiovertex_t &vert = *vertData->Vertex( idx );
  446. // FIXME: if this ever becomes perf-critical... these writes are not in memory-ascending order,
  447. // which hurts since VBs are in write-combined memory (See WriteCombineOrdering_t)
  448. meshBuilder.Position3fv( vert.m_vecPosition.Base() );
  449. meshBuilder.CompressedNormal3fv<T>( vert.m_vecNormal.Base() );
  450. /*
  451. if( vert.m_vecNormal.Length() < .9f || vert.m_vecNormal.Length() > 1.1f )
  452. {
  453. static CUtlStringMap<bool> errorMessages;
  454. if( !errorMessages.Defined( pModelName ) )
  455. {
  456. errorMessages[pModelName] = true;
  457. Warning( "MODELBUG %s: bad normal\n", pModelName );
  458. Warning( "\tnormal %0.1f %0.1f %0.1f pos: %0.1f %0.1f %0.1f\n",
  459. vert.m_vecNormal.x, vert.m_vecNormal.y, vert.m_vecNormal.z,
  460. vert.m_vecPosition.x, vert.m_vecPosition.y, vert.m_vecPosition.z );
  461. }
  462. }
  463. */
  464. meshBuilder.TexCoord2fv( 0, vert.m_vecTexCoord.Base() );
  465. if (vertData->HasTangentData())
  466. {
  467. /*
  468. if( bNeedsTangentSpace && pModelName && vertData->TangentS( idx ) )
  469. {
  470. const Vector4D &tangentS = *vertData->TangentS( idx );
  471. float w = tangentS.w;
  472. if( !( w == 1.0f || w == -1.0f ) )
  473. {
  474. static CUtlStringMap<bool> errorMessages;
  475. if( !errorMessages.Defined( pModelName ) )
  476. {
  477. errorMessages[pModelName] = true;
  478. Warning( "MODELBUG %s: bad tangent sign\n", pModelName );
  479. Warning( "\tsign %0.1f at position %0.1f %0.1f %0.1f\n",
  480. w, vert.m_vecPosition.x, vert.m_vecPosition.y, vert.m_vecPosition.z );
  481. }
  482. }
  483. float len = tangentS.AsVector3D().Length();
  484. if( len < .9f || len > 1.1f )
  485. {
  486. static CUtlStringMap<bool> errorMessages;
  487. if( !errorMessages.Defined( pModelName ) )
  488. {
  489. errorMessages[pModelName] = true;
  490. Warning( "MODELBUG %s: bad tangent vector\n", pModelName );
  491. Warning( "\ttangent: %0.1f %0.1f %0.1f with length %0.1f at position %0.1f %0.1f %0.1f\n",
  492. tangentS.x, tangentS.y, tangentS.z,
  493. len,
  494. vert.m_vecPosition.x, vert.m_vecPosition.y, vert.m_vecPosition.z );
  495. }
  496. }
  497. #if 0
  498. float dot = DotProduct( vert.m_vecNormal, tangentS.AsVector3D() );
  499. if( dot > .95 || dot < -.95 )
  500. {
  501. static CUtlStringMap<bool> errorMessages;
  502. if( !errorMessages.Defined( pModelName ) )
  503. {
  504. errorMessages[pModelName] = true;
  505. // this is crashing for some reason. .need to investigate.
  506. Warning( "MODELBUG %s: nearly colinear tangentS (%f %f %f) and normal (%f %f %f) at position %f %f %f Probably have 2 or more texcoords that are the same on a triangle.\n",
  507. pModelName, tangentS.x, tangentS.y, tangentS.y, vert.m_vecNormal.x, vert.m_vecNormal.y, vert.m_vecNormal.z, vert.m_vecPosition.x, vert.m_vecPosition.y, vert.m_vecPosition.z );
  508. }
  509. }
  510. #endif
  511. }
  512. */
  513. // send down tangent S as a 4D userdata vect.
  514. meshBuilder.CompressedUserData<T>( (*vertData->TangentS( idx )).Base() );
  515. }
  516. // Just in case we get hooked to a material that wants per-vertex color
  517. meshBuilder.Color4ub( 255, 255, 255, 255 );
  518. float boneWeights[ MAX_NUM_BONE_INDICES ];
  519. if ( hwSkin )
  520. {
  521. // sum up weights..
  522. int i;
  523. // We have to do this because since we're potentially dropping bones
  524. // to get them to fit in hardware, we'll need to renormalize based on
  525. // the actual total.
  526. mstudioboneweight_t *pBoneWeight = vertData->BoneWeights(idx);
  527. // NOTE: We use pVertex->numbones because that's the number of bones actually influencing this
  528. // vertex. Note that pVertex->numBones is not necessary the *desired* # of bones influencing this
  529. // vertex; we could have collapsed some of those bones out. pBoneWeight->numbones stures the desired #
  530. float totalWeight = 0;
  531. for (i = 0; i < pVertex->numBones; ++i)
  532. {
  533. totalWeight += pBoneWeight->weight[pVertex->boneWeightIndex[i]];
  534. }
  535. // The only way we should not add up to 1 is if there's more than 3 *desired* bones
  536. // and more than 1 *actual* bone (we can have 0 vertex bones in the case of static props
  537. if ( (pVertex->numBones > 0) && (pBoneWeight->numbones <= 3) && fabs(totalWeight - 1.0f) > 1e-3 )
  538. {
  539. // force them to re-normalize
  540. bOK = false;
  541. totalWeight = 1.0f;
  542. }
  543. // Fix up the static prop case
  544. if ( totalWeight == 0.0f )
  545. {
  546. totalWeight = 1.0f;
  547. }
  548. float invTotalWeight = 1.0f / totalWeight;
  549. // It is essential to iterate over all actual bones so that the bone indices
  550. // are set correctly, even though the last bone weight is computed in a shader program
  551. for (i = 0; i < pVertex->numBones; ++i)
  552. {
  553. if ( pVertex->boneID[i] == -1 )
  554. {
  555. boneWeights[ i ] = 0.0f;
  556. meshBuilder.BoneMatrix( i, BONE_MATRIX_INDEX_INVALID );
  557. }
  558. else
  559. {
  560. float weight = pBoneWeight->weight[pVertex->boneWeightIndex[i]];
  561. boneWeights[ i ] = weight * invTotalWeight;
  562. meshBuilder.BoneMatrix( i, pVertex->boneID[i] );
  563. }
  564. }
  565. for( ; i < MAX_NUM_BONE_INDICES; i++ )
  566. {
  567. boneWeights[ i ] = 0.0f;
  568. meshBuilder.BoneMatrix( i, BONE_MATRIX_INDEX_INVALID );
  569. }
  570. }
  571. else
  572. {
  573. for (int i = 0; i < MAX_NUM_BONE_INDICES; ++i)
  574. {
  575. boneWeights[ i ] = (i == 0) ? 1.0f : 0.0f;
  576. meshBuilder.BoneMatrix( i, BONE_MATRIX_INDEX_INVALID );
  577. }
  578. }
  579. // Set all the weights at once (the meshbuilder performs additional, post-compression, normalization):
  580. Assert( pVertex->numBones <= 3 );
  581. if ( pVertex->numBones > 0 )
  582. {
  583. meshBuilder.CompressedBoneWeight3fv<T>( &( boneWeights[ 0 ] ) );
  584. }
  585. meshBuilder.AdvanceVertex();
  586. return bOK;
  587. }
  588. // Get (uncompressed) vertex data from a mesh, if available
  589. inline const mstudio_meshvertexdata_t * GetFatVertexData( mstudiomesh_t * pMesh, studiohdr_t * pStudioHdr )
  590. {
  591. if ( !pMesh->pModel()->CacheVertexData( pStudioHdr ) )
  592. {
  593. // not available yet
  594. return NULL;
  595. }
  596. const mstudio_meshvertexdata_t *pVertData = pMesh->GetVertexData( pStudioHdr );
  597. Assert( pVertData );
  598. if ( !pVertData )
  599. {
  600. static unsigned int warnCount = 0;
  601. if ( warnCount++ < 20 )
  602. Warning( "ERROR: model verts have been compressed, cannot render! (use \"-no_compressed_vvds\")" );
  603. }
  604. return pVertData;
  605. }
  606. //-----------------------------------------------------------------------------
  607. // Builds the group
  608. //-----------------------------------------------------------------------------
  609. void CStudioRenderContext::R_StudioBuildMeshGroup( const char *pModelName, bool bNeedsTangentSpace, studiomeshgroup_t* pMeshGroup,
  610. OptimizedModel::StripGroupHeader_t *pStripGroup, mstudiomesh_t* pMesh,
  611. studiohdr_t *pStudioHdr, VertexFormat_t vertexFormat )
  612. {
  613. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  614. // We have to do this here because of skinning; there may be any number of
  615. // materials that are applied to this mesh.
  616. // Copy over all the vertices + indices in this strip group
  617. pMeshGroup->m_pMesh = pRenderContext->CreateStaticMesh( vertexFormat, TEXTURE_GROUP_STATIC_VERTEX_BUFFER_MODELS );
  618. VertexCompressionType_t compressionType = CompressionType( vertexFormat );
  619. pMeshGroup->m_ColorMeshID = -1;
  620. bool hwSkin = (pMeshGroup->m_Flags & MESHGROUP_IS_HWSKINNED) != 0;
  621. // This mesh could have tristrips or trilists in it
  622. CMeshBuilder meshBuilder;
  623. meshBuilder.SetCompressionType( compressionType );
  624. meshBuilder.Begin( pMeshGroup->m_pMesh, MATERIAL_HETEROGENOUS,
  625. hwSkin ? pStripGroup->numVerts : 0, pStripGroup->numIndices );
  626. int i;
  627. bool bBadBoneWeights = false;
  628. if ( hwSkin )
  629. {
  630. const mstudio_meshvertexdata_t *vertData = GetFatVertexData( pMesh, pStudioHdr );
  631. Assert( vertData );
  632. for ( i = 0; i < pStripGroup->numVerts; ++i )
  633. {
  634. bool success;
  635. switch ( compressionType )
  636. {
  637. case VERTEX_COMPRESSION_ON:
  638. success = R_AddVertexToMesh<VERTEX_COMPRESSION_ON>( pModelName, bNeedsTangentSpace, meshBuilder, pStripGroup->pVertex(i), pMesh, vertData, hwSkin );
  639. break;
  640. case VERTEX_COMPRESSION_NONE:
  641. default:
  642. success = R_AddVertexToMesh<VERTEX_COMPRESSION_NONE>( pModelName, bNeedsTangentSpace, meshBuilder, pStripGroup->pVertex(i), pMesh, vertData, hwSkin );
  643. break;
  644. }
  645. if ( !success )
  646. {
  647. bBadBoneWeights = true;
  648. }
  649. }
  650. }
  651. if ( bBadBoneWeights )
  652. {
  653. mstudiomodel_t* pModel = pMesh->pModel();
  654. ConMsg( "Bad data found in model \"%s\" (bad bone weights)\n", pModel->pszName() );
  655. }
  656. for (i = 0; i < pStripGroup->numIndices; ++i)
  657. {
  658. meshBuilder.Index( *pStripGroup->pIndex(i) );
  659. meshBuilder.AdvanceIndex();
  660. }
  661. meshBuilder.End();
  662. // Copy over the strip indices. We need access to the indices for decals
  663. pMeshGroup->m_pIndices = new unsigned short[ pStripGroup->numIndices ];
  664. memcpy( pMeshGroup->m_pIndices, pStripGroup->pIndex(0),
  665. pStripGroup->numIndices * sizeof(unsigned short) );
  666. // Compute the number of non-degenerate trianges in each strip group
  667. // for statistics gathering
  668. pMeshGroup->m_pUniqueTris = new int[ pStripGroup->numStrips ];
  669. for (i = 0; i < pStripGroup->numStrips; ++i )
  670. {
  671. int numUnique = 0;
  672. if (pStripGroup->pStrip(i)->flags & OptimizedModel::STRIP_IS_TRISTRIP)
  673. {
  674. int last[2] = {-1, -1};
  675. int curr = pStripGroup->pStrip(i)->indexOffset;
  676. int end = curr + pStripGroup->pStrip(i)->numIndices;
  677. while (curr != end)
  678. {
  679. int idx = *pStripGroup->pIndex(curr);
  680. if (idx != last[0] && idx != last[1] && last[0] != last[1] && last[0] != -1)
  681. ++numUnique;
  682. last[0] = last[1];
  683. last[1] = idx;
  684. ++curr;
  685. }
  686. }
  687. else
  688. {
  689. numUnique = pStripGroup->pStrip(i)->numIndices / 3;
  690. }
  691. pMeshGroup->m_pUniqueTris[i] = numUnique;
  692. }
  693. }
  694. //-----------------------------------------------------------------------------
  695. // Builds the group
  696. //-----------------------------------------------------------------------------
  697. void CStudioRenderContext::R_StudioBuildMorph( studiohdr_t *pStudioHdr,
  698. studiomeshgroup_t* pMeshGroup, mstudiomesh_t* pMesh,
  699. OptimizedModel::StripGroupHeader_t *pStripGroup )
  700. {
  701. if ( !g_pMaterialSystemHardwareConfig->HasFastVertexTextures() ||
  702. ( ( pMeshGroup->m_Flags & MESHGROUP_IS_DELTA_FLEXED ) == 0 ) ||
  703. ( ( pStripGroup->flags & OptimizedModel::STRIPGROUP_SUPPRESS_HW_MORPH ) != 0 ) )
  704. {
  705. pMeshGroup->m_pMorph = NULL;
  706. return;
  707. }
  708. // Build an inverse mapping from mesh index to strip group index
  709. unsigned short *pMeshIndexToGroupIndex = (unsigned short*)_alloca( pMesh->pModel()->numvertices * sizeof(unsigned short) );
  710. memset( pMeshIndexToGroupIndex, 0xFF, pMesh->pModel()->numvertices * sizeof(unsigned short) );
  711. for ( int i = 0; i < pStripGroup->numVerts; ++i )
  712. {
  713. int nMeshVert = pStripGroup->pVertex(i)->origMeshVertID;
  714. pMeshIndexToGroupIndex[ nMeshVert ] = (unsigned short)i;
  715. }
  716. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  717. MorphFormat_t morphType = MORPH_POSITION | MORPH_NORMAL | MORPH_SPEED | MORPH_SIDE;
  718. for ( int i = 0; i < pMesh->numflexes; ++i )
  719. {
  720. if ( pMesh->pFlex( i )->vertanimtype == STUDIO_VERT_ANIM_WRINKLE )
  721. {
  722. morphType |= MORPH_WRINKLE;
  723. break;
  724. }
  725. }
  726. char pTemp[256];
  727. Q_snprintf( pTemp, sizeof(pTemp), "%s [%p]", pStudioHdr->pszName(), pMeshGroup );
  728. pMeshGroup->m_pMorph = pRenderContext->CreateMorph( morphType, pTemp );
  729. const float flVertAnimFixedPointScale = pStudioHdr->VertAnimFixedPointScale();
  730. CMorphBuilder morphBuilder;
  731. morphBuilder.Begin( pMeshGroup->m_pMorph, 1.0f / flVertAnimFixedPointScale );
  732. for ( int i = 0; i < pMesh->numflexes; ++i )
  733. {
  734. mstudioflex_t *pFlex = pMesh->pFlex( i );
  735. byte *pVAnim = pFlex->pBaseVertanim();
  736. int nVAnimSizeBytes = pFlex->VertAnimSizeBytes();
  737. for ( int j = 0; j < pFlex->numverts; ++j )
  738. {
  739. mstudiovertanim_t *pAnim = (mstudiovertanim_t*)( pVAnim + j * nVAnimSizeBytes );
  740. int nMeshVert = pAnim->index;
  741. unsigned short nGroupVert = pMeshIndexToGroupIndex[nMeshVert];
  742. // In this case, this vertex is not part of this meshgroup. Ignore it.
  743. if ( nGroupVert == 0xFFFF )
  744. continue;
  745. morphBuilder.PositionDelta3( pAnim->GetDeltaFixed( flVertAnimFixedPointScale ) );
  746. morphBuilder.NormalDelta3( pAnim->GetNDeltaFixed( flVertAnimFixedPointScale ) );
  747. morphBuilder.Speed1f( pAnim->speed / 255.0f );
  748. morphBuilder.Side1f( pAnim->side / 255.0f );
  749. if ( pFlex->vertanimtype == STUDIO_VERT_ANIM_WRINKLE )
  750. {
  751. mstudiovertanim_wrinkle_t *pWrinkleAnim = static_cast<mstudiovertanim_wrinkle_t*>( pAnim );
  752. morphBuilder.WrinkleDelta1f( pWrinkleAnim->GetWrinkleDeltaFixed( flVertAnimFixedPointScale ) );
  753. }
  754. else
  755. {
  756. morphBuilder.WrinkleDelta1f( 0.0f );
  757. }
  758. morphBuilder.AdvanceMorph( nGroupVert, i );
  759. }
  760. }
  761. morphBuilder.End();
  762. }
  763. //-----------------------------------------------------------------------------
  764. // Builds the strip data
  765. //-----------------------------------------------------------------------------
  766. void CStudioRenderContext::R_StudioBuildMeshStrips( studiomeshgroup_t* pMeshGroup,
  767. OptimizedModel::StripGroupHeader_t *pStripGroup )
  768. {
  769. // FIXME: This is bogus
  770. // Compute the amount of memory we need to store the strip data
  771. int i;
  772. int stripDataSize = 0;
  773. for( i = 0; i < pStripGroup->numStrips; ++i )
  774. {
  775. stripDataSize += sizeof(OptimizedModel::StripHeader_t);
  776. stripDataSize += pStripGroup->pStrip(i)->numBoneStateChanges *
  777. sizeof(OptimizedModel::BoneStateChangeHeader_t);
  778. }
  779. pMeshGroup->m_pStripData = (OptimizedModel::StripHeader_t*)malloc(stripDataSize);
  780. // Copy over the strip info
  781. int boneStateChangeOffset = pStripGroup->numStrips * sizeof(OptimizedModel::StripHeader_t);
  782. for( i = 0; i < pStripGroup->numStrips; ++i )
  783. {
  784. memcpy( &pMeshGroup->m_pStripData[i], pStripGroup->pStrip(i),
  785. sizeof( OptimizedModel::StripHeader_t ) );
  786. // Fixup the bone state change offset, since we have it right after the strip data
  787. pMeshGroup->m_pStripData[i].boneStateChangeOffset = boneStateChangeOffset -
  788. i * sizeof(OptimizedModel::StripHeader_t);
  789. // copy over bone state changes
  790. int boneWeightSize = pMeshGroup->m_pStripData[i].numBoneStateChanges *
  791. sizeof(OptimizedModel::BoneStateChangeHeader_t);
  792. if (boneWeightSize != 0)
  793. {
  794. unsigned char* pBoneStateChange = (unsigned char*)pMeshGroup->m_pStripData + boneStateChangeOffset;
  795. memcpy( pBoneStateChange, pStripGroup->pStrip(i)->pBoneStateChange(0), boneWeightSize);
  796. boneStateChangeOffset += boneWeightSize;
  797. }
  798. }
  799. pMeshGroup->m_NumStrips = pStripGroup->numStrips;
  800. }
  801. //-----------------------------------------------------------------------------
  802. // Determine the max. number of bone weights used by a stripgroup
  803. //-----------------------------------------------------------------------------
  804. int CStudioRenderContext::GetNumBoneWeights( const OptimizedModel::StripGroupHeader_t *pGroup )
  805. {
  806. int nBoneWeightsMax = 0;
  807. for (int i = 0;i < pGroup->numStrips; i++)
  808. {
  809. OptimizedModel::StripHeader_t * pStrip = pGroup->pStrip( i );
  810. nBoneWeightsMax = max( nBoneWeightsMax, (int)pStrip->numBones );
  811. }
  812. return nBoneWeightsMax;
  813. }
  814. //-----------------------------------------------------------------------------
  815. // Determine an actual model vertex format for a mesh based on its material usage.
  816. // Bypasses the homegenous model vertex format in favor of the actual format.
  817. // Ideally matches 1:1 the shader's data requirements without any bloat.
  818. //-----------------------------------------------------------------------------
  819. VertexFormat_t CStudioRenderContext::CalculateVertexFormat( const studiohdr_t *pStudioHdr, const studioloddata_t *pStudioLodData,
  820. const mstudiomesh_t* pMesh, OptimizedModel::StripGroupHeader_t *pGroup, bool bIsHwSkinned )
  821. {
  822. bool bSkinnedMesh = ( pStudioHdr->numbones > 1 );
  823. int nBoneWeights = GetNumBoneWeights( pGroup );
  824. bool bIsDX7 = !g_pMaterialSystemHardwareConfig->SupportsVertexAndPixelShaders();
  825. bool bIsDX8 = ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 90 );
  826. if ( bIsDX7 )
  827. {
  828. // FIXME: this is untested (as of June '07, the engine currently doesn't work with "-dxlevel 70")
  829. if ( bSkinnedMesh )
  830. return MATERIAL_VERTEX_FORMAT_MODEL_SKINNED_DX7;
  831. else
  832. return MATERIAL_VERTEX_FORMAT_MODEL_DX7;
  833. }
  834. else if ( bIsDX8 )
  835. {
  836. if ( bSkinnedMesh )
  837. return MATERIAL_VERTEX_FORMAT_MODEL_SKINNED;
  838. else
  839. return MATERIAL_VERTEX_FORMAT_MODEL;
  840. }
  841. else
  842. {
  843. // DX9+ path (supports vertex compression)
  844. // iterate each skin table
  845. // determine aggregate vertex format for specified mesh's material
  846. VertexFormat_t newVertexFormat = 0;
  847. //bool bBumpmapping = false;
  848. short *pSkinref = pStudioHdr->pSkinref( 0 );
  849. for ( int i = 0; i < pStudioHdr->numskinfamilies; i++ )
  850. {
  851. // FIXME: ### MATERIAL VERTEX FORMATS ARE UNRELIABLE! ###
  852. //
  853. // IMaterial* pMaterial = pStudioLodData->ppMaterials[ pSkinref[ pMesh->material ] ];
  854. // Assert( pMaterial );
  855. // VertexFormat_t vertexFormat = pMaterial->GetVertexFormat();
  856. // newVertexFormat &= ~VERTEX_FORMAT_COMPRESSED; // Decide whether to compress below
  857. //
  858. // FIXME: ### MATERIAL VERTEX FORMATS ARE UNRELIABLE! ###
  859. // we need to go through all the shader CPP code and make sure that the correct vertex format
  860. // is being specified for every single shader combo! We don't have time to fix that before
  861. // shipping Ep2, but should fix it ASAP afterwards. To make catching such errors easier, we
  862. // should Assert in draw calls that the vertexdecl matches vertex shader inputs (note that D3D
  863. // debug DLLs will do that on PC, though it's not as informative as if we do it ourselves).
  864. // So, in the absence of reliable material vertex formats, use the old 'standard' elements
  865. // (we can still omit skinning data - and COLOR for DX8+, where it should come from the
  866. // second static lighting stream):
  867. VertexFormat_t vertexFormat = bIsDX7 ? MATERIAL_VERTEX_FORMAT_MODEL_DX7 : ( MATERIAL_VERTEX_FORMAT_MODEL & ~VERTEX_COLOR );
  868. // aggregate single bit settings
  869. newVertexFormat |= vertexFormat & ( ( 1 << VERTEX_LAST_BIT ) - 1 );
  870. int nUserDataSize = UserDataSize( vertexFormat );
  871. if ( nUserDataSize > UserDataSize( newVertexFormat ) )
  872. {
  873. newVertexFormat &= ~USER_DATA_SIZE_MASK;
  874. newVertexFormat |= VERTEX_USERDATA_SIZE( nUserDataSize );
  875. }
  876. for (int j = 0; j < VERTEX_MAX_TEXTURE_COORDINATES; ++j)
  877. {
  878. int nSize = TexCoordSize( j, vertexFormat );
  879. if ( nSize > TexCoordSize( j, newVertexFormat ) )
  880. {
  881. newVertexFormat &= ~VERTEX_TEXCOORD_SIZE( j, 0x7 );
  882. newVertexFormat |= VERTEX_TEXCOORD_SIZE( j, nSize );
  883. }
  884. }
  885. // FIXME: re-enable this test, fix it to work and see how much memory we save (Q: why is this different to CStudioRenderContext::MeshNeedsTangentSpace ?)
  886. /*if ( !bBumpmapping && pMaterial->NeedsTangentSpace() )
  887. {
  888. bool bFound = false;
  889. IMaterialVar *pEnvmapMatVar = pMaterial->FindVar( "$envmap", &bFound, false );
  890. if ( bFound && pEnvmapMatVar->IsDefined() )
  891. {
  892. IMaterialVar *pBumpMatVar = pMaterial->FindVar( "$bumpmap", &bFound, false );
  893. if ( bFound && pBumpMatVar->IsDefined() )
  894. {
  895. bBumpmapping = true;
  896. }
  897. }
  898. } */
  899. pSkinref += pStudioHdr->numskinref;
  900. }
  901. // Add skinning elements for non-rigid models (with more than one bone weight)
  902. if ( bSkinnedMesh )
  903. {
  904. if ( nBoneWeights > 0 )
  905. {
  906. // Always exactly zero or two weights
  907. newVertexFormat |= VERTEX_BONEWEIGHT( 2 );
  908. }
  909. newVertexFormat |= VERTEX_BONE_INDEX;
  910. }
  911. // FIXME: re-enable this (see above)
  912. /*if ( !bBumpmapping )
  913. {
  914. // no bumpmapping, user data not needed
  915. newVertexFormat &= ~USER_DATA_SIZE_MASK;
  916. }*/
  917. // materials on models should never have tangent space as they use userdata
  918. Assert( !(newVertexFormat & VERTEX_TANGENT_SPACE) );
  919. // Don't compress the mesh unless it is HW-skinned (we only want to compress static
  920. // VBs, not dynamic ones - that would slow down the MeshBuilder in dynamic use cases).
  921. // Also inspect the vertex data to see if it's appropriate for the vertex element
  922. // compression techniques that we do (e.g. look at UV ranges).
  923. if ( //IsX360() && // Disabled until the craziness is banished
  924. bIsHwSkinned &&
  925. ( g_pMaterialSystemHardwareConfig->SupportsCompressedVertices() == VERTEX_COMPRESSION_ON ) )
  926. {
  927. // this mesh is appropriate for vertex compression
  928. newVertexFormat |= VERTEX_FORMAT_COMPRESSED;
  929. }
  930. return newVertexFormat;
  931. }
  932. }
  933. bool CStudioRenderContext::MeshNeedsTangentSpace( studiohdr_t *pStudioHdr, studioloddata_t *pStudioLodData, mstudiomesh_t* pMesh )
  934. {
  935. // iterate each skin table
  936. if( !pStudioHdr || !pStudioHdr->pSkinref( 0 ) || !pStudioHdr->numskinfamilies )
  937. {
  938. return false;
  939. }
  940. short *pSkinref = pStudioHdr->pSkinref( 0 );
  941. for ( int i=0; i<pStudioHdr->numskinfamilies; i++)
  942. {
  943. IMaterial* pMaterial = pStudioLodData->ppMaterials[pSkinref[pMesh->material]];
  944. Assert( pMaterial );
  945. if( !pMaterial )
  946. {
  947. continue;
  948. }
  949. // Warning( "*****%s needstangentspace: %d\n", pMaterial->GetName(), pMaterial->NeedsTangentSpace() ? 1 : 0 );
  950. if( pMaterial->NeedsTangentSpace() )
  951. {
  952. return true;
  953. }
  954. }
  955. return false;
  956. }
  957. //-----------------------------------------------------------------------------
  958. // Creates a single mesh
  959. //-----------------------------------------------------------------------------
  960. void CStudioRenderContext::R_StudioCreateSingleMesh( studiohdr_t *pStudioHdr, studioloddata_t *pStudioLodData,
  961. mstudiomesh_t* pMesh, OptimizedModel::MeshHeader_t* pVtxMesh, int numBones,
  962. studiomeshdata_t* pMeshData, int *pColorMeshID )
  963. {
  964. // Here are the cases where we don't use any meshes at all...
  965. // In the case of eyes, we're just gonna use dynamic buffers
  966. // because it's the fastest solution (prevents lots of locks)
  967. bool bNeedsTangentSpace = MeshNeedsTangentSpace( pStudioHdr, pStudioLodData, pMesh );
  968. // Each strip group represents a locking group, it's a set of vertices
  969. // that are locked together, and, potentially, software light + skinned together
  970. pMeshData->m_NumGroup = pVtxMesh->numStripGroups;
  971. pMeshData->m_pMeshGroup = new studiomeshgroup_t[pVtxMesh->numStripGroups];
  972. for (int i = 0; i < pVtxMesh->numStripGroups; ++i )
  973. {
  974. OptimizedModel::StripGroupHeader_t* pStripGroup = pVtxMesh->pStripGroup(i);
  975. studiomeshgroup_t* pMeshGroup = &pMeshData->m_pMeshGroup[i];
  976. pMeshGroup->m_MeshNeedsRestore = false;
  977. // Set the flags...
  978. pMeshGroup->m_Flags = 0;
  979. if (pStripGroup->flags & OptimizedModel::STRIPGROUP_IS_FLEXED)
  980. {
  981. pMeshGroup->m_Flags |= MESHGROUP_IS_FLEXED;
  982. }
  983. if (pStripGroup->flags & OptimizedModel::STRIPGROUP_IS_DELTA_FLEXED)
  984. {
  985. pMeshGroup->m_Flags |= MESHGROUP_IS_DELTA_FLEXED;
  986. }
  987. bool bIsHwSkinned = !!(pStripGroup->flags & OptimizedModel::STRIPGROUP_IS_HWSKINNED);
  988. if ( bIsHwSkinned )
  989. {
  990. pMeshGroup->m_Flags |= MESHGROUP_IS_HWSKINNED;
  991. }
  992. // get the minimal vertex format for this mesh
  993. VertexFormat_t vertexFormat = CalculateVertexFormat( pStudioHdr, pStudioLodData, pMesh, pStripGroup, bIsHwSkinned );
  994. // Build the vertex + index buffers
  995. R_StudioBuildMeshGroup( pStudioHdr->pszName(), bNeedsTangentSpace, pMeshGroup, pStripGroup, pMesh, pStudioHdr, vertexFormat );
  996. // Copy over the tristrip and triangle list data
  997. R_StudioBuildMeshStrips( pMeshGroup, pStripGroup );
  998. // Builds morph targets
  999. R_StudioBuildMorph( pStudioHdr, pMeshGroup, pMesh, pStripGroup );
  1000. // Build the mapping from strip group vertex idx to actual mesh idx
  1001. pMeshGroup->m_pGroupIndexToMeshIndex = new unsigned short[pStripGroup->numVerts + PREFETCH_VERT_COUNT];
  1002. pMeshGroup->m_NumVertices = pStripGroup->numVerts;
  1003. int j;
  1004. for ( j = 0; j < pStripGroup->numVerts; ++j )
  1005. {
  1006. pMeshGroup->m_pGroupIndexToMeshIndex[j] = pStripGroup->pVertex(j)->origMeshVertID;
  1007. }
  1008. // Extra copies are for precaching...
  1009. for ( j = pStripGroup->numVerts; j < pStripGroup->numVerts + PREFETCH_VERT_COUNT; ++j )
  1010. {
  1011. pMeshGroup->m_pGroupIndexToMeshIndex[j] = pMeshGroup->m_pGroupIndexToMeshIndex[pStripGroup->numVerts - 1];
  1012. }
  1013. // assign the possibly used color mesh id now
  1014. pMeshGroup->m_ColorMeshID = (*pColorMeshID)++;
  1015. }
  1016. }
  1017. //-----------------------------------------------------------------------------
  1018. // Creates static meshes
  1019. //-----------------------------------------------------------------------------
  1020. void CStudioRenderContext::R_StudioCreateStaticMeshes( studiohdr_t *pStudioHdr,
  1021. OptimizedModel::FileHeader_t *pVtxHdr, studiohwdata_t *pStudioHWData, int nLodID, int *pColorMeshID )
  1022. {
  1023. int i, j, k;
  1024. Assert( pStudioHdr && pVtxHdr && pStudioHWData );
  1025. pStudioHWData->m_pLODs[nLodID].m_pMeshData = new studiomeshdata_t[pStudioHWData->m_NumStudioMeshes];
  1026. // Iterate over every body part...
  1027. for ( i = 0; i < pStudioHdr->numbodyparts; i++ )
  1028. {
  1029. mstudiobodyparts_t* pBodyPart = pStudioHdr->pBodypart(i);
  1030. OptimizedModel::BodyPartHeader_t* pVtxBodyPart = pVtxHdr->pBodyPart(i);
  1031. // Iterate over every submodel...
  1032. for ( j = 0; j < pBodyPart->nummodels; ++j )
  1033. {
  1034. mstudiomodel_t* pModel = pBodyPart->pModel(j);
  1035. OptimizedModel::ModelHeader_t* pVtxModel = pVtxBodyPart->pModel(j);
  1036. OptimizedModel::ModelLODHeader_t *pVtxLOD = pVtxModel->pLOD( nLodID );
  1037. // Determine which meshes should be hw morphed
  1038. DetermineHWMorphing( pModel, pVtxLOD );
  1039. // Support tracking of VB allocations
  1040. // FIXME: categorise studiomodel allocs more precisely
  1041. if ( g_VBAllocTracker )
  1042. {
  1043. if ( ( pStudioHdr->numbones > 8 ) || ( pStudioHdr->numflexdesc > 0 ) )
  1044. {
  1045. g_VBAllocTracker->TrackMeshAllocations( "R_StudioCreateStaticMeshes (character)" );
  1046. }
  1047. else
  1048. {
  1049. if ( pStudioHdr->flags & STUDIOHDR_FLAGS_STATIC_PROP )
  1050. {
  1051. g_VBAllocTracker->TrackMeshAllocations( "R_StudioCreateStaticMeshes (prop_static)" );
  1052. }
  1053. else
  1054. {
  1055. g_VBAllocTracker->TrackMeshAllocations( "R_StudioCreateStaticMeshes (prop_dynamic)" );
  1056. }
  1057. }
  1058. }
  1059. // Iterate over all the meshes....
  1060. for ( k = 0; k < pModel->nummeshes; ++k )
  1061. {
  1062. Assert( pModel->nummeshes == pVtxLOD->numMeshes );
  1063. mstudiomesh_t* pMesh = pModel->pMesh(k);
  1064. OptimizedModel::MeshHeader_t* pVtxMesh = pVtxLOD->pMesh(k);
  1065. Assert( pMesh->meshid < pStudioHWData->m_NumStudioMeshes );
  1066. R_StudioCreateSingleMesh( pStudioHdr, &pStudioHWData->m_pLODs[nLodID],
  1067. pMesh, pVtxMesh, pVtxHdr->maxBonesPerVert,
  1068. &pStudioHWData->m_pLODs[nLodID].m_pMeshData[pMesh->meshid], pColorMeshID );
  1069. }
  1070. if ( g_VBAllocTracker )
  1071. {
  1072. g_VBAllocTracker->TrackMeshAllocations( NULL );
  1073. }
  1074. }
  1075. }
  1076. }
  1077. //-----------------------------------------------------------------------------
  1078. // Destroys static meshes
  1079. //-----------------------------------------------------------------------------
  1080. void CStudioRenderContext::R_StudioDestroyStaticMeshes( int numStudioMeshes, studiomeshdata_t **ppStudioMeshes )
  1081. {
  1082. if( !*ppStudioMeshes)
  1083. return;
  1084. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1085. // Iterate over every body mesh...
  1086. for ( int i = 0; i < numStudioMeshes; ++i )
  1087. {
  1088. studiomeshdata_t* pMesh = &((*ppStudioMeshes)[i]);
  1089. for (int j = 0; j < pMesh->m_NumGroup; ++j)
  1090. {
  1091. studiomeshgroup_t* pGroup = &pMesh->m_pMeshGroup[j];
  1092. if (pGroup->m_pGroupIndexToMeshIndex)
  1093. {
  1094. delete[] pGroup->m_pGroupIndexToMeshIndex;
  1095. pGroup->m_pGroupIndexToMeshIndex = 0;
  1096. }
  1097. if (pGroup->m_pUniqueTris)
  1098. {
  1099. delete [] pGroup->m_pUniqueTris;
  1100. pGroup->m_pUniqueTris = 0;
  1101. }
  1102. if (pGroup->m_pIndices)
  1103. {
  1104. delete [] pGroup->m_pIndices;
  1105. pGroup->m_pIndices = 0;
  1106. }
  1107. if (pGroup->m_pMesh)
  1108. {
  1109. pRenderContext->DestroyStaticMesh( pGroup->m_pMesh );
  1110. pGroup->m_pMesh = 0;
  1111. }
  1112. if (pGroup->m_pMorph)
  1113. {
  1114. pRenderContext->DestroyMorph( pGroup->m_pMorph );
  1115. pGroup->m_pMorph = 0;
  1116. }
  1117. if (pGroup->m_pStripData)
  1118. {
  1119. free( pGroup->m_pStripData );
  1120. pGroup->m_pStripData = 0;
  1121. }
  1122. }
  1123. if (pMesh->m_pMeshGroup)
  1124. {
  1125. delete[] pMesh->m_pMeshGroup;
  1126. pMesh->m_pMeshGroup = 0;
  1127. }
  1128. }
  1129. if ( *ppStudioMeshes )
  1130. {
  1131. delete *ppStudioMeshes;
  1132. *ppStudioMeshes = 0;
  1133. }
  1134. }
  1135. //-----------------------------------------------------------------------------
  1136. // Builds the decal bone remap for a particular mesh
  1137. //-----------------------------------------------------------------------------
  1138. void CStudioRenderContext::BuildDecalBoneMap( studiohdr_t *pStudioHdr, int *pUsedBones, int *pBoneRemap, int *pMaxBoneCount, mstudiomesh_t* pMesh, OptimizedModel::StripGroupHeader_t* pStripGroup )
  1139. {
  1140. const mstudio_meshvertexdata_t *pVertData = GetFatVertexData( pMesh, pStudioHdr );
  1141. Assert( pVertData );
  1142. for ( int i = 0; i < pStripGroup->numVerts; ++i )
  1143. {
  1144. int nMeshVert = pStripGroup->pVertex( i )->origMeshVertID;
  1145. mstudioboneweight_t &boneWeight = pVertData->Vertex( nMeshVert )->m_BoneWeights;
  1146. int nBoneCount = boneWeight.numbones;
  1147. for ( int j = 0; j < nBoneCount; ++j )
  1148. {
  1149. if ( boneWeight.weight[j] == 0.0f )
  1150. continue;
  1151. if ( pBoneRemap[ (unsigned)boneWeight.bone[j] ] >= 0 )
  1152. continue;
  1153. pBoneRemap[ (unsigned)boneWeight.bone[j] ] = *pUsedBones;
  1154. *pUsedBones = *pUsedBones + 1;
  1155. }
  1156. }
  1157. for ( int i = 0; i < pStripGroup->numStrips; ++i )
  1158. {
  1159. if ( pStripGroup->pStrip(i)->numBones > *pMaxBoneCount )
  1160. {
  1161. *pMaxBoneCount = pStripGroup->pStrip(i)->numBones;
  1162. }
  1163. }
  1164. }
  1165. //-----------------------------------------------------------------------------
  1166. // For decals on hardware morphing, we must actually do hardware skinning
  1167. // because the flex must occur before skinning.
  1168. // For this to work, we have to hope that the total # of bones used by
  1169. // hw flexed verts is < than the max possible for the dx level we're running under
  1170. //-----------------------------------------------------------------------------
  1171. void CStudioRenderContext::ComputeHWMorphDecalBoneRemap( studiohdr_t *pStudioHdr, OptimizedModel::FileHeader_t *pVtxHdr, studiohwdata_t *pStudioHWData, int nLOD )
  1172. {
  1173. if ( pStudioHdr->numbones == 0 )
  1174. return;
  1175. // Remaps sw bones to hw bones during decal rendering
  1176. // NOTE: Only bones affecting vertices which have hw flexes will be add to this map.
  1177. int nBufSize = pStudioHdr->numbones * sizeof(int);
  1178. int *pBoneRemap = (int*)_alloca( nBufSize );
  1179. memset( pBoneRemap, 0xFF, nBufSize );
  1180. int nMaxBoneCount = 0;
  1181. // NOTE: HW bone index 0 is always the identity transform during decals.
  1182. pBoneRemap[0] = 0; // necessary for unused bones in a vertex
  1183. int nUsedBones = 1;
  1184. studioloddata_t *pStudioLOD = &pStudioHWData->m_pLODs[nLOD];
  1185. for ( int i = 0; i < pStudioHdr->numbodyparts; ++i )
  1186. {
  1187. mstudiobodyparts_t* pBodyPart = pStudioHdr->pBodypart(i);
  1188. OptimizedModel::BodyPartHeader_t* pVtxBodyPart = pVtxHdr->pBodyPart(i);
  1189. // Iterate over every submodel...
  1190. for ( int j = 0; j < pBodyPart->nummodels; ++j )
  1191. {
  1192. mstudiomodel_t* pModel = pBodyPart->pModel(j);
  1193. OptimizedModel::ModelHeader_t* pVtxModel = pVtxBodyPart->pModel(j);
  1194. OptimizedModel::ModelLODHeader_t *pVtxLOD = pVtxModel->pLOD( nLOD );
  1195. // Iterate over all the meshes....
  1196. for ( int k = 0; k < pModel->nummeshes; ++k )
  1197. {
  1198. Assert( pModel->nummeshes == pVtxLOD->numMeshes );
  1199. mstudiomesh_t* pMesh = pModel->pMesh(k);
  1200. OptimizedModel::MeshHeader_t* pVtxMesh = pVtxLOD->pMesh(k);
  1201. studiomeshdata_t* pMeshData = &pStudioLOD->m_pMeshData[pMesh->meshid];
  1202. for ( int l = 0; l < pVtxMesh->numStripGroups; ++l )
  1203. {
  1204. studiomeshgroup_t* pMeshGroup = &pMeshData->m_pMeshGroup[l];
  1205. if ( !pMeshGroup->m_pMorph )
  1206. continue;
  1207. OptimizedModel::StripGroupHeader_t* pStripGroup = pVtxMesh->pStripGroup(l);
  1208. BuildDecalBoneMap( pStudioHdr, &nUsedBones, pBoneRemap, &nMaxBoneCount, pMesh, pStripGroup );
  1209. }
  1210. }
  1211. }
  1212. }
  1213. if ( nUsedBones > 1 )
  1214. {
  1215. if ( nUsedBones > g_pMaterialSystemHardwareConfig->MaxVertexShaderBlendMatrices() )
  1216. {
  1217. Warning( "Hardware morphing of decals will be busted! Too many unique bones on flexed vertices!\n" );
  1218. }
  1219. pStudioLOD->m_pHWMorphDecalBoneRemap = new int[ pStudioHdr->numbones ];
  1220. memcpy( pStudioLOD->m_pHWMorphDecalBoneRemap, pBoneRemap, nBufSize );
  1221. pStudioLOD->m_nDecalBoneCount = nMaxBoneCount;
  1222. }
  1223. }
  1224. //-----------------------------------------------------------------------------
  1225. // Hook needed by mdlcache to load the vertex data
  1226. //-----------------------------------------------------------------------------
  1227. const vertexFileHeader_t * mstudiomodel_t::CacheVertexData( void *pModelData )
  1228. {
  1229. // make requested data resident
  1230. return g_pStudioDataCache->CacheVertexData( (studiohdr_t *)pModelData );
  1231. }
  1232. //-----------------------------------------------------------------------------
  1233. // Loads, unloads models
  1234. //-----------------------------------------------------------------------------
  1235. bool CStudioRenderContext::LoadModel( studiohdr_t *pStudioHdr, void *pVtxBuffer, studiohwdata_t *pStudioHWData )
  1236. {
  1237. int i;
  1238. int j;
  1239. Assert( pStudioHdr );
  1240. Assert( pVtxBuffer );
  1241. Assert( pStudioHWData );
  1242. if ( !pStudioHdr || !pVtxBuffer || !pStudioHWData )
  1243. return false;
  1244. // NOTE: This must be called *after* Mod_LoadStudioModel
  1245. OptimizedModel::FileHeader_t* pVertexHdr = (OptimizedModel::FileHeader_t*)pVtxBuffer;
  1246. if ( pVertexHdr->checkSum != pStudioHdr->checksum )
  1247. {
  1248. ConDMsg("Error! Model %s .vtx file out of synch with .mdl\n", pStudioHdr->pszName() );
  1249. return false;
  1250. }
  1251. pStudioHWData->m_NumStudioMeshes = 0;
  1252. for ( i = 0; i < pStudioHdr->numbodyparts; i++ )
  1253. {
  1254. mstudiobodyparts_t* pBodyPart = pStudioHdr->pBodypart(i);
  1255. for (j = 0; j < pBodyPart->nummodels; j++)
  1256. {
  1257. pStudioHWData->m_NumStudioMeshes += pBodyPart->pModel(j)->nummeshes;
  1258. }
  1259. }
  1260. // Create static meshes
  1261. Assert( pVertexHdr->numLODs );
  1262. pStudioHWData->m_RootLOD = min( (int)pStudioHdr->rootLOD, pVertexHdr->numLODs-1 );
  1263. pStudioHWData->m_NumLODs = pVertexHdr->numLODs;
  1264. pStudioHWData->m_pLODs = new studioloddata_t[pVertexHdr->numLODs];
  1265. memset( pStudioHWData->m_pLODs, 0, pVertexHdr->numLODs * sizeof( studioloddata_t ));
  1266. // reset the runtime flags
  1267. pStudioHdr->flags &= ~STUDIOHDR_FLAGS_USES_ENV_CUBEMAP;
  1268. pStudioHdr->flags &= ~STUDIOHDR_FLAGS_USES_FB_TEXTURE;
  1269. pStudioHdr->flags &= ~STUDIOHDR_FLAGS_USES_BUMPMAPPING;
  1270. #ifdef _DEBUG
  1271. int totalNumMeshGroups = 0;
  1272. #endif
  1273. int nColorMeshID = 0;
  1274. int nLodID;
  1275. for ( nLodID = pStudioHWData->m_RootLOD; nLodID < pStudioHWData->m_NumLODs; nLodID++ )
  1276. {
  1277. // Load materials and determine material dependent mesh requirements
  1278. LoadMaterials( pStudioHdr, pVertexHdr, pStudioHWData->m_pLODs[nLodID], nLodID );
  1279. // build the meshes
  1280. R_StudioCreateStaticMeshes( pStudioHdr, pVertexHdr, pStudioHWData, nLodID, &nColorMeshID );
  1281. // Build the hardware bone remap for decal rendering using HW morphing
  1282. ComputeHWMorphDecalBoneRemap( pStudioHdr, pVertexHdr, pStudioHWData, nLodID );
  1283. // garymcthack - need to check for NULL here.
  1284. // save off the lod switch point
  1285. pStudioHWData->m_pLODs[nLodID].m_SwitchPoint = pVertexHdr->pBodyPart( 0 )->pModel( 0 )->pLOD( nLodID )->switchPoint;
  1286. #ifdef _DEBUG
  1287. studioloddata_t *pLOD = &pStudioHWData->m_pLODs[nLodID];
  1288. for ( int meshID = 0; meshID < pStudioHWData->m_NumStudioMeshes; ++meshID )
  1289. {
  1290. totalNumMeshGroups += pLOD->m_pMeshData[meshID].m_NumGroup;
  1291. }
  1292. #endif
  1293. }
  1294. #ifdef _DEBUG
  1295. Assert( nColorMeshID == totalNumMeshGroups );
  1296. #endif
  1297. return true;
  1298. }
  1299. void CStudioRenderContext::UnloadModel( studiohwdata_t *pHardwareData )
  1300. {
  1301. int i;
  1302. for ( i = pHardwareData->m_RootLOD; i < pHardwareData->m_NumLODs; i++ )
  1303. {
  1304. int j;
  1305. for ( j = 0; j < pHardwareData->m_pLODs[i].numMaterials; j++ )
  1306. {
  1307. if ( pHardwareData->m_pLODs[i].ppMaterials[j] )
  1308. {
  1309. pHardwareData->m_pLODs[i].ppMaterials[j]->DecrementReferenceCount();
  1310. }
  1311. }
  1312. delete [] pHardwareData->m_pLODs[i].ppMaterials;
  1313. delete [] pHardwareData->m_pLODs[i].pMaterialFlags;
  1314. pHardwareData->m_pLODs[i].ppMaterials = NULL;
  1315. pHardwareData->m_pLODs[i].pMaterialFlags = NULL;
  1316. }
  1317. for ( i = pHardwareData->m_RootLOD; i < pHardwareData->m_NumLODs; i++ )
  1318. {
  1319. R_StudioDestroyStaticMeshes( pHardwareData->m_NumStudioMeshes, &pHardwareData->m_pLODs[i].m_pMeshData );
  1320. }
  1321. delete[] pHardwareData->m_pLODs;
  1322. pHardwareData->m_pLODs = NULL;
  1323. }
  1324. //-----------------------------------------------------------------------------
  1325. // Refresh the studiohdr since it was lost...
  1326. //-----------------------------------------------------------------------------
  1327. void CStudioRenderContext::RefreshStudioHdr( studiohdr_t* pStudioHdr, studiohwdata_t* pHardwareData )
  1328. {
  1329. }
  1330. //-----------------------------------------------------------------------------
  1331. // Set the eye view target
  1332. //-----------------------------------------------------------------------------
  1333. void CStudioRenderContext::SetEyeViewTarget( const studiohdr_t *pStudioHdr, int nBodyIndex, const Vector& viewtarget )
  1334. {
  1335. VectorCopy( viewtarget, m_RC.m_ViewTarget );
  1336. }
  1337. //-----------------------------------------------------------------------------
  1338. // Returns information about the ambient light samples
  1339. //-----------------------------------------------------------------------------
  1340. static TableVector s_pAmbientLightDir[6] =
  1341. {
  1342. { 1, 0, 0 },
  1343. { -1, 0, 0 },
  1344. { 0, 1, 0 },
  1345. { 0, -1, 0 },
  1346. { 0, 0, 1 },
  1347. { 0, 0, -1 },
  1348. };
  1349. int CStudioRenderContext::GetNumAmbientLightSamples()
  1350. {
  1351. return 6;
  1352. }
  1353. const Vector *CStudioRenderContext::GetAmbientLightDirections()
  1354. {
  1355. return (const Vector*)s_pAmbientLightDir;
  1356. }
  1357. //-----------------------------------------------------------------------------
  1358. // Methods related to LOD
  1359. //-----------------------------------------------------------------------------
  1360. int CStudioRenderContext::GetNumLODs( const studiohwdata_t &hardwareData ) const
  1361. {
  1362. return hardwareData.m_NumLODs;
  1363. }
  1364. float CStudioRenderContext::GetLODSwitchValue( const studiohwdata_t &hardwareData, int nLOD ) const
  1365. {
  1366. return hardwareData.m_pLODs[nLOD].m_SwitchPoint;
  1367. }
  1368. void CStudioRenderContext::SetLODSwitchValue( studiohwdata_t &hardwareData, int nLOD, float flSwitchValue )
  1369. {
  1370. // NOTE: This must block the hardware thread since it reads this data.
  1371. // This method is only used in tools, though.
  1372. MaterialLock_t hLock = g_pMaterialSystem->Lock();
  1373. hardwareData.m_pLODs[nLOD].m_SwitchPoint = flSwitchValue;
  1374. g_pMaterialSystem->Unlock( hLock );
  1375. }
  1376. //-----------------------------------------------------------------------------
  1377. // Returns the first n materials. The studiohdr material list is the superset
  1378. // for all lods.
  1379. //-----------------------------------------------------------------------------
  1380. int CStudioRenderContext::GetMaterialList( studiohdr_t *pStudioHdr, int count, IMaterial** ppMaterials )
  1381. {
  1382. AssertMsg( pStudioHdr, "Don't ignore this assert! CStudioRenderContext::GetMaterialList() has null pStudioHdr." );
  1383. if ( !pStudioHdr )
  1384. return 0;
  1385. if ( pStudioHdr->textureindex == 0 )
  1386. return 0;
  1387. // iterate each texture
  1388. int i;
  1389. int j;
  1390. int found = 0;
  1391. for ( i = 0; i < pStudioHdr->numtextures; i++ )
  1392. {
  1393. char szPath[MAX_PATH];
  1394. IMaterial *pMaterial = NULL;
  1395. // iterate quietly through all specified directories until a valid material is found
  1396. for ( j = 0; j < pStudioHdr->numcdtextures && IsErrorMaterial( pMaterial ); j++ )
  1397. {
  1398. // If we don't do this, we get filenames like "materials\\blah.vmt".
  1399. const char *textureName = pStudioHdr->pTexture( i )->pszName();
  1400. if ( textureName[0] == CORRECT_PATH_SEPARATOR || textureName[0] == INCORRECT_PATH_SEPARATOR )
  1401. ++textureName;
  1402. // This prevents filenames like /models/blah.vmt.
  1403. const char *pCdTexture = pStudioHdr->pCdtexture( j );
  1404. if ( pCdTexture[0] == CORRECT_PATH_SEPARATOR || pCdTexture[0] == INCORRECT_PATH_SEPARATOR )
  1405. ++pCdTexture;
  1406. V_ComposeFileName( pCdTexture, textureName, szPath, sizeof( szPath ) );
  1407. if ( pStudioHdr->flags & STUDIOHDR_FLAGS_OBSOLETE )
  1408. {
  1409. pMaterial = g_pMaterialSystem->FindMaterialEx( "models/obsolete/obsolete", TEXTURE_GROUP_MODEL, MATERIAL_FINDCONTEXT_ISONAMODEL, false );
  1410. }
  1411. else
  1412. {
  1413. pMaterial = g_pMaterialSystem->FindMaterialEx( szPath, TEXTURE_GROUP_MODEL, MATERIAL_FINDCONTEXT_ISONAMODEL, false );
  1414. }
  1415. }
  1416. if ( !pMaterial )
  1417. continue;
  1418. if ( found < count )
  1419. {
  1420. int k;
  1421. for ( k=0; k<found; k++ )
  1422. {
  1423. if ( ppMaterials[k] == pMaterial )
  1424. break;
  1425. }
  1426. if ( k >= found )
  1427. {
  1428. // add uniquely
  1429. ppMaterials[found++] = pMaterial;
  1430. }
  1431. }
  1432. else
  1433. {
  1434. break;
  1435. }
  1436. }
  1437. return found;
  1438. }
  1439. int CStudioRenderContext::GetMaterialListFromBodyAndSkin( MDLHandle_t studio, int nSkin, int nBody, int nCountOutputMaterials, IMaterial** ppOutputMaterials )
  1440. {
  1441. int found = 0;
  1442. studiohwdata_t *pStudioHWData = g_pMDLCache->GetHardwareData( studio );
  1443. if ( pStudioHWData == NULL )
  1444. return 0;
  1445. for ( int lodID = pStudioHWData->m_RootLOD; lodID < pStudioHWData->m_NumLODs; lodID++ )
  1446. {
  1447. studiohdr_t *pStudioHdr = g_pMDLCache->GetStudioHdr( studio );
  1448. IMaterial **ppInputMaterials = pStudioHWData->m_pLODs[lodID].ppMaterials;
  1449. if ( nSkin >= pStudioHdr->numskinfamilies )
  1450. {
  1451. nSkin = 0;
  1452. }
  1453. short *pSkinRef = pStudioHdr->pSkinref( nSkin * pStudioHdr->numskinref );
  1454. for (int i=0 ; i < pStudioHdr->numbodyparts ; i++)
  1455. {
  1456. mstudiomodel_t *pModel = NULL;
  1457. R_StudioSetupModel( i, nBody, &pModel, pStudioHdr );
  1458. // Iterate over all the meshes.... each mesh is a new material
  1459. for( int k = 0; k < pModel->nummeshes; ++k )
  1460. {
  1461. mstudiomesh_t *pMesh = pModel->pMesh(k);
  1462. IMaterial *pMaterial = ppInputMaterials[pSkinRef[pMesh->material]];
  1463. Assert( pMaterial );
  1464. int m;
  1465. for ( m=0; m<found; m++ )
  1466. {
  1467. if ( ppOutputMaterials[m] == pMaterial )
  1468. break;
  1469. }
  1470. if ( m >= found )
  1471. {
  1472. // add uniquely
  1473. ppOutputMaterials[found++] = pMaterial;
  1474. // No more room to store additional materials!
  1475. if ( found >= nCountOutputMaterials )
  1476. return found;
  1477. }
  1478. }
  1479. }
  1480. }
  1481. return found;
  1482. }
  1483. //-----------------------------------------------------------------------------
  1484. // Returns perf stats about a particular model
  1485. //-----------------------------------------------------------------------------
  1486. void CStudioRenderContext::GetPerfStats( DrawModelResults_t *pResults, const DrawModelInfo_t &info, CUtlBuffer *pSpewBuf ) const
  1487. {
  1488. pResults->m_ActualTriCount = pResults->m_TextureMemoryBytes = 0;
  1489. pResults->m_Materials.RemoveAll();
  1490. Assert( info.m_Lod >= 0 );
  1491. if ( info.m_Lod < 0 || !info.m_pHardwareData->m_pLODs )
  1492. return;
  1493. studiomeshdata_t *pStudioMeshes = info.m_pHardwareData->m_pLODs[info.m_Lod].m_pMeshData;
  1494. // Set up an array that keeps up with the number of used hardware bones in the models.
  1495. CUtlVector<bool> hardwareBonesUsed;
  1496. hardwareBonesUsed.EnsureCount( info.m_pStudioHdr->numbones );
  1497. int i;
  1498. for( i = 0; i < info.m_pStudioHdr->numbones; i++ )
  1499. {
  1500. hardwareBonesUsed[i] = false;
  1501. }
  1502. // Warning( "\n\n\n" );
  1503. pResults->m_NumMaterials = 0;
  1504. int numBoneStateChangeBatches = 0;
  1505. int numBoneStateChanges = 0;
  1506. // Iterate over every submodel...
  1507. IMaterial **ppMaterials = info.m_pHardwareData->m_pLODs[info.m_Lod].ppMaterials;
  1508. int nSkin = info.m_Skin;
  1509. if ( nSkin >= info.m_pStudioHdr->numskinfamilies )
  1510. {
  1511. nSkin = 0;
  1512. }
  1513. short *pSkinRef = info.m_pStudioHdr->pSkinref( nSkin * info.m_pStudioHdr->numskinref );
  1514. pResults->m_NumBatches = 0;
  1515. for (i=0 ; i < info.m_pStudioHdr->numbodyparts ; i++)
  1516. {
  1517. mstudiomodel_t *pModel = NULL;
  1518. R_StudioSetupModel( i, info.m_Body, &pModel, info.m_pStudioHdr );
  1519. // Iterate over all the meshes.... each mesh is a new material
  1520. int k;
  1521. for( k = 0; k < pModel->nummeshes; ++k )
  1522. {
  1523. mstudiomesh_t *pMesh = pModel->pMesh(k);
  1524. IMaterial *pMaterial = ppMaterials[pSkinRef[pMesh->material]];
  1525. Assert( pMaterial );
  1526. studiomeshdata_t *pMeshData = &pStudioMeshes[pMesh->meshid];
  1527. if( pMeshData->m_NumGroup == 0 )
  1528. continue;
  1529. Assert( pResults->m_NumMaterials == pResults->m_Materials.Count() );
  1530. pResults->m_NumMaterials++;
  1531. if( pResults->m_NumMaterials < MAX_DRAW_MODEL_INFO_MATERIALS )
  1532. {
  1533. pResults->m_Materials.AddToTail( pMaterial );
  1534. }
  1535. else
  1536. {
  1537. Assert( 0 );
  1538. }
  1539. if( pSpewBuf )
  1540. {
  1541. pSpewBuf->Printf( " material: %s\n", pMaterial->GetName() );
  1542. }
  1543. int numPasses = m_RC.m_pForcedMaterial ? m_RC.m_pForcedMaterial->GetNumPasses() : pMaterial->GetNumPasses();
  1544. if( pSpewBuf )
  1545. {
  1546. pSpewBuf->Printf( " numPasses:%d\n", numPasses );
  1547. }
  1548. int bytes = pMaterial->GetTextureMemoryBytes();
  1549. pResults->m_TextureMemoryBytes += bytes;
  1550. if( pSpewBuf )
  1551. {
  1552. pSpewBuf->Printf( " texture memory: %d (Only valid in a rendering app)\n", bytes );
  1553. }
  1554. // Iterate over all stripgroups
  1555. int stripGroupID;
  1556. for( stripGroupID = 0; stripGroupID < pMeshData->m_NumGroup; stripGroupID++ )
  1557. {
  1558. studiomeshgroup_t *pMeshGroup = &pMeshData->m_pMeshGroup[stripGroupID];
  1559. bool bIsFlexed = ( pMeshGroup->m_Flags & MESHGROUP_IS_FLEXED ) != 0;
  1560. bool bIsHWSkinned = ( pMeshGroup->m_Flags & MESHGROUP_IS_HWSKINNED ) != 0;
  1561. if( pSpewBuf )
  1562. {
  1563. pSpewBuf->Printf( " %d batch(es):\n", ( int )pMeshGroup->m_NumStrips );
  1564. }
  1565. // Iterate over all strips. . . each strip potentially changes bones states.
  1566. int stripID;
  1567. for( stripID = 0; stripID < pMeshGroup->m_NumStrips; stripID++ )
  1568. {
  1569. pResults->m_NumBatches++;
  1570. OptimizedModel::StripHeader_t *pStripData = &pMeshGroup->m_pStripData[stripID];
  1571. numBoneStateChangeBatches++;
  1572. numBoneStateChanges += pStripData->numBoneStateChanges;
  1573. if( bIsHWSkinned )
  1574. {
  1575. // Only count bones as hardware bones if we are using hardware skinning here.
  1576. int boneID;
  1577. for( boneID = 0; boneID < pStripData->numBoneStateChanges; boneID++ )
  1578. {
  1579. OptimizedModel::BoneStateChangeHeader_t *pBoneStateChange = pStripData->pBoneStateChange( boneID );
  1580. hardwareBonesUsed[pBoneStateChange->newBoneID] = true;
  1581. }
  1582. }
  1583. if( pStripData->flags & OptimizedModel::STRIP_IS_TRILIST )
  1584. {
  1585. // TODO: need to factor in bIsFlexed and bIsHWSkinned
  1586. int numTris = pStripData->numIndices / 3;
  1587. if( pSpewBuf )
  1588. {
  1589. pSpewBuf->Printf( " %s%s", bIsFlexed ? "flexed " : "nonflexed ",
  1590. bIsHWSkinned ? "hwskinned " : "swskinned " );
  1591. pSpewBuf->Printf( "tris: %d ", numTris );
  1592. pSpewBuf->Printf( "bone changes: %d bones/strip: %d\n", pStripData->numBoneStateChanges,
  1593. ( int )pStripData->numBones );
  1594. }
  1595. pResults->m_ActualTriCount += numTris * numPasses;
  1596. }
  1597. else if( pStripData->flags & OptimizedModel::STRIP_IS_TRISTRIP )
  1598. {
  1599. Assert( 0 ); // FIXME: fill this in when we start using strips again.
  1600. }
  1601. else
  1602. {
  1603. Assert( 0 );
  1604. }
  1605. }
  1606. }
  1607. }
  1608. }
  1609. if( pSpewBuf )
  1610. {
  1611. char nil = '\0';
  1612. pSpewBuf->Put( &nil, 1 );;
  1613. }
  1614. pResults->m_NumHardwareBones = 0;
  1615. for( i = 0; i < info.m_pStudioHdr->numbones; i++ )
  1616. {
  1617. if( hardwareBonesUsed[i] )
  1618. {
  1619. pResults->m_NumHardwareBones++;
  1620. }
  1621. }
  1622. }
  1623. //-----------------------------------------------------------------------------
  1624. // Begin/end frame
  1625. //-----------------------------------------------------------------------------
  1626. static ConVar r_hwmorph( "r_hwmorph", "1", FCVAR_CHEAT );
  1627. void CStudioRenderContext::BeginFrame( void )
  1628. {
  1629. // Cache a few values here so I don't have to in software inner loops:
  1630. Assert( g_pMaterialSystemHardwareConfig );
  1631. m_RC.m_Config.m_bSupportsVertexAndPixelShaders = g_pMaterialSystemHardwareConfig->SupportsVertexAndPixelShaders();
  1632. m_RC.m_Config.m_bSupportsOverbright = g_pMaterialSystemHardwareConfig->SupportsOverbright();
  1633. m_RC.m_Config.m_bEnableHWMorph = r_hwmorph.GetInt() != 0;
  1634. // Haven't implemented the hw morph with threading yet
  1635. if ( g_pMaterialSystem->GetThreadMode() != MATERIAL_SINGLE_THREADED )
  1636. {
  1637. m_RC.m_Config.m_bEnableHWMorph = false;
  1638. }
  1639. m_RC.m_Config.m_bStatsMode = false;
  1640. g_pStudioRenderImp->PrecacheGlint();
  1641. }
  1642. void CStudioRenderContext::EndFrame( void )
  1643. {
  1644. }
  1645. //-----------------------------------------------------------------------------
  1646. // Methods related to config
  1647. //-----------------------------------------------------------------------------
  1648. void CStudioRenderContext::UpdateConfig( const StudioRenderConfig_t& config )
  1649. {
  1650. memcpy( &m_RC.m_Config, &config, sizeof( StudioRenderConfig_t ) );
  1651. }
  1652. void CStudioRenderContext::GetCurrentConfig( StudioRenderConfig_t& config )
  1653. {
  1654. memcpy( &config, &m_RC.m_Config, sizeof( StudioRenderConfig_t ) );
  1655. }
  1656. //-----------------------------------------------------------------------------
  1657. // Material overrides
  1658. //-----------------------------------------------------------------------------
  1659. void CStudioRenderContext::ForcedMaterialOverride( IMaterial *newMaterial, OverrideType_t nOverrideType )
  1660. {
  1661. m_RC.m_pForcedMaterial = newMaterial;
  1662. m_RC.m_nForcedMaterialType = nOverrideType;
  1663. }
  1664. //-----------------------------------------------------------------------------
  1665. // Return the material overrides
  1666. //-----------------------------------------------------------------------------
  1667. void CStudioRenderContext::GetMaterialOverride( IMaterial** ppOutForcedMaterial, OverrideType_t* pOutOverrideType )
  1668. {
  1669. Assert( ppOutForcedMaterial != NULL && pOutOverrideType != NULL );
  1670. *ppOutForcedMaterial = m_RC.m_pForcedMaterial;
  1671. *pOutOverrideType = m_RC.m_nForcedMaterialType;
  1672. }
  1673. //-----------------------------------------------------------------------------
  1674. // Sets the view state
  1675. //-----------------------------------------------------------------------------
  1676. void CStudioRenderContext::SetViewState( const Vector& viewOrigin,
  1677. const Vector& viewRight, const Vector& viewUp, const Vector& viewPlaneNormal )
  1678. {
  1679. VectorCopy( viewOrigin, m_RC.m_ViewOrigin );
  1680. VectorCopy( viewRight, m_RC.m_ViewRight );
  1681. VectorCopy( viewUp, m_RC.m_ViewUp );
  1682. VectorCopy( viewPlaneNormal, m_RC.m_ViewPlaneNormal );
  1683. }
  1684. //-----------------------------------------------------------------------------
  1685. // Sets lighting state
  1686. //-----------------------------------------------------------------------------
  1687. void CStudioRenderContext::SetAmbientLightColors( const Vector *pColors )
  1688. {
  1689. for( int i = 0; i < 6; i++ )
  1690. {
  1691. VectorCopy( pColors[i], m_RC.m_LightBoxColors[i].AsVector3D() );
  1692. m_RC.m_LightBoxColors[i][3] = 1.0f;
  1693. }
  1694. // FIXME: Would like to get this into the render thread, but there's systemic confusion
  1695. // about whether to set lighting state here or in the material system
  1696. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1697. pRenderContext->SetAmbientLightCube( m_RC.m_LightBoxColors );
  1698. }
  1699. void CStudioRenderContext::SetAmbientLightColors( const Vector4D *pColors )
  1700. {
  1701. memcpy( m_RC.m_LightBoxColors, pColors, 6 * sizeof(Vector4D) );
  1702. // FIXME: Would like to get this into the render thread, but there's systemic confusion
  1703. // about whether to set lighting state here or in the material system
  1704. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1705. pRenderContext->SetAmbientLightCube( m_RC.m_LightBoxColors );
  1706. }
  1707. void CStudioRenderContext::SetLocalLights( int nLightCount, const LightDesc_t *pLights )
  1708. {
  1709. m_RC.m_NumLocalLights = CopyLocalLightingState( MAXLOCALLIGHTS, m_RC.m_LocalLights, nLightCount, pLights );
  1710. // FIXME: Would like to get this into the render thread, but there's systemic confusion
  1711. // about whether to set lighting state here or in the material system
  1712. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1713. if ( m_RC.m_Config.bSoftwareLighting || m_RC.m_NumLocalLights == 0 )
  1714. {
  1715. pRenderContext->DisableAllLocalLights();
  1716. }
  1717. else
  1718. {
  1719. int i;
  1720. int nMaxLightCount = g_pMaterialSystemHardwareConfig->MaxNumLights();
  1721. int nLightCount = min( m_RC.m_NumLocalLights, nMaxLightCount );
  1722. for( i = 0; i < nLightCount; i++ )
  1723. {
  1724. pRenderContext->SetLight( i, m_RC.m_LocalLights[i] );
  1725. }
  1726. for( ; i < nMaxLightCount; i++ )
  1727. {
  1728. LightDesc_t desc;
  1729. desc.m_Type = MATERIAL_LIGHT_DISABLE;
  1730. pRenderContext->SetLight( i, desc );
  1731. }
  1732. }
  1733. }
  1734. //-----------------------------------------------------------------------------
  1735. // Sets the color modulation
  1736. //-----------------------------------------------------------------------------
  1737. void CStudioRenderContext::SetColorModulation( const float* pColor )
  1738. {
  1739. VectorCopy( pColor, m_RC.m_ColorMod );
  1740. }
  1741. void CStudioRenderContext::SetAlphaModulation( float alpha )
  1742. {
  1743. m_RC.m_AlphaMod = alpha;
  1744. }
  1745. //-----------------------------------------------------------------------------
  1746. // Used to set bone-to-world transforms.
  1747. // FIXME: Should this be a lock/unlock pattern so we can't read after unlock?
  1748. //-----------------------------------------------------------------------------
  1749. matrix3x4_t* CStudioRenderContext::LockBoneMatrices( int nCount )
  1750. {
  1751. MEM_ALLOC_CREDIT_( "CStudioRenderContext::m_BoneToWorldMatrices" );
  1752. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1753. CMatRenderData<matrix3x4_t> rdMatrix( pRenderContext );
  1754. matrix3x4_t *pDest = rdMatrix.Lock( nCount );
  1755. return pDest;
  1756. }
  1757. void CStudioRenderContext::UnlockBoneMatrices()
  1758. {
  1759. }
  1760. //-----------------------------------------------------------------------------
  1761. // Allocates flex weights
  1762. //-----------------------------------------------------------------------------
  1763. void CStudioRenderContext::LockFlexWeights( int nWeightCount, float **ppFlexWeights, float **ppFlexDelayedWeights )
  1764. {
  1765. MEM_ALLOC_CREDIT_( "CStudioRenderContext::m_FlexWeights" );
  1766. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1767. CMatRenderData<float> rdFlex( pRenderContext );
  1768. CMatRenderData<float> rdFlexDelayed( pRenderContext );
  1769. float *pFlexOut = rdFlex.Lock( nWeightCount );
  1770. for ( int i = 0; i < nWeightCount; i++ )
  1771. {
  1772. pFlexOut[i] = 0.0f;
  1773. }
  1774. *ppFlexWeights = pFlexOut;
  1775. if ( ppFlexDelayedWeights )
  1776. {
  1777. pFlexOut = rdFlexDelayed.Lock( nWeightCount );
  1778. for ( int i = 0; i < nWeightCount; i++ )
  1779. {
  1780. pFlexOut[i] = 0.0f;
  1781. }
  1782. *ppFlexDelayedWeights = pFlexOut;
  1783. }
  1784. }
  1785. void CStudioRenderContext::UnlockFlexWeights()
  1786. {
  1787. }
  1788. //-----------------------------------------------------------------------------
  1789. // Methods related to flex weights
  1790. //-----------------------------------------------------------------------------
  1791. static ConVar r_randomflex( "r_randomflex", "0", FCVAR_CHEAT );
  1792. //-----------------------------------------------------------------------------
  1793. // This will generate random flex data that has a specified # of non-zero values
  1794. //-----------------------------------------------------------------------------
  1795. void CStudioRenderContext::GenerateRandomFlexWeights( int nWeightCount, float* pWeights, float *pDelayedWeights )
  1796. {
  1797. int nRandomFlex = r_randomflex.GetInt();
  1798. if ( nRandomFlex <= 0 || !pWeights )
  1799. return;
  1800. if ( nRandomFlex > nWeightCount )
  1801. {
  1802. nRandomFlex = nWeightCount;
  1803. }
  1804. int *pIndices = (int*)_alloca( nWeightCount * sizeof(int) );
  1805. for ( int i = 0; i < nWeightCount; ++i )
  1806. {
  1807. pIndices[i] = i;
  1808. }
  1809. // Shuffle
  1810. for ( int i = 0; i < nWeightCount; ++i )
  1811. {
  1812. int n = RandomInt( 0, nWeightCount-1 );
  1813. int nTemp = pIndices[n];
  1814. pIndices[n] = pIndices[i];
  1815. pIndices[i] = nTemp;
  1816. }
  1817. memset( pWeights, 0, nWeightCount * sizeof(float) );
  1818. for ( int i = 0; i < nRandomFlex; ++i )
  1819. {
  1820. pWeights[ pIndices[i] ] = RandomFloat( 0.0f, 1.0f );
  1821. }
  1822. if ( pDelayedWeights )
  1823. {
  1824. memset( pDelayedWeights, 0, nWeightCount * sizeof(float) );
  1825. for ( int i = 0; i < nRandomFlex; ++i )
  1826. {
  1827. pDelayedWeights[ pIndices[i] ] = RandomFloat( 0.0f, 1.0f );
  1828. }
  1829. }
  1830. }
  1831. //-----------------------------------------------------------------------------
  1832. // Computes LOD
  1833. //-----------------------------------------------------------------------------
  1834. int CStudioRenderContext::ComputeRenderLOD( IMatRenderContext *pRenderContext,
  1835. const DrawModelInfo_t& info, const Vector &origin, float *pMetric )
  1836. {
  1837. int lod = info.m_Lod;
  1838. int lastlod = info.m_pHardwareData->m_NumLODs - 1;
  1839. if ( pMetric )
  1840. {
  1841. *pMetric = 0.0f;
  1842. }
  1843. if ( lod == USESHADOWLOD )
  1844. return lastlod;
  1845. if ( lod != -1 )
  1846. return clamp( lod, info.m_pHardwareData->m_RootLOD, lastlod );
  1847. float screenSize = pRenderContext->ComputePixelWidthOfSphere( origin, 0.5f );
  1848. lod = ComputeModelLODAndMetric( info.m_pHardwareData, screenSize, pMetric );
  1849. // make sure we have a valid lod
  1850. if ( info.m_pStudioHdr->flags & STUDIOHDR_FLAGS_HASSHADOWLOD )
  1851. {
  1852. lastlod--;
  1853. }
  1854. lod = clamp( lod, info.m_pHardwareData->m_RootLOD, lastlod );
  1855. return lod;
  1856. }
  1857. //-----------------------------------------------------------------------------
  1858. // This invokes proxies of all materials that are queued to be rendered
  1859. // It has the effect of ensuring the material vars are in the correct state
  1860. // since material var sets generated by the proxy bind are queued.
  1861. //-----------------------------------------------------------------------------
  1862. void CStudioRenderContext::InvokeBindProxies( const DrawModelInfo_t &info )
  1863. {
  1864. if ( m_RC.m_pForcedMaterial )
  1865. {
  1866. if ( m_RC.m_nForcedMaterialType == OVERRIDE_NORMAL && m_RC.m_pForcedMaterial->HasProxy() )
  1867. {
  1868. m_RC.m_pForcedMaterial->CallBindProxy( info.m_pClientEntity );
  1869. }
  1870. return;
  1871. }
  1872. // get skinref array
  1873. int nSkin = ( m_RC.m_Config.skin > 0 ) ? m_RC.m_Config.skin : info.m_Skin;
  1874. short *pSkinRef = info.m_pStudioHdr->pSkinref( 0 );
  1875. if ( nSkin > 0 && nSkin < info.m_pStudioHdr->numskinfamilies )
  1876. {
  1877. pSkinRef += ( nSkin * info.m_pStudioHdr->numskinref );
  1878. }
  1879. // This is used to ensure proxies are only called once
  1880. int nBufSize = info.m_pStudioHdr->numtextures * sizeof(bool);
  1881. bool *pProxyCalled = (bool*)stackalloc( nBufSize );
  1882. memset( pProxyCalled, 0, nBufSize );
  1883. IMaterial **ppMaterials = info.m_pHardwareData->m_pLODs[ info.m_Lod ].ppMaterials;
  1884. mstudiomodel_t *pModel;
  1885. for ( int i=0 ; i < info.m_pStudioHdr->numbodyparts; ++i )
  1886. {
  1887. R_StudioSetupModel( i, info.m_Body, &pModel, info.m_pStudioHdr );
  1888. for ( int somethingOtherThanI = 0; somethingOtherThanI < pModel->nummeshes; ++somethingOtherThanI)
  1889. {
  1890. mstudiomesh_t *pMesh = pModel->pMesh(somethingOtherThanI);
  1891. int nMaterialIndex = pSkinRef[ pMesh->material ];
  1892. if ( pProxyCalled[ nMaterialIndex ] )
  1893. continue;
  1894. pProxyCalled[ nMaterialIndex ] = true;
  1895. IMaterial* pMaterial = ppMaterials[ nMaterialIndex ];
  1896. if ( pMaterial && pMaterial->HasProxy() )
  1897. {
  1898. pMaterial->CallBindProxy( info.m_pClientEntity );
  1899. }
  1900. }
  1901. }
  1902. }
  1903. //-----------------------------------------------------------------------------
  1904. // Draws a model
  1905. //-----------------------------------------------------------------------------
  1906. void CStudioRenderContext::DrawModel( DrawModelResults_t *pResults, const DrawModelInfo_t& info,
  1907. matrix3x4_t *pBoneToWorld, float *pFlexWeights, float *pFlexDelayedWeights, const Vector &origin, int flags )
  1908. {
  1909. // Set to zero in case we don't render anything.
  1910. if ( pResults )
  1911. {
  1912. pResults->m_ActualTriCount = pResults->m_TextureMemoryBytes = 0;
  1913. }
  1914. if( !info.m_pStudioHdr || !info.m_pHardwareData ||
  1915. !info.m_pHardwareData->m_NumLODs || !info.m_pHardwareData->m_pLODs )
  1916. {
  1917. return;
  1918. }
  1919. // Replace the flex weight data with random data for testing
  1920. GenerateRandomFlexWeights( info.m_pStudioHdr->numflexdesc, pFlexWeights, pFlexDelayedWeights );
  1921. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1922. float flMetric;
  1923. const_cast<DrawModelInfo_t*>( &info )->m_Lod = ComputeRenderLOD( pRenderContext, info, origin, &flMetric );
  1924. if ( pResults )
  1925. {
  1926. pResults->m_nLODUsed = info.m_Lod;
  1927. pResults->m_flLODMetric = flMetric;
  1928. }
  1929. MaterialLock_t hLock = 0;
  1930. if ( flags & STUDIORENDER_DRAW_ACCURATETIME )
  1931. {
  1932. VPROF("STUDIORENDER_DRAW_ACCURATETIME");
  1933. // Flush the material system before timing this model:
  1934. hLock = g_pMaterialSystem->Lock();
  1935. g_pMaterialSystem->Flush(true);
  1936. }
  1937. if ( pResults )
  1938. {
  1939. pResults->m_RenderTime.Start();
  1940. }
  1941. FlexWeights_t flex;
  1942. flex.m_pFlexWeights = pFlexWeights ? pFlexWeights : s_pZeroFlexWeights;
  1943. flex.m_pFlexDelayedWeights = pFlexDelayedWeights ? pFlexDelayedWeights : flex.m_pFlexWeights;
  1944. ICallQueue *pCallQueue = pRenderContext->GetCallQueue();
  1945. if ( !pCallQueue || studio_queue_mode.GetInt() == 0 )
  1946. {
  1947. g_pStudioRenderImp->DrawModel( info, m_RC, pBoneToWorld, flex, flags );
  1948. }
  1949. else
  1950. {
  1951. CMatRenderData<matrix3x4_t> rdMatrix( pRenderContext, info.m_pStudioHdr->numbones, pBoneToWorld );
  1952. CMatRenderData<float> rdFlex( pRenderContext );
  1953. CMatRenderData<float> rdFlexDelayed( pRenderContext );
  1954. InvokeBindProxies( info );
  1955. pBoneToWorld = rdMatrix.Base();
  1956. if ( info.m_pStudioHdr->numflexdesc != 0 )
  1957. {
  1958. rdFlex.Lock( info.m_pStudioHdr->numflexdesc, flex.m_pFlexWeights );
  1959. flex.m_pFlexWeights = rdFlex.Base();
  1960. if ( !pFlexDelayedWeights )
  1961. {
  1962. flex.m_pFlexDelayedWeights = flex.m_pFlexWeights;
  1963. }
  1964. else
  1965. {
  1966. rdFlexDelayed.Lock( info.m_pStudioHdr->numflexdesc, flex.m_pFlexDelayedWeights );
  1967. flex.m_pFlexDelayedWeights = rdFlexDelayed.Base();
  1968. }
  1969. }
  1970. pCallQueue->QueueCall( g_pStudioRenderImp, &CStudioRender::DrawModel, info, m_RC, pBoneToWorld, flex, flags );
  1971. }
  1972. if( flags & STUDIORENDER_DRAW_ACCURATETIME )
  1973. {
  1974. VPROF( "STUDIORENDER_DRAW_ACCURATETIME" );
  1975. // Make sure this model is completely drawn before ending the timer:
  1976. g_pMaterialSystem->Flush(true);
  1977. g_pMaterialSystem->Flush(true);
  1978. g_pMaterialSystem->Unlock( hLock );
  1979. }
  1980. if ( pResults )
  1981. {
  1982. pResults->m_RenderTime.End();
  1983. if( flags & STUDIORENDER_DRAW_GET_PERF_STATS )
  1984. {
  1985. GetPerfStats( pResults, info, 0 );
  1986. }
  1987. }
  1988. }
  1989. void CStudioRenderContext::DrawModelArray( const DrawModelInfo_t &drawInfo, int arrayCount, model_array_instance_t *pInstanceData, int instanceStride, int flags )
  1990. {
  1991. // UNDONE: Support queue mode?
  1992. g_pStudioRenderImp->DrawModelArray( drawInfo, m_RC, arrayCount, pInstanceData, instanceStride, flags );
  1993. }
  1994. //-----------------------------------------------------------------------------
  1995. // Methods related to rendering static props
  1996. //-----------------------------------------------------------------------------
  1997. void CStudioRenderContext::DrawModelStaticProp( const DrawModelInfo_t& info, const matrix3x4_t &modelToWorld, int flags )
  1998. {
  1999. if ( info.m_Lod < info.m_pHardwareData->m_RootLOD )
  2000. {
  2001. const_cast< DrawModelInfo_t* >( &info )->m_Lod = info.m_pHardwareData->m_RootLOD;
  2002. }
  2003. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  2004. ICallQueue *pCallQueue = pRenderContext->GetCallQueue();
  2005. if ( !pCallQueue || studio_queue_mode.GetInt() == 0 )
  2006. {
  2007. g_pStudioRenderImp->DrawModelStaticProp( info, m_RC, modelToWorld, flags );
  2008. }
  2009. else
  2010. {
  2011. InvokeBindProxies( info );
  2012. pCallQueue->QueueCall( g_pStudioRenderImp, &CStudioRender::DrawModelStaticProp, info, m_RC, modelToWorld, flags );
  2013. }
  2014. }
  2015. void CStudioRenderContext::DrawStaticPropDecals( const DrawModelInfo_t &info, const matrix3x4_t &modelToWorld )
  2016. {
  2017. QUEUE_STUDIORENDER_CALL( DrawStaticPropDecals, CStudioRender, g_pStudioRenderImp, info, m_RC, modelToWorld );
  2018. }
  2019. void CStudioRenderContext::DrawStaticPropShadows( const DrawModelInfo_t &info, const matrix3x4_t &modelToWorld, int flags )
  2020. {
  2021. QUEUE_STUDIORENDER_CALL( DrawStaticPropShadows, CStudioRender, g_pStudioRenderImp, info, m_RC, modelToWorld, flags );
  2022. }
  2023. //-----------------------------------------------------------------------------
  2024. // Methods related to shadows
  2025. //-----------------------------------------------------------------------------
  2026. void CStudioRenderContext::AddShadow( IMaterial* pMaterial, void* pProxyData,
  2027. FlashlightState_t *pFlashlightState, VMatrix *pWorldToTexture, ITexture *pFlashlightDepthTexture )
  2028. {
  2029. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  2030. ICallQueue *pCallQueue = pRenderContext->GetCallQueue();
  2031. if ( !pCallQueue || studio_queue_mode.GetInt() == 0 )
  2032. {
  2033. g_pStudioRenderImp->AddShadow( pMaterial, pProxyData, pFlashlightState, pWorldToTexture, pFlashlightDepthTexture );
  2034. }
  2035. else
  2036. {
  2037. // NOTE: We don't need to make proxies work, because proxies are only ever used
  2038. // when casting shadows onto props, which we don't do..that feature is disabled.
  2039. // When casting flashlights onto mdls, which we *do* use, the proxy is NULL.
  2040. Assert( pProxyData == NULL );
  2041. if ( pProxyData != NULL )
  2042. {
  2043. Warning( "Cannot call CStudioRenderContext::AddShadows w/ proxies in queued mode!\n" );
  2044. return;
  2045. }
  2046. CMatRenderData< FlashlightState_t > rdFlashlight( pRenderContext, 1, pFlashlightState );
  2047. CMatRenderData< VMatrix > rdMatrix( pRenderContext, 1, pWorldToTexture );
  2048. pCallQueue->QueueCall( g_pStudioRenderImp, &CStudioRender::AddShadow, pMaterial,
  2049. (void*)NULL, rdFlashlight.Base(), rdMatrix.Base(), pFlashlightDepthTexture );
  2050. }
  2051. }
  2052. void CStudioRenderContext::ClearAllShadows()
  2053. {
  2054. QUEUE_STUDIORENDER_CALL( ClearAllShadows, CStudioRender, g_pStudioRenderImp );
  2055. }
  2056. //-----------------------------------------------------------------------------
  2057. // Methods related to decals
  2058. //-----------------------------------------------------------------------------
  2059. void CStudioRenderContext::DestroyDecalList( StudioDecalHandle_t handle )
  2060. {
  2061. QUEUE_STUDIORENDER_CALL( DestroyDecalList, CStudioRender, g_pStudioRenderImp, handle );
  2062. }
  2063. void CStudioRenderContext::AddDecal( StudioDecalHandle_t handle, studiohdr_t *pStudioHdr,
  2064. matrix3x4_t *pBoneToWorld, const Ray_t& ray, const Vector& decalUp,
  2065. IMaterial* pDecalMaterial, float radius, int body, bool noPokethru, int maxLODToDecal )
  2066. {
  2067. // This substition always has to be done in the main thread, so do it here.
  2068. pDecalMaterial = GetModelSpecificDecalMaterial( pDecalMaterial );
  2069. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  2070. Assert( pRenderContext->IsRenderData( pBoneToWorld ) );
  2071. QUEUE_STUDIORENDER_CALL_RC( AddDecal, CStudioRender, g_pStudioRenderImp, pRenderContext,
  2072. handle, m_RC, pBoneToWorld, pStudioHdr, ray, decalUp, pDecalMaterial, radius,
  2073. body, noPokethru, maxLODToDecal );
  2074. }
  2075. // Function to do replacement because we always need to do this from the main thread.
  2076. IMaterial* GetModelSpecificDecalMaterial( IMaterial* pDecalMaterial )
  2077. {
  2078. Assert( ThreadInMainThread() );
  2079. // Since we're adding this to a studio model, check the decal to see if
  2080. // there's an alternate form used for static props...
  2081. bool found;
  2082. IMaterialVar* pModelMaterialVar = pDecalMaterial->FindVar( "$modelmaterial", &found, false );
  2083. if ( found )
  2084. {
  2085. IMaterial* pModelMaterial = g_pMaterialSystem->FindMaterial( pModelMaterialVar->GetStringValue(), TEXTURE_GROUP_DECAL, false );
  2086. if ( !IsErrorMaterial( pModelMaterial ) )
  2087. {
  2088. return pModelMaterial;
  2089. }
  2090. }
  2091. return pDecalMaterial;
  2092. }