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

2826 lines
98 KiB

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