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.

1786 lines
68 KiB

  1. //===== Copyright (c) 1996-2007, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $Revision: $
  6. // $NoKeywords: $
  7. //
  8. // Fast path model rendering
  9. //
  10. //===========================================================================//
  11. #include "cbase.h"
  12. #include "modelrendersystem.h"
  13. #include "model_types.h"
  14. #include "iviewrender.h"
  15. #include "tier3/tier3.h"
  16. #undef max
  17. #undef min
  18. #include <algorithm>
  19. #include "tier1/memstack.h"
  20. #include "engine/ivdebugoverlay.h"
  21. #include "shaderapi/ishaderapi.h"
  22. #include "materialsystem/MaterialSystemUtil.h"
  23. #include "engine_model_client.h"
  24. #include "tier0/vprof.h"
  25. // NOTE: This has to be the last file included!
  26. #include "tier0/memdbgon.h"
  27. //-----------------------------------------------------------------------------
  28. // Convars defined by other systems
  29. //-----------------------------------------------------------------------------
  30. ConVar r_lod( "r_lod", "-1" );
  31. ConVar r_shadowlod( "r_shadowlod", "-1" );
  32. ConVar r_drawmodellightorigin( "r_DrawModelLightOrigin", "0", FCVAR_CHEAT );
  33. extern ConVar g_CV_FlexSmooth;
  34. extern ConVar r_fastzreject;
  35. //-----------------------------------------------------------------------------
  36. // The client leaf system
  37. //-----------------------------------------------------------------------------
  38. class CModelRenderSystem : public CAutoGameSystem, public IModelRenderSystem
  39. {
  40. // Methods of IModelRenderSystem
  41. public:
  42. virtual void DrawModels( ModelRenderSystemData_t *pEntities, int nCount, ModelRenderMode_t renderMode, bool bShadowDepthIncludeTranslucentMaterials = false );
  43. virtual void DrawBrushModels( ModelRenderSystemData_t *pModels, int nCount, ModelRenderMode_t renderMode );
  44. virtual void ComputeTranslucentRenderData( ModelRenderSystemData_t *pModels, int nCount, TranslucentInstanceRenderData_t *pRenderData, TranslucentTempData_t *pTempData );
  45. virtual void CleanupTranslucentTempData( TranslucentTempData_t *pTempData );
  46. virtual IMaterial *GetFastPathColorMaterial() { return m_DebugMaterial; }
  47. // Methods of IGameSystem
  48. public:
  49. virtual void LevelInitPostEntity();
  50. virtual void LevelShutdownPreEntity();
  51. // Other public methods
  52. public:
  53. CModelRenderSystem();
  54. virtual ~CModelRenderSystem();
  55. private:
  56. struct ModelListNode_t
  57. {
  58. ModelRenderSystemData_t m_Entry;
  59. int32 m_nInitialListIndex : 24;
  60. uint32 m_bBoneMerge : 1;
  61. int32 m_nLOD : 7;
  62. ShaderStencilState_t *m_pStencilState;
  63. ModelListNode_t *m_pNext;
  64. };
  65. struct RenderModelInfo_t : public StudioArrayInstanceData_t
  66. {
  67. ModelRenderSystemData_t m_Entry;
  68. ModelInstanceHandle_t m_hInstance;
  69. matrix3x4a_t* m_pBoneToWorld;
  70. uint32 m_nInitialListIndex : 24;
  71. uint32 m_bSetupBonesOnly : 1;
  72. uint32 m_bBoneMerge : 1;
  73. };
  74. struct ModelListByType_t : public StudioModelArrayInfo_t
  75. {
  76. RenderableLightingModel_t m_nLightingModel;
  77. const model_t *m_pModel;
  78. ModelListNode_t *m_pFirstNode;
  79. int m_nCount;
  80. int m_nSetupBoneCount;
  81. uint32 m_nParentDepth : 31;
  82. uint32 m_bWantsStencil : 1;
  83. RenderModelInfo_t *m_pRenderModels;
  84. ModelListByType_t *m_pNextLightingModel;
  85. // speed up std::sort by implementing these
  86. ModelListByType_t &operator=( const ModelListByType_t &rhs )
  87. {
  88. memcpy( this, &rhs, sizeof( ModelListByType_t ) );
  89. return *this;
  90. }
  91. ModelListByType_t() {}
  92. ModelListByType_t( const ModelListByType_t &rhs )
  93. {
  94. memcpy( this, &rhs, sizeof( ModelListByType_t ) );
  95. }
  96. };
  97. struct BrushModelList_t
  98. {
  99. ModelRenderSystemData_t m_Entry;
  100. uint32 m_nParentDepth : 31;
  101. uint32 m_bWantsStencil : 1;
  102. BrushArrayInstanceData_t *m_pInstanceData;
  103. BrushModelList_t() {}
  104. };
  105. struct LightingList_t
  106. {
  107. ModelListByType_t *m_pFirstModel;
  108. int m_nCount;
  109. int m_nTotalModelCount;
  110. };
  111. private:
  112. int BucketModelsByMDL( ModelListByType_t *pModelList, ModelListNode_t *pModelListNodes, ModelRenderSystemData_t *pEntities, int nCount, ModelRenderMode_t renderMode, int *pModelsRenderingStencilCountOut );
  113. uint AddModelToLists( int &nModelTypeCount, ModelListByType_t *pModelList, int &nModelNodeCount, ModelListNode_t *pModelListNodes, int nDataIndex, ModelRenderSystemData_t &data, ModelRenderMode_t renderMode );
  114. void SortBucketsByDependency( int nModelTypeCount, ModelListByType_t *pModelList, LightingList_t *pLightingList );
  115. void ComputeModelLODs( int nModelTypeCount, ModelListByType_t *pModelList, ModelListNode_t *pModelListNode, ModelRenderMode_t renderMode );
  116. void SlamModelLODs( int nLOD, int nModelTypeCount, ModelListByType_t *pModelList, ModelListNode_t *pModelListNode );
  117. void SortModels( RenderModelInfo_t *pSortedModelListNode, int nListTotal, int nModelTypeCount, ModelListByType_t *pModelList, ModelListNode_t *pModelListNode );
  118. static bool SortLessFunc( const RenderModelInfo_t &left, const RenderModelInfo_t &right );
  119. void SetupBones( int nModelTypeCount, ModelListByType_t *pModelList );
  120. void SetupFlexes( int nModelTypeCount, ModelListByType_t *pModelList );
  121. void ComputeLightingOrigin( ModelListByType_t &list, LightingQuery_t *pLightingQuery, int nQueryStride );
  122. int SetupLighting( LightingList_t *pLightingList, int nModelTypeCount, ModelListByType_t *pModelList, DataCacheHandle_t *pColorMeshHandles, ModelRenderMode_t renderMode );
  123. void RenderModels( StudioModelArrayInfo2_t *pInfo, int nModelTypeCount, ModelListByType_t *pModelList, int nTotalModelCount, ModelRenderMode_t renderMode, bool bShadowDepthIncludeTranslucentMaterials = false );
  124. void SetupTranslucentData( int nModelTypeCount, ModelListByType_t *pModelList, int nTotalModelCount, TranslucentInstanceRenderData_t *pRenderData );
  125. void SetupFlashlightsAndDecals( StudioModelArrayInfo2_t *pInfo, int nModelTypeCount, ModelListByType_t *pModelList, int nTotalModelCount, RenderModelInfo_t *pModelInfo, ModelRenderMode_t renderMode );
  126. void SetupPerInstanceColorModulation( int nModelTypeCount, ModelListByType_t *pModelList );
  127. void DebugDrawLightingOrigin( const ModelListByType_t &list, const RenderModelInfo_t &model );
  128. int BuildLightingList( ModelListByType_t **ppLists, unsigned char *pFlags, int *pTotalModels, const LightingList_t &lightingList );
  129. int SetupStaticPropLighting( LightingList_t &lightingList, DataCacheHandle_t *pColorMeshHandles );
  130. void SetupStandardLighting( LightingList_t &lightingList );
  131. int SetupPhysicsPropLighting( LightingList_t &lightingList, DataCacheHandle_t *pColorMeshHandles );
  132. void HookUpStaticLightingState( int nCount, ModelListByType_t **ppLists, unsigned char *pFlags, ITexture **ppEnvCubemap, MaterialLightingState_t *pLightingState, MaterialLightingState_t *pDecalLightingState, ColorMeshInfo_t **ppColorMeshInfo );
  133. void RenderDebugOverlays( int nModelTypeCount, ModelListByType_t *pModelList, ModelRenderMode_t renderMode );
  134. void RenderVCollideDebugOverlay( int nModelTypeCount, ModelListByType_t *pModelList );
  135. void RenderBBoxDebugOverlay( int nModelTypeCount, ModelListByType_t *pModelList );
  136. int ComputeParentDepth( C_BaseEntity *pEnt );
  137. static bool DependencySortLessFunc( const ModelListByType_t &left, const ModelListByType_t &right );
  138. static bool StencilSortLessFunc( const ModelListByType_t &left, const ModelListByType_t &right );
  139. // Methods related to fastpath brush model rendering
  140. void AddBrushModelToList( int nInitialListIndex, ModelRenderSystemData_t &data, ModelRenderMode_t renderMode,
  141. BrushArrayInstanceData_t &instance, matrix3x4a_t &brushToWorld );
  142. void SetupPerInstanceColorModulation( int nCount, ModelRenderSystemData_t *pModels, BrushArrayInstanceData_t *pInstanceData, ModelRenderMode_t renderMode );
  143. CMemoryStack m_BoneToWorld;
  144. CTextureReference m_DefaultCubemap;
  145. CMaterialReference m_DebugMaterial;
  146. CMaterialReference m_ShadowBuild;
  147. IMatRenderContext *m_pRenderContext;
  148. CUtlMemoryFixedGrowable< BrushModelList_t, 512 > m_BrushModelList;
  149. int m_nColorMeshHandles;
  150. int m_nModelTypeCount;
  151. int m_nTotalModelCount;
  152. bool m_bShadowDepth;
  153. bool m_bHasInstanceData;
  154. };
  155. //-----------------------------------------------------------------------------
  156. // Singleton accessor
  157. //-----------------------------------------------------------------------------
  158. static CModelRenderSystem s_ModelRenderSystem;
  159. IModelRenderSystem *g_pModelRenderSystem = &s_ModelRenderSystem;
  160. //-----------------------------------------------------------------------------
  161. // Constructor, destructor
  162. //-----------------------------------------------------------------------------
  163. CModelRenderSystem::CModelRenderSystem()
  164. {
  165. m_bHasInstanceData = false;
  166. m_BoneToWorld.Init( "CModelRenderSystem::m_BoneToWorld", 1 * 1024 * 1024, 32 * 1024, 0, 32 );
  167. }
  168. CModelRenderSystem::~CModelRenderSystem()
  169. {
  170. m_BoneToWorld.Term();
  171. }
  172. //-----------------------------------------------------------------------------
  173. // Level init, shutdown
  174. //-----------------------------------------------------------------------------
  175. void CModelRenderSystem::LevelInitPostEntity()
  176. {
  177. m_DefaultCubemap.Init( "engine/defaultcubemap", TEXTURE_GROUP_CUBE_MAP );
  178. m_DebugMaterial.Init( "debug/debugempty", TEXTURE_GROUP_OTHER );
  179. m_ShadowBuild.Init( "engine/shadowbuild", TEXTURE_GROUP_OTHER );
  180. }
  181. void CModelRenderSystem::LevelShutdownPreEntity()
  182. {
  183. m_DefaultCubemap.Shutdown();
  184. m_DebugMaterial.Shutdown();
  185. m_ShadowBuild.Shutdown();
  186. }
  187. //-----------------------------------------------------------------------------
  188. // returns bone setup dependency depth
  189. //-----------------------------------------------------------------------------
  190. int CModelRenderSystem::ComputeParentDepth( C_BaseEntity *pEnt )
  191. {
  192. if ( !pEnt )
  193. return 0;
  194. int nDepth = 0;
  195. while ( pEnt->IsFollowingEntity() || ( pEnt->GetMoveParent() && pEnt->GetParentAttachment() > 0 ) )
  196. {
  197. ++nDepth;
  198. pEnt = pEnt->GetMoveParent();
  199. }
  200. return nDepth;
  201. }
  202. //-----------------------------------------------------------------------------
  203. // Adds a model to the appropriate render lists
  204. //-----------------------------------------------------------------------------
  205. uint CModelRenderSystem::AddModelToLists( int &nModelTypeCountInOut, ModelListByType_t *pModelList,
  206. int &nModelNodeCount, ModelListNode_t *pModelListNodes, int nInitialListIndex, ModelRenderSystemData_t &data, ModelRenderMode_t renderMode )
  207. {
  208. int nModelTypeCount = nModelTypeCountInOut;
  209. // NOTE: we actually are bucketing both by model + also by lighting model
  210. // Bucketing by lighting model is not strictly necessary, but doing so
  211. // simplifies the code a lot in exchange for having two batches if the
  212. // same model is used but a different lighting model, something that could
  213. // theoretically happen if a static prop + physics prop use the same .mdl
  214. // My thought is that even if this split happens, it will be rare, and
  215. // we still will get a lot of sharing.
  216. // L4D2: We'll also bucket by whether the model renders stencil or not.
  217. // This allows us to keep stenciling models in the fastpath but group them together
  218. // to be rendered AFTER the 360 Z prepass ends. (360 doesn't allow stencil rendering
  219. // during the Z prepass).
  220. const model_t *pModel = data.m_pRenderable->GetModel();
  221. Assert( modelinfo->GetModelType( pModel ) == mod_studio );
  222. // PerfectWorld build needs to not render certain models from the exclude list, so just don't add those models to any lists
  223. if ( EngineModelClientFlags( pModel ) & ENGINE_MODEL_CLIENT_MODELFLAG_RENDER_DISABLED )
  224. return 0; // Such models don't render anywhere and don't need stencil
  225. RenderableLightingModel_t nLightingModel = LIGHTING_MODEL_NONE;
  226. uint bWantsStencil = 0;
  227. ShaderStencilState_t tempStencil;
  228. if ( data.m_pModelRenderable )
  229. {
  230. data.m_pModelRenderable->GetRenderData( &nLightingModel, MODEL_DATA_LIGHTING_MODEL );
  231. if ( renderMode == MODEL_RENDER_MODE_NORMAL )
  232. {
  233. // I considered making a MODEL_DATA_STENCIL_ENABLE renderdata type that would only return a bool
  234. // if stencil was enabled, but it turns out most of the work for MODEL_DATA_STENCIL is computing
  235. // that bool, so pulling this out into a separate piece didn't turn out to be a perf win.
  236. bWantsStencil = data.m_pModelRenderable->GetRenderData( &tempStencil, MODEL_DATA_STENCIL ) ? 1 : 0;
  237. }
  238. }
  239. else
  240. {
  241. ExecuteOnce( DevWarning( "data.m_pModelRenderable is NULL for %s\n", modelinfo->GetModelName( pModel ) ) );
  242. }
  243. int j;
  244. for ( j = 0; j < nModelTypeCount; ++j )
  245. {
  246. if ( pModelList[j].m_pModel == pModel &&
  247. pModelList[j].m_nLightingModel == nLightingModel &&
  248. pModelList[j].m_bWantsStencil == bWantsStencil )
  249. break;
  250. }
  251. if ( j == nModelTypeCount )
  252. {
  253. // Bail if we're rendering into shadow depth map and this model doesn't cast shadows
  254. // NOTE: if m_pModelRenderable is NULL, it's a dependent bone setup so we need to keep it
  255. studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pModel );
  256. if ( ( renderMode != MODEL_RENDER_MODE_NORMAL ) && data.m_pModelRenderable && ( ( pStudioHdr->flags & STUDIOHDR_FLAGS_DO_NOT_CAST_SHADOWS ) != 0 ) )
  257. {
  258. return bWantsStencil;
  259. }
  260. MDLHandle_t hMDL = modelinfo->GetCacheHandle( pModel );
  261. studiohwdata_t *pHardwareData = g_pMDLCache->GetHardwareData( hMDL );
  262. // This can occur if there was an error loading the model; for instance
  263. // if the vtx and mdl are out of sync.
  264. if ( !pHardwareData || !pHardwareData->m_pLODs )
  265. return bWantsStencil;
  266. ModelListByType_t &list = pModelList[ nModelTypeCount ];
  267. list.m_pModel = pModel;
  268. list.m_nLightingModel = nLightingModel;
  269. list.m_bWantsStencil = bWantsStencil;
  270. list.m_pStudioHdr = pStudioHdr;
  271. list.m_pHardwareData = pHardwareData;
  272. list.m_nFlashlightCount = 0;
  273. list.m_pFlashlights = NULL;
  274. list.m_nCount = 0;
  275. list.m_pFirstNode = 0;
  276. list.m_pRenderModels = 0;
  277. list.m_nParentDepth = 0;
  278. list.m_pNextLightingModel = NULL;
  279. j = nModelTypeCount++;
  280. }
  281. C_BaseEntity *pEntity = data.m_pRenderable->GetIClientUnknown()->GetBaseEntity();
  282. uint nParentDepth = ComputeParentDepth( pEntity );
  283. ModelListByType_t &list = pModelList[ j ];
  284. ModelListNode_t &node = pModelListNodes[ nModelNodeCount++ ];
  285. node.m_Entry = data;
  286. node.m_nInitialListIndex = nInitialListIndex;
  287. node.m_bBoneMerge = pEntity && pEntity->IsEffectActive( EF_BONEMERGE );
  288. if ( bWantsStencil && ( renderMode == MODEL_RENDER_MODE_NORMAL ) )
  289. {
  290. CMatRenderData< ShaderStencilState_t > rdStencil( m_pRenderContext, 1 );
  291. memcpy( &rdStencil[0], &tempStencil, sizeof( tempStencil ) );
  292. node.m_pStencilState = &rdStencil[0];
  293. }
  294. else
  295. {
  296. node.m_pStencilState = NULL;
  297. }
  298. node.m_pNext = list.m_pFirstNode;
  299. list.m_nParentDepth = MAX( list.m_nParentDepth, nParentDepth );
  300. list.m_pFirstNode = &node;
  301. ++list.m_nCount;
  302. nModelTypeCountInOut = nModelTypeCount;
  303. return bWantsStencil;
  304. }
  305. //-----------------------------------------------------------------------------
  306. // bucket models by type, return # of unique types
  307. //-----------------------------------------------------------------------------
  308. int CModelRenderSystem::BucketModelsByMDL( ModelListByType_t *pModelList, ModelListNode_t *pModelListNodes, ModelRenderSystemData_t *pEntities, int nCount, ModelRenderMode_t renderMode,
  309. int *pModelsRenderingStencilCountOut )
  310. {
  311. int nModelTypeCount = 0;
  312. int nModelNodeCount = 0;
  313. int nModelWantingStencil = 0;
  314. for ( int i = 0; i < nCount; ++i )
  315. {
  316. nModelWantingStencil += AddModelToLists( nModelTypeCount, pModelList, nModelNodeCount, pModelListNodes, i, pEntities[i], renderMode );
  317. }
  318. *pModelsRenderingStencilCountOut = nModelWantingStencil;
  319. return nModelTypeCount;
  320. }
  321. //-----------------------------------------------------------------------------
  322. // Sort model types function
  323. //-----------------------------------------------------------------------------
  324. inline bool CModelRenderSystem::DependencySortLessFunc( const ModelListByType_t &left, const ModelListByType_t &right )
  325. {
  326. // Ensures bone setup occurs in the correct order
  327. if ( left.m_nParentDepth != right.m_nParentDepth )
  328. return left.m_nParentDepth < right.m_nParentDepth;
  329. // Ensure stenciling models are at the end of the list.
  330. // This doesn't guarantee that stencil stuff is at the end because parent depth trumps it,
  331. // so we'll have to sort again before rendering.
  332. if ( left.m_bWantsStencil != right.m_bWantsStencil )
  333. {
  334. return left.m_bWantsStencil < right.m_bWantsStencil;
  335. }
  336. // Keep same models with different lighting types together
  337. return left.m_pModel < right.m_pModel;
  338. }
  339. //-----------------------------------------------------------------------------
  340. // Sorts so that bone setup occurs in the appropriate order (parents set up first)
  341. //-----------------------------------------------------------------------------
  342. void CModelRenderSystem::SortBucketsByDependency( int nModelTypeCount, ModelListByType_t *pModelList, LightingList_t *pLightingList )
  343. {
  344. std::sort( pModelList, pModelList + nModelTypeCount, DependencySortLessFunc );
  345. // Assign models to the appropriate lighting list
  346. for ( int i = nModelTypeCount; --i >= 0; )
  347. {
  348. ModelListByType_t &list = pModelList[ i ];
  349. // Hook into lighting list
  350. if ( list.m_nLightingModel == LIGHTING_MODEL_NONE )
  351. continue;
  352. LightingList_t &lightList = pLightingList[ list.m_nLightingModel ];
  353. list.m_pNextLightingModel = lightList.m_pFirstModel;
  354. lightList.m_pFirstModel = &list;
  355. ++lightList.m_nCount;
  356. lightList.m_nTotalModelCount += list.m_nCount;
  357. }
  358. #ifdef _DEBUG
  359. // Don't want to allow some MDLs of type A to depend on MDLs of type B
  360. // and other MDLS of type B to depend on type A because that would
  361. // dramatically increase complexity of the system here. With this assumption,
  362. // we can always have all models of the same type be set up at the same time,
  363. // also improving cache efficiency.
  364. for ( int i =0; i < nModelTypeCount; ++i )
  365. {
  366. ModelListByType_t &list = pModelList[ i ];
  367. if ( list.m_nParentDepth == 0 )
  368. continue;
  369. for( ModelListNode_t *pNode = list.m_pFirstNode; pNode; pNode = pNode->m_pNext )
  370. {
  371. C_BaseEntity *pEnt = pNode->m_Entry.m_pRenderable->GetIClientUnknown()->GetBaseEntity();
  372. if ( !pEnt )
  373. continue;
  374. C_BaseEntity *pTest = pEnt;
  375. while ( pEnt->IsFollowingEntity() || ( pEnt->GetMoveParent() && pEnt->GetParentAttachment() > 0 ) )
  376. {
  377. pEnt = pEnt->GetMoveParent();
  378. const model_t *pModel = pEnt->GetModel();
  379. bool bFound = false;
  380. for ( int j = 0; j < nModelTypeCount; ++j )
  381. {
  382. if ( pModelList[j].m_pModel != pModel )
  383. continue;
  384. if ( pModelList[j].m_nParentDepth >= list.m_nParentDepth )
  385. {
  386. // NOTE: GetClassname() stores the name in a global, hence need to do the warning on 2 lines
  387. Warning( "Bone setup dependency ordering issue [ent %s ", pTest->GetClassname() );
  388. Warning( " depends on ent %s]!\n", pEnt->GetClassname() );
  389. }
  390. for( ModelListNode_t *pParentNode = pModelList[j].m_pFirstNode; pParentNode; pParentNode = pParentNode->m_pNext )
  391. {
  392. if ( pParentNode->m_Entry.m_pRenderable == pEnt->GetClientRenderable() )
  393. {
  394. bFound = true;
  395. break;
  396. }
  397. }
  398. }
  399. if ( !bFound )
  400. {
  401. // NOTE: GetClassname() stores the name in a global, hence need to do the warning on 2 lines
  402. // Warning( "Missing bone setup dependency [ent %s ", pTest->GetClassname() );
  403. // Warning( "depends on ent %s]!\n", pEnt->GetClassname() );
  404. }
  405. }
  406. }
  407. }
  408. #endif
  409. }
  410. //-----------------------------------------------------------------------------
  411. // Slam model LODs to the appropriate level
  412. //-----------------------------------------------------------------------------
  413. void CModelRenderSystem::SlamModelLODs( int nLOD, int nModelTypeCount, ModelListByType_t *pModelList, ModelListNode_t *pModelListNode )
  414. {
  415. for ( int i = 0; i < nModelTypeCount; ++i )
  416. {
  417. ModelListByType_t &list = pModelList[i];
  418. int nLODCount = list.m_pHardwareData->m_NumLODs;
  419. int nRootLOD = list.m_pHardwareData->m_RootLOD;
  420. bool bHasShadowLOD = ( list.m_pStudioHdr->flags & STUDIOHDR_FLAGS_HASSHADOWLOD ) != 0;
  421. int nMaxLOD = bHasShadowLOD ? nLODCount - 2 : nLODCount - 1;
  422. for ( ModelListNode_t *pNode = list.m_pFirstNode; pNode; pNode = pNode->m_pNext )
  423. {
  424. pNode->m_nLOD = clamp( nLOD, nRootLOD, nMaxLOD );
  425. }
  426. }
  427. }
  428. //-----------------------------------------------------------------------------
  429. // Compute model LODs
  430. //-----------------------------------------------------------------------------
  431. void CModelRenderSystem::ComputeModelLODs( int nModelTypeCount, ModelListByType_t *pModelList, ModelListNode_t *pModelListNode, ModelRenderMode_t renderMode )
  432. {
  433. if ( renderMode == MODEL_RENDER_MODE_RTT_SHADOWS )
  434. {
  435. // Slam to shadow lod
  436. //int nShadowLodConVar = r_shadowlod.GetInt();
  437. for ( int i = 0; i < nModelTypeCount; ++i )
  438. {
  439. ModelListByType_t &list = pModelList[i];
  440. int nLODCount = list.m_pHardwareData->m_NumLODs;
  441. //int nRootLOD = list.m_pHardwareData->m_RootLOD;
  442. int nMaxLOD = nLODCount - 1;
  443. for ( ModelListNode_t *pNode = list.m_pFirstNode; pNode; pNode = pNode->m_pNext )
  444. {
  445. // Just always use the lowest LOD right now
  446. //int nLOD = nShadowLodConVar;
  447. //pNode->m_nLOD = clamp( nLOD, nRootLOD, nMaxLOD );
  448. pNode->m_nLOD = nMaxLOD;
  449. }
  450. }
  451. return;
  452. }
  453. #ifdef CSTRIKE15
  454. // Always slam r_lod to 0 for CS:GO.
  455. int nLOD = 0;
  456. #else
  457. int nLOD = r_lod.GetInt();
  458. #endif
  459. if ( nLOD >= 0 )
  460. {
  461. SlamModelLODs( nLOD, nModelTypeCount, pModelList, pModelListNode );
  462. return;
  463. }
  464. ScreenSizeComputeInfo_t info;
  465. ComputeScreenSizeInfo( &info );
  466. for ( int i = 0; i < nModelTypeCount; ++i )
  467. {
  468. ModelListByType_t &list = pModelList[i];
  469. int nLODCount = list.m_pHardwareData->m_NumLODs;
  470. int nRootLOD = list.m_pHardwareData->m_RootLOD;
  471. int nMaxLOD = nLODCount - 1;
  472. for ( ModelListNode_t *pNode = list.m_pFirstNode; pNode; pNode = pNode->m_pNext )
  473. {
  474. // FIXME: SIMD-ize, eliminate all extraneous calls (get view render state outside of loop)
  475. const Vector &vecRenderOrigin = pNode->m_Entry.m_pRenderable->GetRenderOrigin();
  476. // NOTE: The 2.0 is for legacy reasons
  477. float flScreenSize = 2.0f * ComputeScreenSize( vecRenderOrigin, 0.5f, info );
  478. float flMetric = list.m_pHardwareData->LODMetric( flScreenSize );
  479. nLOD = list.m_pHardwareData->GetLODForMetric( flMetric );
  480. pNode->m_nLOD = clamp( nLOD, nRootLOD, nMaxLOD );
  481. }
  482. }
  483. }
  484. //-----------------------------------------------------------------------------
  485. // Sort models function
  486. //-----------------------------------------------------------------------------
  487. inline bool CModelRenderSystem::SortLessFunc( const RenderModelInfo_t &left, const RenderModelInfo_t &right )
  488. {
  489. // NOTE: Could do this, but it is not faster, because the cost of an integer multiply is about three
  490. // times that of a branch penalty:
  491. // int nLeft = left.m_nSkin * 1000000 + left.m_nLOD * 1000 + left.m_nBody;
  492. // int nRight = right.m_nSkin * 1000000 + right.m_nLOD * 1000 + right.m_nBody;
  493. // return nLeft > nRight;
  494. if ( left.m_bSetupBonesOnly != right.m_bSetupBonesOnly )
  495. return !left.m_bSetupBonesOnly;
  496. if ( left.m_nSkin != right.m_nSkin )
  497. return left.m_nSkin > right.m_nSkin;
  498. if ( left.m_nLOD != right.m_nLOD )
  499. return left.m_nLOD > right.m_nLOD;
  500. return left.m_nBody > right.m_nBody;
  501. }
  502. //-----------------------------------------------------------------------------
  503. // Sort models
  504. //-----------------------------------------------------------------------------
  505. void CModelRenderSystem::SortModels( RenderModelInfo_t *pRenderModelInfo, int nListTotal,
  506. int nModelTypeCount, ModelListByType_t *pModelList, ModelListNode_t *pModelListNode )
  507. {
  508. // First place them in arrays
  509. Plat_FastMemset( pRenderModelInfo, 0, sizeof(RenderModelInfo_t) * nListTotal );
  510. RenderModelInfo_t *pCurrInfo = pRenderModelInfo;
  511. for ( int i = 0; i < nModelTypeCount; ++i )
  512. {
  513. ModelListByType_t &list = pModelList[i];
  514. list.m_pRenderModels = pCurrInfo;
  515. list.m_nSetupBoneCount = 0;
  516. for ( ModelListNode_t *pNode = list.m_pFirstNode; pNode; pNode = pNode->m_pNext )
  517. {
  518. pCurrInfo->m_Entry = pNode->m_Entry;
  519. pCurrInfo->m_nLOD = pNode->m_nLOD;
  520. pCurrInfo->m_nSkin = pNode->m_Entry.m_pRenderable->GetSkin();
  521. pCurrInfo->m_nBody = pNode->m_Entry.m_pRenderable->GetBody();
  522. pCurrInfo->m_hInstance = pNode->m_Entry.m_pRenderable->GetModelInstance();
  523. pCurrInfo->m_Decals = STUDIORENDER_DECAL_INVALID;
  524. pCurrInfo->m_nInitialListIndex = pNode->m_nInitialListIndex;
  525. pCurrInfo->m_bBoneMerge = pNode->m_bBoneMerge;
  526. pCurrInfo->m_bSetupBonesOnly = ( pNode->m_Entry.m_pModelRenderable == NULL );
  527. pCurrInfo->m_pStencilState = pNode->m_pStencilState;
  528. list.m_nSetupBoneCount += pCurrInfo->m_bSetupBonesOnly;
  529. ++pCurrInfo;
  530. }
  531. // Sort within this model type. skin first, then LOD, then body.
  532. Assert( pCurrInfo - list.m_pRenderModels == list.m_nCount );
  533. std::sort( list.m_pRenderModels, list.m_pRenderModels + list.m_nCount, SortLessFunc );
  534. list.m_nCount -= list.m_nSetupBoneCount;
  535. list.m_nSetupBoneCount += list.m_nCount;
  536. }
  537. }
  538. //-----------------------------------------------------------------------------
  539. // Sets up bones on all models
  540. //-----------------------------------------------------------------------------
  541. void CModelRenderSystem::SetupBones( int nModelTypeCount, ModelListByType_t *pModelList )
  542. {
  543. // FIXME: Can we make parallel bone setup faster? Yes, we can!
  544. const float flCurTime = gpGlobals->curtime;
  545. matrix3x4a_t pPoseToBone[MAXSTUDIOBONES];
  546. for ( int i = 0; i < nModelTypeCount; ++i )
  547. {
  548. ModelListByType_t &list = pModelList[i];
  549. const int nBoneCount = list.m_pStudioHdr->numbones;
  550. // Force setup of attachments if we're going to use an illumposition
  551. const int nAttachmentMask = ( list.m_pStudioHdr->IllumPositionAttachmentIndex() > 0 ) ? BONE_USED_BY_ATTACHMENT : 0;
  552. for ( int j = 0; j < list.m_nSetupBoneCount; ++j )
  553. {
  554. RenderModelInfo_t *pModel = &list.m_pRenderModels[j];
  555. const int nBoneMask = BONE_USED_BY_VERTEX_AT_LOD( pModel->m_nLOD ) | nAttachmentMask;
  556. pModel->m_pBoneToWorld = (matrix3x4a_t*)m_BoneToWorld.Alloc( nBoneCount * sizeof(matrix3x4a_t) );
  557. const bool bOk = pModel->m_Entry.m_pRenderable->SetupBones( pModel->m_pBoneToWorld, nBoneCount, nBoneMask, flCurTime );
  558. if ( !bOk )
  559. {
  560. for ( int k = 0; k < nBoneCount; ++k)
  561. {
  562. SetIdentityMatrix( pModel->m_pBoneToWorld[k] );
  563. }
  564. }
  565. }
  566. if ( list.m_nCount == 0 )
  567. continue;
  568. // Get the pose to bone for the model
  569. if ( !list.m_pStudioHdr->pLinearBones() )
  570. {
  571. // convert bone to world transformations into pose to world transformations
  572. for (int k = 0; k < nBoneCount; k++)
  573. {
  574. const mstudiobone_t *pCurBone = list.m_pStudioHdr->pBone( k );
  575. MatrixCopy( pCurBone->poseToBone, pPoseToBone[k] );
  576. }
  577. }
  578. else
  579. {
  580. mstudiolinearbone_t *pLinearBones = list.m_pStudioHdr->pLinearBones();
  581. #if defined(_X360) || defined (_PS3)
  582. const int iOffsetToCacheline = 2; // == 128/sizeof(mstudiolinearbone_t) == 128/64
  583. int iNextPrefetch = 0;
  584. #endif
  585. // convert bone to world transformations into pose to world transformations
  586. for ( int k = 0; k < nBoneCount; k++)
  587. {
  588. #if defined(_X360) || defined (_PS3)
  589. if ( k == iNextPrefetch && (iNextPrefetch = k + iOffsetToCacheline) < nBoneCount )
  590. {
  591. PREFETCH360( &pLinearBones->poseToBone(iNextPrefetch), 0 );
  592. }
  593. #endif
  594. MatrixCopy( pLinearBones->poseToBone(k), pPoseToBone[k] );
  595. }
  596. }
  597. // Apply the pose-to-bone matrix to all instances
  598. // NOTE: We should be able to optimize this a ton since it's very parallelizable
  599. // NOTE: We may well want to compute the aggregate bone to world here also.
  600. for ( int j = 0; j < list.m_nCount; ++j )
  601. {
  602. RenderModelInfo_t *pModel = &list.m_pRenderModels[j];
  603. CMatRenderData< matrix3x4a_t > rdPoseToWorld( m_pRenderContext, nBoneCount );
  604. pModel->m_pPoseToWorld = rdPoseToWorld.Base();
  605. #if defined(_X360) || defined (_PS3)
  606. if ( j + 1 < list.m_nCount )
  607. {
  608. PREFETCH360( list.m_pRenderModels[j + 1].m_pBoneToWorld, 0 );
  609. PREFETCH360( pModel->m_pPoseToWorld + nBoneCount, 0 );
  610. }
  611. const int iOffsetToCacheline = 3; // == 128/sizeof(matrix3x4a_t) == 128/48
  612. int iNextPrefetch = 0;
  613. #endif
  614. for ( int b = 0; b < nBoneCount; b++ )
  615. {
  616. #if defined(_X360) || defined (_PS3)
  617. if ( b == iNextPrefetch && (iNextPrefetch = b + iOffsetToCacheline) < nBoneCount )
  618. {
  619. PREFETCH360( &pModel->m_pBoneToWorld[iNextPrefetch], 0 );
  620. PREFETCH360( &pModel->m_pPoseToWorld[iNextPrefetch], 0 );
  621. }
  622. #endif
  623. ConcatTransforms_Aligned( pModel->m_pBoneToWorld[b], pPoseToBone[b], pModel->m_pPoseToWorld[b] );
  624. }
  625. }
  626. }
  627. }
  628. //-----------------------------------------------------------------------------
  629. // Sets up flexes on all models
  630. //-----------------------------------------------------------------------------
  631. void CModelRenderSystem::SetupFlexes( int nModelTypeCount, ModelListByType_t *pModelList )
  632. {
  633. bool bUsesDelayedWeights = g_CV_FlexSmooth.GetBool();
  634. for ( int i = 0; i < nModelTypeCount; ++i )
  635. {
  636. ModelListByType_t &list = pModelList[i];
  637. const int nFlexCount = list.m_pStudioHdr->numflexdesc;
  638. if ( !nFlexCount )
  639. continue;
  640. for ( int j = 0; j < list.m_nCount; ++j )
  641. {
  642. RenderModelInfo_t *pModel = &list.m_pRenderModels[j];
  643. CMatRenderData< float > rdFlexWeights( m_pRenderContext );
  644. CMatRenderData< float > rdDelayedFlexWeights( m_pRenderContext );
  645. pModel->m_pFlexWeights = rdFlexWeights.Lock( nFlexCount );
  646. if ( bUsesDelayedWeights )
  647. {
  648. pModel->m_pDelayedFlexWeights = rdDelayedFlexWeights.Lock( nFlexCount );
  649. }
  650. pModel->m_Entry.m_pRenderable->SetupWeights( pModel->m_pBoneToWorld, nFlexCount, pModel->m_pFlexWeights, pModel->m_pDelayedFlexWeights );
  651. }
  652. }
  653. }
  654. //-----------------------------------------------------------------------------
  655. // Draws debugging information for lighting
  656. //-----------------------------------------------------------------------------
  657. void CModelRenderSystem::DebugDrawLightingOrigin( const ModelListByType_t &list, const RenderModelInfo_t &model )
  658. {
  659. if ( !model.m_pLightingState )
  660. return;
  661. const Vector& lightOrigin = model.m_pLightingState->m_vecLightingOrigin;
  662. const matrix3x4_t &modelToWorld = model.m_Entry.m_pRenderable->RenderableToWorldTransform();
  663. // draw z planar cross at lighting origin
  664. Vector pt0;
  665. Vector pt1;
  666. pt0 = lightOrigin;
  667. pt1 = lightOrigin;
  668. pt0.x -= 4;
  669. pt1.x += 4;
  670. debugoverlay->AddLineOverlay( pt0, pt1, 0, 255, 0, true, 0.0f );
  671. pt0 = lightOrigin;
  672. pt1 = lightOrigin;
  673. pt0.y -= 4;
  674. pt1.y += 4;
  675. debugoverlay->AddLineOverlay( pt0, pt1, 0, 255, 0, true, 0.0f );
  676. // draw lines from the light origin to the hull boundaries to identify model
  677. Vector pt;
  678. pt0.x = list.m_pStudioHdr->hull_min.x;
  679. pt0.y = list.m_pStudioHdr->hull_min.y;
  680. pt0.z = list.m_pStudioHdr->hull_min.z;
  681. VectorTransform( pt0, modelToWorld, pt1 );
  682. debugoverlay->AddLineOverlay( lightOrigin, pt1, 100, 100, 150, true, 0.0f );
  683. pt0.x = list.m_pStudioHdr->hull_min.x;
  684. pt0.y = list.m_pStudioHdr->hull_max.y;
  685. pt0.z = list.m_pStudioHdr->hull_min.z;
  686. VectorTransform( pt0, modelToWorld, pt1 );
  687. debugoverlay->AddLineOverlay( lightOrigin, pt1, 100, 100, 150, true, 0.0f );
  688. pt0.x = list.m_pStudioHdr->hull_max.x;
  689. pt0.y = list.m_pStudioHdr->hull_max.y;
  690. pt0.z = list.m_pStudioHdr->hull_min.z;
  691. VectorTransform( pt0, modelToWorld, pt1 );
  692. debugoverlay->AddLineOverlay( lightOrigin, pt1, 100, 100, 150, true, 0.0f );
  693. pt0.x = list.m_pStudioHdr->hull_max.x;
  694. pt0.y = list.m_pStudioHdr->hull_min.y;
  695. pt0.z = list.m_pStudioHdr->hull_min.z;
  696. VectorTransform( pt0, modelToWorld, pt1 );
  697. debugoverlay->AddLineOverlay( lightOrigin, pt1, 100, 100, 150, true, 0.0f );
  698. pt0.x = list.m_pStudioHdr->hull_min.x;
  699. pt0.y = list.m_pStudioHdr->hull_min.y;
  700. pt0.z = list.m_pStudioHdr->hull_max.z;
  701. VectorTransform( pt0, modelToWorld, pt1 );
  702. debugoverlay->AddLineOverlay( lightOrigin, pt1, 100, 100, 150, true, 0.0f );
  703. pt0.x = list.m_pStudioHdr->hull_min.x;
  704. pt0.y = list.m_pStudioHdr->hull_max.y;
  705. pt0.z = list.m_pStudioHdr->hull_max.z;
  706. VectorTransform( pt0, modelToWorld, pt1 );
  707. debugoverlay->AddLineOverlay( lightOrigin, pt1, 100, 100, 150, true, 0.0f );
  708. pt0.x = list.m_pStudioHdr->hull_max.x;
  709. pt0.y = list.m_pStudioHdr->hull_max.y;
  710. pt0.z = list.m_pStudioHdr->hull_max.z;
  711. VectorTransform( pt0, modelToWorld, pt1 );
  712. debugoverlay->AddLineOverlay( lightOrigin, pt1, 100, 100, 150, true, 0.0f );
  713. pt0.x = list.m_pStudioHdr->hull_max.x;
  714. pt0.y = list.m_pStudioHdr->hull_min.y;
  715. pt0.z = list.m_pStudioHdr->hull_max.z;
  716. VectorTransform( pt0, modelToWorld, pt1 );
  717. debugoverlay->AddLineOverlay( lightOrigin, pt1, 100, 100, 150, true, 0.0f );
  718. }
  719. //-----------------------------------------------------------------------------
  720. // Compute lighting origin on all models
  721. //-----------------------------------------------------------------------------
  722. void CModelRenderSystem::ComputeLightingOrigin( ModelListByType_t &list, LightingQuery_t *pLightingQueryBase, int nQueryStride )
  723. {
  724. LightingQuery_t *pLightingQuery = pLightingQueryBase;
  725. int nAttachmentIndex = list.m_pStudioHdr->IllumPositionAttachmentIndex();
  726. bool bAmbientBoost = ( list.m_pStudioHdr->flags & STUDIOHDR_FLAGS_AMBIENT_BOOST ) != 0;
  727. const Vector &vecIllumPosition = list.m_pStudioHdr->illumposition;
  728. // ($TODO): We may want to pull the functionality of ComputeLightingOrigin inlined into this loop to prevent the virtual function call overhead and refactor to reduce the conditionals.
  729. for ( int j = 0; j < list.m_nCount; ++j, pLightingQuery = (LightingQuery_t*)( (unsigned char*)pLightingQuery + nQueryStride ) )
  730. {
  731. RenderModelInfo_t *pModel = &list.m_pRenderModels[j];
  732. const matrix3x4_t &renderToWorld = pModel->m_Entry.m_pRenderable->RenderableToWorldTransform();
  733. C_BaseEntity *pEnt = pModel->m_Entry.m_pRenderable->GetIClientUnknown()->GetBaseEntity();
  734. pEnt->ComputeLightingOrigin( nAttachmentIndex, vecIllumPosition, renderToWorld, pLightingQuery->m_LightingOrigin );
  735. //VectorTransform( vecIllumPosition, renderToWorld, pLightingQuery->m_LightingOrigin );
  736. pLightingQuery->m_InstanceHandle = pModel->m_hInstance;
  737. pLightingQuery->m_bAmbientBoost = bAmbientBoost;
  738. }
  739. #if 0
  740. // NOTE: This is more expensive, but hopefully is uncommon
  741. // Bonemerged models will copy the lighting environment from their parent entity.
  742. // This fixes issues with L4D2 infected wounds where the wounds would sometimes receive different lighting
  743. // than the body they're embedded in.
  744. if ( nBoneMergeCount > 0 )
  745. {
  746. pLightingQuery = pLightingQueryBase;
  747. for ( int j = 0; j < list.m_nCount; ++j, pLightingQuery = (LightingQuery_t*)( (unsigned char*)pLightingQuery + nQueryStride ) )
  748. {
  749. RenderModelInfo_t *pModel = &list.m_pRenderModels[j];
  750. if ( !pModel->m_bBoneMerge )
  751. continue;
  752. C_BaseEntity *pEnt = pModel->m_Entry.m_pRenderable->GetIClientUnknown()->GetBaseEntity();
  753. C_BaseEntity *pParent = pEnt->GetMoveParent();
  754. if ( !pParent )
  755. continue;
  756. pLightingQuery->m_ParentInstanceHandle = pParent->GetModelInstance();
  757. }
  758. }
  759. #endif
  760. }
  761. //-----------------------------------------------------------------------------
  762. // Builds the model lighting list
  763. //-----------------------------------------------------------------------------
  764. enum
  765. {
  766. LIGHTING_USES_ENV_CUBEMAP = 0x1,
  767. LIGHTING_IS_VERTEX_LIT = 0x2,
  768. LIGHTING_IS_STATIC_LIT = 0x4,
  769. };
  770. int CModelRenderSystem::BuildLightingList( ModelListByType_t **ppLists, unsigned char *pFlags, int *pTotalModels, const LightingList_t &lightingList )
  771. {
  772. // FIXME: This may be better placed in the engine to avoid all the virtual calls?
  773. int nSetupCount = 0;
  774. *pTotalModels = 0;
  775. for ( ModelListByType_t* pList = lightingList.m_pFirstModel; pList; pList = pList->m_pNextLightingModel )
  776. {
  777. // FIXME: Under what conditions can the static prop skip lighting? [unlit materials]
  778. bool bIsLit = modelinfo->IsModelVertexLit( pList->m_pModel );
  779. bool bUsesEnvCubemap = modelinfo->UsesEnvCubemap( pList->m_pModel );
  780. bool bIsStaticLit = modelinfo->UsesStaticLighting( pList->m_pModel );
  781. if ( !bIsLit && !bUsesEnvCubemap && !bIsStaticLit )
  782. continue;
  783. ppLists[ nSetupCount ] = pList;
  784. pFlags[ nSetupCount ] = ( bIsStaticLit << 2 ) | ( bIsLit << 1 ) | ( bUsesEnvCubemap << 0 );
  785. *pTotalModels += pList->m_nCount;
  786. ++nSetupCount;
  787. }
  788. return nSetupCount;
  789. }
  790. //-----------------------------------------------------------------------------
  791. // Hook up computed lighting state
  792. //-----------------------------------------------------------------------------
  793. void CModelRenderSystem::HookUpStaticLightingState( int nCount, ModelListByType_t **ppLists,
  794. unsigned char *pFlags, ITexture **ppEnvCubemap, MaterialLightingState_t *pLightingState,
  795. MaterialLightingState_t *pDecalLightingState, ColorMeshInfo_t **ppColorMeshInfo )
  796. {
  797. // FIXME: This has got to be more efficient that this
  798. for ( int i = 0; i < nCount; ++i )
  799. {
  800. ModelListByType_t &list = *( ppLists[i] );
  801. if ( pFlags[i] & LIGHTING_USES_ENV_CUBEMAP )
  802. {
  803. for ( int j = 0; j < list.m_nCount; ++j )
  804. {
  805. RenderModelInfo_t *pModel = &list.m_pRenderModels[j];
  806. pModel->m_pEnvCubemapTexture = ppEnvCubemap[j] ? ppEnvCubemap[j] : m_DefaultCubemap;
  807. }
  808. }
  809. if ( pFlags[i] & LIGHTING_IS_VERTEX_LIT )
  810. {
  811. for ( int j = 0; j < list.m_nCount; ++j )
  812. {
  813. RenderModelInfo_t *pModel = &list.m_pRenderModels[j];
  814. pModel->m_pLightingState = &pLightingState[j];
  815. pModel->m_pDecalLightingState = &pDecalLightingState[j];
  816. }
  817. }
  818. if ( pFlags[i] & LIGHTING_IS_STATIC_LIT )
  819. {
  820. for ( int j = 0; j < list.m_nCount; ++j )
  821. {
  822. RenderModelInfo_t *pModel = &list.m_pRenderModels[j];
  823. pModel->m_pColorMeshInfo = ppColorMeshInfo[j];
  824. }
  825. }
  826. ppEnvCubemap += list.m_nCount;
  827. pLightingState += list.m_nCount;
  828. pDecalLightingState += list.m_nCount;
  829. ppColorMeshInfo += list.m_nCount;
  830. }
  831. }
  832. //-----------------------------------------------------------------------------
  833. // Sets up lighting on all models
  834. //-----------------------------------------------------------------------------
  835. int CModelRenderSystem::SetupStaticPropLighting( LightingList_t &lightingList, DataCacheHandle_t *pColorMeshHandle )
  836. {
  837. if ( lightingList.m_nCount == 0 )
  838. return 0;
  839. // Build list of everything that needs lighting
  840. int nTotalModels;
  841. ModelListByType_t **ppLists = (ModelListByType_t**)stackalloc( lightingList.m_nCount * sizeof(ModelListByType_t*) );
  842. unsigned char *pFlags = (unsigned char*)stackalloc( lightingList.m_nCount * sizeof(unsigned char) );
  843. int nSetupCount = BuildLightingList( ppLists, pFlags, &nTotalModels, lightingList );
  844. if ( nSetupCount == 0 )
  845. return 0;
  846. // Build queries used to compute lighting
  847. StaticLightingQuery_t *pLightingQuery = (StaticLightingQuery_t*)stackalloc( nTotalModels * sizeof(StaticLightingQuery_t) );
  848. int nOffset = 0;
  849. for ( int i = 0; i < nSetupCount; ++i )
  850. {
  851. ModelListByType_t &list = *( ppLists[i] );
  852. for ( int j = 0; j < list.m_nCount; ++j, ++nOffset )
  853. {
  854. pLightingQuery[ nOffset ].m_pRenderable = list.m_pRenderModels[j].m_Entry.m_pRenderable;
  855. pLightingQuery[ nOffset ].m_InstanceHandle = list.m_pRenderModels[j].m_hInstance;
  856. pLightingQuery[ nOffset ].m_bAmbientBoost = false;
  857. }
  858. }
  859. // Compute lighting origins
  860. staticpropmgr->GetLightingOrigins( &pLightingQuery[0].m_LightingOrigin,
  861. sizeof(StaticLightingQuery_t), nTotalModels, &pLightingQuery[0].m_pRenderable, sizeof(StaticLightingQuery_t) );
  862. // Does all lighting computations for all models
  863. ColorMeshInfo_t **ppColorMeshInfo = (ColorMeshInfo_t**)stackalloc( nTotalModels * sizeof(ColorMeshInfo_t*) );
  864. ITexture **ppEnvCubemap = (ITexture**)stackalloc( nTotalModels * sizeof(ITexture*) );
  865. CMatRenderData< MaterialLightingState_t > rdLightingState( m_pRenderContext, 2 * nTotalModels );
  866. // bring this into cache and clear it, we're going to write to most of it anyway
  867. Plat_FastMemset( rdLightingState.Base(), 0, sizeof(MaterialLightingState_t) * 2 * nTotalModels );
  868. MaterialLightingState_t *pLightingState = rdLightingState.Base();
  869. MaterialLightingState_t *pDecalLightingState = &rdLightingState[ nTotalModels ];
  870. modelrender->ComputeStaticLightingState( nTotalModels, pLightingQuery, pLightingState, pDecalLightingState, ppColorMeshInfo, ppEnvCubemap, pColorMeshHandle );
  871. // Hook up pointers
  872. HookUpStaticLightingState( nSetupCount, ppLists, pFlags, ppEnvCubemap, pLightingState, pDecalLightingState, ppColorMeshInfo );
  873. return nTotalModels;
  874. }
  875. void CModelRenderSystem::SetupStandardLighting( LightingList_t &lightingList )
  876. {
  877. if ( lightingList.m_nCount == 0 )
  878. return;
  879. // Determine which groups need lighting
  880. ModelListByType_t **ppLists = (ModelListByType_t**)stackalloc( lightingList.m_nCount * sizeof(ModelListByType_t*) );
  881. unsigned char *pFlags = (unsigned char*)stackalloc( lightingList.m_nCount * sizeof(unsigned char) );
  882. int nTotalModels = 0;
  883. int nSetupCount = BuildLightingList( ppLists, pFlags, &nTotalModels, lightingList );
  884. if ( nSetupCount == 0 )
  885. return;
  886. // Compute data necessary for lighting computations
  887. int nOffset = 0;
  888. LightingQuery_t *pLightingQuery = (LightingQuery_t*)stackalloc( nTotalModels * sizeof(LightingQuery_t) );
  889. CMatRenderData<MaterialLightingState_t> rdLightingState( m_pRenderContext, nTotalModels );
  890. MaterialLightingState_t *pLightingState = rdLightingState.Base();
  891. PREFETCH360( pLightingState, 0 );
  892. PREFETCH360( pLightingState, 128 );
  893. PREFETCH360( pLightingState, 256 );
  894. PREFETCH360( pLightingState, 384 );
  895. PREFETCH360( pLightingState, 512 );
  896. PREFETCH360( pLightingState, 640 );
  897. PREFETCH360( pLightingState, 768 );
  898. PREFETCH360( pLightingState, 896 );
  899. for ( int i = 0; i < nSetupCount; ++i )
  900. {
  901. ModelListByType_t &list = *( ppLists[i] );
  902. ComputeLightingOrigin( list, &pLightingQuery[nOffset], sizeof(LightingQuery_t) );
  903. nOffset += list.m_nCount;
  904. }
  905. memset( pLightingState, 0, nTotalModels * sizeof(MaterialLightingState_t) );
  906. // Does all lighting computations for all models
  907. ITexture **ppEnvCubemap = (ITexture**)stackalloc( nTotalModels * sizeof(ITexture*) );
  908. modelrender->ComputeLightingState( nTotalModels, pLightingQuery, pLightingState, ppEnvCubemap );
  909. // Hook up pointers
  910. MaterialLightingState_t *pCurrState = pLightingState;
  911. for ( int i = 0; i < nSetupCount; ++i )
  912. {
  913. ModelListByType_t &list = *( ppLists[i] );
  914. if ( pFlags[i] & 0x1 )
  915. {
  916. for ( int j = 0; j < list.m_nCount; ++j )
  917. {
  918. RenderModelInfo_t *pModel = &list.m_pRenderModels[j];
  919. pModel->m_pEnvCubemapTexture = ppEnvCubemap[j] ? ppEnvCubemap[j] : m_DefaultCubemap;
  920. }
  921. }
  922. if ( pFlags[i] & 0x2 )
  923. {
  924. for ( int j = 0; j < list.m_nCount; ++j )
  925. {
  926. RenderModelInfo_t *pModel = &list.m_pRenderModels[j];
  927. pModel->m_pLightingState = &pCurrState[j];
  928. }
  929. }
  930. ppEnvCubemap += list.m_nCount;
  931. pCurrState += list.m_nCount;
  932. }
  933. }
  934. int CModelRenderSystem::SetupPhysicsPropLighting( LightingList_t &lightingList, DataCacheHandle_t *pColorMeshHandle )
  935. {
  936. if ( lightingList.m_nCount == 0 )
  937. return 0;
  938. // NOTE: Physics prop lighting is the same as static prop lighting, only
  939. // the static lighting is *always* used (the system goes to the standard path
  940. // for physics props which are moving or which use bumpmapping).
  941. ModelListByType_t **ppLists = (ModelListByType_t**)stackalloc( lightingList.m_nCount * sizeof(ModelListByType_t*) );
  942. unsigned char *pFlags = (unsigned char*)stackalloc( lightingList.m_nCount * sizeof(unsigned char) );
  943. int nTotalModels = 0;
  944. int nSetupCount = BuildLightingList( ppLists, pFlags, &nTotalModels, lightingList );
  945. if ( nSetupCount == 0 )
  946. return 0;
  947. StaticLightingQuery_t *pLightingQuery = (StaticLightingQuery_t*)stackalloc( nTotalModels * sizeof(StaticLightingQuery_t) );
  948. int nOffset = 0;
  949. for ( int i = 0; i < nSetupCount; ++i )
  950. {
  951. ModelListByType_t &list = *( ppLists[i] );
  952. ComputeLightingOrigin( list, &pLightingQuery[nOffset], sizeof(StaticLightingQuery_t) );
  953. for ( int j = 0; j < list.m_nCount; ++j, ++nOffset )
  954. {
  955. pLightingQuery[ nOffset ].m_pRenderable = list.m_pRenderModels[j].m_Entry.m_pRenderable;
  956. }
  957. }
  958. // Does all lighting computations for all models
  959. ColorMeshInfo_t **ppColorMeshInfo = (ColorMeshInfo_t**)stackalloc( nTotalModels * sizeof(ColorMeshInfo_t*) );
  960. ITexture **ppEnvCubemap = (ITexture**)stackalloc( nTotalModels * sizeof(ITexture*) );
  961. CMatRenderData< MaterialLightingState_t > rdLightingState( m_pRenderContext, 2 * nTotalModels );
  962. MaterialLightingState_t *pLightingState = rdLightingState.Base();
  963. MaterialLightingState_t *pDecalLightingState = &pLightingState[ nTotalModels ];
  964. modelrender->ComputeStaticLightingState( nTotalModels, pLightingQuery, pLightingState, pDecalLightingState, ppColorMeshInfo, ppEnvCubemap, pColorMeshHandle );
  965. // Hook up pointers
  966. HookUpStaticLightingState( nSetupCount, ppLists, pFlags, ppEnvCubemap, pLightingState, pDecalLightingState, ppColorMeshInfo );
  967. return nTotalModels;
  968. }
  969. int CModelRenderSystem::SetupLighting( LightingList_t *pLightingList, int nModelTypeCount, ModelListByType_t *pModelList, DataCacheHandle_t *pColorMeshHandles, ModelRenderMode_t renderMode )
  970. {
  971. if ( renderMode != MODEL_RENDER_MODE_NORMAL )
  972. {
  973. return 0;
  974. }
  975. int nCount = SetupStaticPropLighting( pLightingList[ LIGHTING_MODEL_STATIC_PROP ], pColorMeshHandles );
  976. pColorMeshHandles += nCount;
  977. SetupStandardLighting( pLightingList[ LIGHTING_MODEL_STANDARD ] );
  978. nCount += SetupPhysicsPropLighting( pLightingList[ LIGHTING_MODEL_PHYSICS_PROP ], pColorMeshHandles );
  979. // Debugging info
  980. if ( r_drawmodellightorigin.GetBool() )
  981. {
  982. for ( int i = 0; i < nModelTypeCount; ++i )
  983. {
  984. const ModelListByType_t &list = pModelList[ i ];
  985. if ( list.m_nLightingModel == LIGHTING_MODEL_NONE )
  986. continue;
  987. for ( int j = 0; j < list.m_nCount; ++j )
  988. {
  989. const RenderModelInfo_t &info = list.m_pRenderModels[j];
  990. DebugDrawLightingOrigin( list, info );
  991. }
  992. }
  993. }
  994. return nCount;
  995. }
  996. //-----------------------------------------------------------------------------
  997. // Setup render state related to flashlights and decals
  998. //-----------------------------------------------------------------------------
  999. void CModelRenderSystem::SetupFlashlightsAndDecals( StudioModelArrayInfo2_t *pInfo, int nModelTypeCount, ModelListByType_t *pModelList, int nTotalModelCount, RenderModelInfo_t *pRenderModels, ModelRenderMode_t renderMode )
  1000. {
  1001. // Skip lighting + decals if we don't need it
  1002. if ( renderMode != MODEL_RENDER_MODE_NORMAL )
  1003. return;
  1004. ShadowHandle_t pFlashlights[MAX_FLASHLIGHTS_PER_INSTANCE_DRAW_CALL];
  1005. int nInstCount = 0;
  1006. ModelInstanceHandle_t *pModelInstanceHandle = (ModelInstanceHandle_t*)stackalloc( nTotalModelCount * sizeof(ModelInstanceHandle_t) );
  1007. for ( int i = 0; i < nModelTypeCount; ++i )
  1008. {
  1009. ModelListByType_t &list = pModelList[ i ];
  1010. for ( int j = 0; j < list.m_nCount; ++j )
  1011. {
  1012. RenderModelInfo_t *pModel = &list.m_pRenderModels[j];
  1013. pModelInstanceHandle[nInstCount++] = pModel->m_hInstance;
  1014. }
  1015. }
  1016. if ( nTotalModelCount != nInstCount )
  1017. {
  1018. // FIXME: custom player model scaffolds have no geometry (only bones) and when used will always trip this warning - this system needs to account for models that don't 'render' in the traditional sense.
  1019. // AssertMsgOnce( false, "Instance count does not match model count." );
  1020. nTotalModelCount = nInstCount;
  1021. }
  1022. // Gets all decals
  1023. StudioDecalHandle_t *pDecals = &pRenderModels->m_Decals;
  1024. modelrender->GetModelDecalHandles( pDecals, sizeof(RenderModelInfo_t), nTotalModelCount, pModelInstanceHandle );
  1025. // Builds a list of all flashlights affecting this model
  1026. uint32 *pFlashlightUsage = &pRenderModels->m_nFlashlightUsage;
  1027. pInfo->m_nFlashlightCount = shadowmgr->SetupFlashlightRenderInstanceInfo( pFlashlights, pFlashlightUsage, sizeof(RenderModelInfo_t), nTotalModelCount, pModelInstanceHandle );
  1028. if ( pInfo->m_nFlashlightCount )
  1029. {
  1030. // Copy over the flashlight state
  1031. // FIXME: Should we do this over the entire list of all instances?
  1032. // There's going to be a fair amount of copying of flashlight_ts
  1033. CMatRenderData< FlashlightInstance_t > rdFlashlights( m_pRenderContext, pInfo->m_nFlashlightCount );
  1034. pInfo->m_pFlashlights = rdFlashlights.Base();
  1035. shadowmgr->GetFlashlightRenderInfo( pInfo->m_pFlashlights, pInfo->m_nFlashlightCount, pFlashlights );
  1036. }
  1037. else
  1038. {
  1039. pInfo->m_pFlashlights = NULL;
  1040. }
  1041. // FIXME: Hack!
  1042. for ( int i = 0; i < nModelTypeCount; ++i )
  1043. {
  1044. ModelListByType_t &list = pModelList[ i ];
  1045. list.m_nFlashlightCount = pInfo->m_nFlashlightCount;
  1046. list.m_pFlashlights = pInfo->m_pFlashlights;
  1047. }
  1048. }
  1049. void CModelRenderSystem::SetupPerInstanceColorModulation( int nModelTypeCount, ModelListByType_t *pModelList )
  1050. {
  1051. for ( int i = 0; i < nModelTypeCount; ++i )
  1052. {
  1053. ModelListByType_t &list = pModelList[ i ];
  1054. if ( !list.m_nCount )
  1055. continue;
  1056. for ( int j = 0; j < list.m_nCount; ++j )
  1057. {
  1058. RenderModelInfo_t *pModel = &list.m_pRenderModels[j];
  1059. IClientRenderable *pRenderable = pModel->m_Entry.m_pRenderable;
  1060. #if 0
  1061. Vector diffuseModulation;
  1062. pRenderable->GetColorModulation( diffuseModulation.Base() );
  1063. pModel->m_DiffuseModulation.x = diffuseModulation.x;
  1064. pModel->m_DiffuseModulation.y = diffuseModulation.y;
  1065. pModel->m_DiffuseModulation.z = diffuseModulation.z;
  1066. #else // preferred to do it this way, because it avoids a load-hit-store on 360
  1067. pRenderable->GetColorModulation( pModel->m_DiffuseModulation.AsVector3D().Base() );
  1068. #endif
  1069. pModel->m_DiffuseModulation.w = pModel->m_Entry.m_InstanceData.m_nAlpha * ( 1.0f / 255.0f );
  1070. }
  1071. }
  1072. }
  1073. //-----------------------------------------------------------------------------
  1074. // Call into studiorender
  1075. //-----------------------------------------------------------------------------
  1076. ConVar cl_colorfastpath( "cl_colorfastpath", "0" );
  1077. void CModelRenderSystem::RenderModels( StudioModelArrayInfo2_t *pInfo, int nModelTypeCount, ModelListByType_t *pModelList, int nTotalModelCount, ModelRenderMode_t renderMode, bool bShadowDepthIncludeTranslucentMaterials )
  1078. {
  1079. if ( renderMode == MODEL_RENDER_MODE_NORMAL )
  1080. {
  1081. bool bColorize = cl_colorfastpath.GetBool();
  1082. if ( bColorize )
  1083. {
  1084. g_pStudioRender->ForcedMaterialOverride( m_DebugMaterial );
  1085. }
  1086. const int nFlags = STUDIORENDER_DRAW_OPAQUE_ONLY;
  1087. CMatRenderData< StudioArrayData_t > rdArray( m_pRenderContext, nModelTypeCount );
  1088. #ifdef _DEBUG
  1089. bool bFoundStencil = false;
  1090. #endif
  1091. int nNonStencilModelTypeCount = 0;
  1092. for ( int i = 0; i < nModelTypeCount; ++i )
  1093. {
  1094. ModelListByType_t &list = pModelList[i];
  1095. rdArray[ i ].m_pStudioHdr = list.m_pStudioHdr;
  1096. rdArray[ i ].m_pHardwareData = list.m_pHardwareData;
  1097. rdArray[ i ].m_pInstanceData = list.m_pRenderModels;
  1098. rdArray[ i ].m_nCount = list.m_nCount;
  1099. nNonStencilModelTypeCount += list.m_bWantsStencil ? 0 : 1;
  1100. #ifdef _DEBUG
  1101. if ( list.m_bWantsStencil )
  1102. {
  1103. bFoundStencil = true;
  1104. }
  1105. else
  1106. {
  1107. Assert( !bFoundStencil );
  1108. }
  1109. #endif
  1110. }
  1111. if ( IsX360() /* && !IsPS3(), see below */ && r_fastzreject.GetBool() && ( nNonStencilModelTypeCount != nModelTypeCount ) )
  1112. {
  1113. // Render all models without stencil
  1114. g_pStudioRender->DrawModelArray( *pInfo, nNonStencilModelTypeCount, rdArray.Base(), sizeof(RenderModelInfo_t), nFlags );
  1115. #if defined( _GAMECONSOLE )
  1116. // end z prepass here
  1117. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1118. pRenderContext->EndConsoleZPass();
  1119. #endif
  1120. // Render all models with stencil
  1121. g_pStudioRender->DrawModelArray( *pInfo, nModelTypeCount - nNonStencilModelTypeCount, rdArray.Base() + nNonStencilModelTypeCount,
  1122. sizeof(RenderModelInfo_t), nFlags );
  1123. }
  1124. else
  1125. {
  1126. #if defined( _PS3 )
  1127. if( r_fastzreject.GetBool() )
  1128. {
  1129. // end z prepass here
  1130. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1131. pRenderContext->EndConsoleZPass();
  1132. }
  1133. #endif
  1134. // PC renders all models in one go regardless of stencil state
  1135. // PS/3 renders all models in one go because models have a lot of vertices and few pixels (as of Portal2). So we end Z Pass earlier, before we RenderModels()
  1136. g_pStudioRender->DrawModelArray( *pInfo, nModelTypeCount, rdArray.Base(), sizeof(RenderModelInfo_t), nFlags );
  1137. }
  1138. g_pStudioRender->ForcedMaterialOverride( NULL );
  1139. }
  1140. else if ( renderMode == MODEL_RENDER_MODE_SHADOW_DEPTH )
  1141. {
  1142. // NOTE: Use this path because we can aggregate draw calls across mdls
  1143. int nFlags = STUDIORENDER_SHADOWDEPTHTEXTURE;
  1144. if ( bShadowDepthIncludeTranslucentMaterials )
  1145. nFlags |= STUDIORENDER_SHADOWDEPTHTEXTURE_INCLUDE_TRANSLUCENT_MATERIALS;
  1146. else
  1147. nFlags |= STUDIORENDER_DRAW_OPAQUE_ONLY;
  1148. CMatRenderData< StudioArrayData_t > rdShadow( m_pRenderContext, nModelTypeCount );
  1149. for ( int i = 0; i < nModelTypeCount; ++i )
  1150. {
  1151. ModelListByType_t &list = pModelList[i];
  1152. rdShadow[ i ].m_pStudioHdr = list.m_pStudioHdr;
  1153. rdShadow[ i ].m_pHardwareData = list.m_pHardwareData;
  1154. rdShadow[ i ].m_pInstanceData = list.m_pRenderModels;
  1155. rdShadow[ i ].m_nCount = list.m_nCount;
  1156. }
  1157. g_pStudioRender->DrawModelShadowArray( nModelTypeCount, rdShadow.Base(), sizeof(RenderModelInfo_t), nFlags );
  1158. }
  1159. else if ( renderMode == MODEL_RENDER_MODE_RTT_SHADOWS )
  1160. {
  1161. // shouldn't get here unless the code is ported from l4d2 to drive this properly.
  1162. Assert(0);
  1163. #if 0
  1164. // HACK: Assume all models in this batch use the same material. This only works because we submit batches of 1 model from the client shadow manager at the moment
  1165. IMaterial* pShadowDrawMaterial = pModelList[0].m_pFirstNode->m_Entry.m_pRenderable->GetShadowDrawMaterial();
  1166. g_pStudioRender->ForcedMaterialOverride( pShadowDrawMaterial ? pShadowDrawMaterial : m_ShadowBuild, OVERRIDE_BUILD_SHADOWS );
  1167. for ( int i = 0; i < nModelTypeCount; ++i )
  1168. {
  1169. ModelListByType_t &list = pModelList[i];
  1170. g_pStudioRender->DrawModelArray( list, list.m_nCount, list.m_pRenderModels, sizeof(RenderModelInfo_t), STUDIORENDER_DRAW_OPAQUE_ONLY );
  1171. }
  1172. g_pStudioRender->ForcedMaterialOverride( NULL );
  1173. #endif
  1174. }
  1175. }
  1176. //-----------------------------------------------------------------------------
  1177. // Call into studiorender
  1178. //-----------------------------------------------------------------------------
  1179. void CModelRenderSystem::SetupTranslucentData( int nModelTypeCount, ModelListByType_t *pModelList, int nTotalModelCount, TranslucentInstanceRenderData_t *pRenderData )
  1180. {
  1181. memset( pRenderData, 0, nTotalModelCount * sizeof( TranslucentInstanceRenderData_t ) );
  1182. CMatRenderData< StudioModelArrayInfo_t > arrayInfo( m_pRenderContext, nModelTypeCount );
  1183. CMatRenderData< StudioArrayInstanceData_t > instanceData( m_pRenderContext, nTotalModelCount );
  1184. int nCurInstance = 0;
  1185. for ( int i = 0; i < nModelTypeCount; ++i )
  1186. {
  1187. ModelListByType_t &list = pModelList[i];
  1188. StudioModelArrayInfo_t *pModelInfo = &arrayInfo[i];
  1189. memcpy( pModelInfo, &list, sizeof( StudioModelArrayInfo_t ) );
  1190. for ( int j = 0; j < list.m_nCount; ++j )
  1191. {
  1192. RenderModelInfo_t &info = list.m_pRenderModels[j];
  1193. StudioArrayInstanceData_t *pInstanceData = &instanceData[nCurInstance++];
  1194. memcpy( pInstanceData, &info, sizeof( StudioArrayInstanceData_t ) );
  1195. TranslucentInstanceRenderData_t &data = pRenderData[ info.m_nInitialListIndex ];
  1196. data.m_pModelInfo = pModelInfo;
  1197. data.m_pInstanceData = pInstanceData;
  1198. }
  1199. }
  1200. }
  1201. //-----------------------------------------------------------------------------
  1202. // Renders debug overlays
  1203. //-----------------------------------------------------------------------------
  1204. void CModelRenderSystem::RenderVCollideDebugOverlay( int nModelTypeCount, ModelListByType_t *pModelList )
  1205. {
  1206. if ( !vcollide_wireframe.GetBool() )
  1207. return;
  1208. for ( int i = 0; i < nModelTypeCount; ++i )
  1209. {
  1210. ModelListByType_t &list = pModelList[i];
  1211. for ( int j = 0; j < list.m_nCount; ++j )
  1212. {
  1213. IClientRenderable *pRenderable = list.m_pRenderModels[j].m_Entry.m_pRenderable;
  1214. C_BaseAnimating *pAnim = dynamic_cast< C_BaseAnimating * >( pRenderable );
  1215. if ( pAnim && pAnim->IsRagdoll() )
  1216. {
  1217. pAnim->m_pRagdoll->DrawWireframe();
  1218. continue;
  1219. }
  1220. ICollideable *pCollideable = pRenderable->GetIClientUnknown()->GetCollideable();
  1221. if ( pCollideable && ( pCollideable->GetSolid() == SOLID_VPHYSICS ) &&
  1222. IsSolid( pCollideable->GetSolid(), pCollideable->GetSolidFlags() ) )
  1223. {
  1224. vcollide_t *pCollide = modelinfo->GetVCollide( pCollideable->GetCollisionModel() );
  1225. if ( pCollide && pCollide->solidCount == 1 )
  1226. {
  1227. static color32 debugColor = {0,255,255,0};
  1228. engine->DebugDrawPhysCollide( pCollide->solids[0], NULL, pCollideable->CollisionToWorldTransform(), debugColor );
  1229. C_BaseEntity *pEntity = pRenderable->GetIClientUnknown()->GetBaseEntity();
  1230. if ( pEntity && pEntity->VPhysicsGetObject() )
  1231. {
  1232. static color32 debugColorPhys = {255,0,0,0};
  1233. matrix3x4_t matrix;
  1234. pEntity->VPhysicsGetObject()->GetPositionMatrix( &matrix );
  1235. engine->DebugDrawPhysCollide( pCollide->solids[0], NULL, matrix, debugColorPhys );
  1236. }
  1237. }
  1238. continue;
  1239. }
  1240. else if ( pCollideable && vcollide_wireframe.GetInt() > 1 )
  1241. {
  1242. vcollide_t *pCollide = modelinfo->GetVCollide( pCollideable->GetCollisionModel() );
  1243. if ( pCollide && pCollide->solidCount == 1 )
  1244. {
  1245. static color32 debugColor = {0,255,0,0};
  1246. engine->DebugDrawPhysCollide( pCollide->solids[0], NULL, pAnim->RenderableToWorldTransform(), debugColor );
  1247. }
  1248. continue;
  1249. }
  1250. }
  1251. }
  1252. }
  1253. void CModelRenderSystem::RenderBBoxDebugOverlay( int nModelTypeCount, ModelListByType_t *pModelList )
  1254. {
  1255. for ( int i = 0; i < nModelTypeCount; ++i )
  1256. {
  1257. ModelListByType_t &list = pModelList[i];
  1258. for ( int j = 0; j < list.m_nCount; ++j )
  1259. {
  1260. IClientRenderable *pRenderable = list.m_pRenderModels[j].m_Entry.m_pRenderable;
  1261. if ( !pRenderable->GetIClientUnknown() )
  1262. continue;
  1263. C_BaseEntity *pEntity = pRenderable->GetIClientUnknown()->GetBaseEntity();
  1264. if ( !pEntity )
  1265. continue;
  1266. pEntity->DrawBBoxVisualizations();
  1267. }
  1268. }
  1269. }
  1270. //-----------------------------------------------------------------------------
  1271. // Renders debug overlays
  1272. //-----------------------------------------------------------------------------
  1273. void CModelRenderSystem::RenderDebugOverlays( int nModelTypeCount, ModelListByType_t *pModelList, ModelRenderMode_t renderMode )
  1274. {
  1275. if ( renderMode != MODEL_RENDER_MODE_NORMAL )
  1276. {
  1277. return;
  1278. }
  1279. RenderVCollideDebugOverlay( nModelTypeCount, pModelList );
  1280. RenderBBoxDebugOverlay( nModelTypeCount, pModelList );
  1281. }
  1282. //-----------------------------------------------------------------------------
  1283. // Sort model types function
  1284. //-----------------------------------------------------------------------------
  1285. inline bool CModelRenderSystem::StencilSortLessFunc( const ModelListByType_t &left, const ModelListByType_t &right )
  1286. {
  1287. // Ensure stenciling models are at the end of the list
  1288. if ( left.m_bWantsStencil != right.m_bWantsStencil )
  1289. {
  1290. return left.m_bWantsStencil < right.m_bWantsStencil;
  1291. }
  1292. // Keep same models with different lighting types together
  1293. return left.m_pModel < right.m_pModel;
  1294. }
  1295. //-----------------------------------------------------------------------------
  1296. // Draw models
  1297. //-----------------------------------------------------------------------------
  1298. static ConVar cl_skipfastpath( "cl_skipfastpath", "0", FCVAR_CHEAT, "Set to 1 to stop all models that go through the model fast path from rendering" );
  1299. void CModelRenderSystem::DrawModels( ModelRenderSystemData_t *pEntities, int nCount, ModelRenderMode_t renderMode, bool bShadowDepthIncludeTranslucentMaterials )
  1300. {
  1301. if ( nCount == 0 || cl_skipfastpath.GetInt() )
  1302. return;
  1303. VPROF_BUDGET( "CModelRenderSystem::DrawModels", VPROF_BUDGETGROUP_MODEL_FAST_PATH_RENDERING );
  1304. MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
  1305. // While doing this, we need materialsystem to keep around its temp allocations
  1306. // which we use for bone matrices + flexes
  1307. CMatRenderContextPtr matRenderContext( g_pMaterialSystem );
  1308. m_pRenderContext = matRenderContext;
  1309. PIXEVENT( m_pRenderContext, "CModelRenderSystem::DrawModels (FASTPATH)" );
  1310. CMatRenderDataReference rdLock( m_pRenderContext );
  1311. // FIXME: This is infected-specific for perf test reasons.
  1312. // Will break into a more fixed pipeline at a later date
  1313. DataCacheHandle_t *pColorMeshHandles = NULL;
  1314. if ( renderMode == MODEL_RENDER_MODE_NORMAL )
  1315. {
  1316. pColorMeshHandles = (DataCacheHandle_t*)stackalloc( nCount * sizeof(DataCacheHandle_t) );
  1317. }
  1318. ModelListByType_t *pModelList = (ModelListByType_t*)stackalloc( nCount * sizeof(ModelListByType_t) );
  1319. ModelListNode_t *pModelListNode = (ModelListNode_t*)stackalloc( nCount * sizeof(ModelListNode_t) );
  1320. int nModelsRenderingStencilCount = 0;
  1321. int nModelTypeCount = BucketModelsByMDL( pModelList, pModelListNode, pEntities, nCount, renderMode, &nModelsRenderingStencilCount );
  1322. LightingList_t pLightingList[ LIGHTING_MODEL_COUNT ];
  1323. memset( pLightingList, 0, LIGHTING_MODEL_COUNT * sizeof(LightingList_t) );
  1324. SortBucketsByDependency( nModelTypeCount, pModelList, pLightingList );
  1325. // Compute LODs for each model
  1326. ComputeModelLODs( nModelTypeCount, pModelList, pModelListNode, renderMode );
  1327. // Sort processing list by body, lod, skin, etc.
  1328. CMatRenderData< RenderModelInfo_t > rdRenderModelInfo( m_pRenderContext, nCount );
  1329. RenderModelInfo_t *pSortedModelListNode = rdRenderModelInfo.Base();
  1330. SortModels( pSortedModelListNode, nCount, nModelTypeCount, pModelList, pModelListNode );
  1331. // Setup bones
  1332. SetupBones( nModelTypeCount, pModelList );
  1333. // Setup flexes
  1334. if ( renderMode != MODEL_RENDER_MODE_RTT_SHADOWS )
  1335. {
  1336. SetupFlexes( nModelTypeCount, pModelList );
  1337. }
  1338. // Setup lighting
  1339. int nColorMeshHandles = SetupLighting( pLightingList, nModelTypeCount, pModelList, pColorMeshHandles, renderMode );
  1340. // Setup flashlights + decals
  1341. StudioModelArrayInfo2_t info;
  1342. SetupFlashlightsAndDecals( &info, nModelTypeCount, pModelList, nCount, pSortedModelListNode, renderMode );
  1343. // Setup per-instance color modulation
  1344. SetupPerInstanceColorModulation( nModelTypeCount, pModelList );
  1345. // Setup per-instance wound data
  1346. //SetupInfectedWoundRenderData( nModelTypeCount, pModelList, nCount, renderMode );
  1347. if ( IsGameConsole() && ( renderMode == MODEL_RENDER_MODE_NORMAL ) && ( nModelsRenderingStencilCount > 0) )
  1348. {
  1349. // resort here to make sure all models rendering stencil come last
  1350. std::sort( pModelList, pModelList + nModelTypeCount, StencilSortLessFunc );
  1351. }
  1352. // Draw models
  1353. RenderModels( &info, nModelTypeCount, pModelList, nCount, renderMode, bShadowDepthIncludeTranslucentMaterials );
  1354. rdLock.Release();
  1355. if ( renderMode == MODEL_RENDER_MODE_NORMAL )
  1356. {
  1357. modelrender->CleanupStaticLightingState( nColorMeshHandles, pColorMeshHandles );
  1358. stackfree( pColorMeshHandles );
  1359. }
  1360. // Blat out temporary memory for bone-to-world transforms
  1361. m_BoneToWorld.FreeAll( false );
  1362. RenderDebugOverlays( nModelTypeCount, pModelList, renderMode );
  1363. m_pRenderContext = NULL;
  1364. }
  1365. //-----------------------------------------------------------------------------
  1366. // Computes per-instance data for fast path rendering
  1367. //-----------------------------------------------------------------------------
  1368. void CModelRenderSystem::ComputeTranslucentRenderData( ModelRenderSystemData_t *pModels, int nCount, TranslucentInstanceRenderData_t *pRenderData, TranslucentTempData_t *pTempData )
  1369. {
  1370. if ( nCount == 0 )
  1371. {
  1372. pTempData->m_nColorMeshHandleCount = 0;
  1373. pTempData->m_bReleaseRenderData = false;
  1374. return;
  1375. }
  1376. VPROF_BUDGET( "CModelRenderSystem::ComputeTranslucentRenderData", VPROF_BUDGETGROUP_MODEL_FAST_PATH_RENDERING );
  1377. MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
  1378. // While doing this, we need materialsystem to keep around its temp allocations
  1379. // which we use for bone matrices + flexes
  1380. CMatRenderContextPtr matRenderContext( g_pMaterialSystem );
  1381. m_pRenderContext = matRenderContext;
  1382. PIXEVENT( m_pRenderContext, "CModelRenderSystem::ComputeTranslucentRenderData (FASTPATH)" );
  1383. m_pRenderContext->AddRefRenderData();
  1384. pTempData->m_bReleaseRenderData = true;
  1385. ModelRenderMode_t renderMode = MODEL_RENDER_MODE_NORMAL;
  1386. // FIXME: This is infected-specific for perf test reasons.
  1387. // Will break into a more fixed pipeline at a later date
  1388. DataCacheHandle_t *pColorMeshHandles = pTempData->m_pColorMeshHandles;
  1389. ModelListByType_t *pModelList = (ModelListByType_t*)stackalloc( nCount * sizeof(ModelListByType_t) );
  1390. ModelListNode_t *pModelListNode = (ModelListNode_t*)stackalloc( nCount * sizeof(ModelListNode_t) );
  1391. int nModelsRenderingStencilCount = 0;
  1392. int nModelTypeCount = BucketModelsByMDL( pModelList, pModelListNode, pModels, nCount, renderMode, &nModelsRenderingStencilCount );
  1393. LightingList_t pLightingList[ LIGHTING_MODEL_COUNT ];
  1394. memset( pLightingList, 0, LIGHTING_MODEL_COUNT * sizeof(LightingList_t) );
  1395. SortBucketsByDependency( nModelTypeCount, pModelList, pLightingList );
  1396. // Compute LODs for each model
  1397. ComputeModelLODs( nModelTypeCount, pModelList, pModelListNode, renderMode );
  1398. // Sort processing list by body, lod, skin, etc.
  1399. RenderModelInfo_t *pSortedModelListNode = (RenderModelInfo_t*)stackalloc( nCount * sizeof(RenderModelInfo_t) );
  1400. SortModels( pSortedModelListNode, nCount, nModelTypeCount, pModelList, pModelListNode );
  1401. // Setup bones
  1402. SetupBones( nModelTypeCount, pModelList );
  1403. // Setup flexes
  1404. SetupFlexes( nModelTypeCount, pModelList );
  1405. // Setup lighting
  1406. pTempData->m_nColorMeshHandleCount = SetupLighting( pLightingList, nModelTypeCount, pModelList, pColorMeshHandles, renderMode );
  1407. // Setup flashlights + decals
  1408. StudioModelArrayInfo2_t info;
  1409. SetupFlashlightsAndDecals( &info, nModelTypeCount, pModelList, nCount, pSortedModelListNode, renderMode );
  1410. // Setup per-instance color modulation
  1411. SetupPerInstanceColorModulation( nModelTypeCount, pModelList );
  1412. // Setup per-instance wound data
  1413. // SetupInfectedWoundRenderData( nModelTypeCount, pModelList, nCount, renderMode );
  1414. // Draw models
  1415. SetupTranslucentData( nModelTypeCount, pModelList, nCount, pRenderData );
  1416. // Blat out temporary memory for bone-to-world transforms
  1417. m_BoneToWorld.FreeAll( false );
  1418. RenderDebugOverlays( nModelTypeCount, pModelList, renderMode );
  1419. m_pRenderContext = NULL;
  1420. }
  1421. void CModelRenderSystem::CleanupTranslucentTempData( TranslucentTempData_t *pTempData )
  1422. {
  1423. if ( pTempData->m_bReleaseRenderData )
  1424. {
  1425. modelrender->CleanupStaticLightingState( pTempData->m_nColorMeshHandleCount, pTempData->m_pColorMeshHandles );
  1426. CMatRenderContextPtr matRenderContext( g_pMaterialSystem );
  1427. matRenderContext->ReleaseRenderData();
  1428. }
  1429. }
  1430. //-----------------------------------------------------------------------------
  1431. //
  1432. // Brush model rendering system starts here
  1433. //
  1434. //-----------------------------------------------------------------------------
  1435. //-----------------------------------------------------------------------------
  1436. // Adds a model to the list of brush models to render
  1437. //-----------------------------------------------------------------------------
  1438. void CModelRenderSystem::AddBrushModelToList( int nInitialListIndex, ModelRenderSystemData_t &data,
  1439. ModelRenderMode_t renderMode, BrushArrayInstanceData_t &instance, matrix3x4a_t &brushToWorld )
  1440. {
  1441. const model_t *pModel = data.m_pRenderable->GetModel();
  1442. Assert( modelinfo->GetModelType( pModel ) == mod_brush );
  1443. brushToWorld = data.m_pRenderable->RenderableToWorldTransform();
  1444. instance.m_pBrushToWorld = &brushToWorld;
  1445. instance.m_pBrushModel = pModel;
  1446. instance.m_pStencilState = NULL;
  1447. uint bWantsStencil = 0;
  1448. if ( data.m_pModelRenderable )
  1449. {
  1450. if ( renderMode == MODEL_RENDER_MODE_NORMAL )
  1451. {
  1452. // I considered making a MODEL_DATA_STENCIL_ENABLE renderdata type that would only return a bool
  1453. // if stencil was enabled, but it turns out most of the work for MODEL_DATA_STENCIL is computing
  1454. // that bool, so pulling this out into a separate piece didn't turn out to be a perf win.
  1455. ShaderStencilState_t tempStencil;
  1456. bWantsStencil = data.m_pModelRenderable->GetRenderData( &tempStencil, MODEL_DATA_STENCIL ) ? 1 : 0;
  1457. if ( bWantsStencil )
  1458. {
  1459. CMatRenderData< ShaderStencilState_t > rdStencil( m_pRenderContext, 1 );
  1460. memcpy( &rdStencil[0], &tempStencil, sizeof( tempStencil ) );
  1461. instance.m_pStencilState = &rdStencil[0];
  1462. // Not working yet...
  1463. Assert( 0 );
  1464. }
  1465. }
  1466. }
  1467. else
  1468. {
  1469. ExecuteOnce( DevWarning( "data.m_pModelRenderable is NULL for %s\n", modelinfo->GetModelName( pModel ) ) );
  1470. }
  1471. }
  1472. void CModelRenderSystem::SetupPerInstanceColorModulation( int nCount, ModelRenderSystemData_t *pModels, BrushArrayInstanceData_t *pInstanceData, ModelRenderMode_t renderMode )
  1473. {
  1474. if ( renderMode != MODEL_RENDER_MODE_NORMAL )
  1475. return;
  1476. Vector vecColorModulation;
  1477. for ( int i = 0; i < nCount; ++i )
  1478. {
  1479. IClientRenderable *pRenderable = pModels[i].m_pRenderable;
  1480. pRenderable->GetColorModulation( pInstanceData[i].m_DiffuseModulation.AsVector3D().Base() );
  1481. pInstanceData[i].m_DiffuseModulation.w = pModels[i].m_InstanceData.m_nAlpha * ( 1.0f / 255.0f );
  1482. }
  1483. }
  1484. void CModelRenderSystem::DrawBrushModels( ModelRenderSystemData_t *pModels, int nCount, ModelRenderMode_t renderMode )
  1485. {
  1486. if ( nCount == 0 || cl_skipfastpath.GetInt() )
  1487. return;
  1488. VPROF_BUDGET( "CModelRenderSystem::DrawBrushModels", VPROF_BUDGETGROUP_BRUSH_FAST_PATH_RENDERING );
  1489. // While doing this, we need materialsystem to keep around its temp allocations
  1490. // which we use for bone matrices + flexes
  1491. CMatRenderContextPtr matRenderContext( g_pMaterialSystem );
  1492. m_pRenderContext = matRenderContext;
  1493. PIXEVENT( m_pRenderContext, "CModelRenderSystem::DrawBrushModels (FASTPATH)" );
  1494. CMatRenderDataReference rdLock( m_pRenderContext );
  1495. CMatRenderData< BrushArrayInstanceData_t > rdInstances( m_pRenderContext, nCount );
  1496. CMatRenderData< matrix3x4a_t > rdMatrices( m_pRenderContext, nCount );
  1497. for ( int i = 0; i < nCount; ++i )
  1498. {
  1499. AddBrushModelToList( i, pModels[i], renderMode, rdInstances[i], rdMatrices[i] );
  1500. }
  1501. SetupPerInstanceColorModulation( nCount, pModels, rdInstances.Base(), renderMode );
  1502. // Two pass is telling it to only do the opaque portion of the brush model
  1503. int nFlags = STUDIO_RENDER | STUDIO_TWOPASS;
  1504. switch( renderMode )
  1505. {
  1506. case MODEL_RENDER_MODE_NORMAL:
  1507. break;
  1508. case MODEL_RENDER_MODE_SHADOW_DEPTH:
  1509. nFlags |= STUDIO_SHADOWDEPTHTEXTURE;
  1510. break;
  1511. case MODEL_RENDER_MODE_RTT_SHADOWS:
  1512. nFlags |= STUDIO_SHADOWTEXTURE;
  1513. break;
  1514. };
  1515. render->DrawBrushModelArray( m_pRenderContext, nCount, rdInstances.Base(), nFlags );
  1516. rdLock.Release();
  1517. // RenderDebugOverlays( nModelTypeCount, pModelList, renderMode );
  1518. m_pRenderContext = NULL;
  1519. }