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.

2710 lines
100 KiB

  1. //===== Copyright (c) 1996-2007, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include <stdlib.h>
  7. #include <algorithm>
  8. #include "studiorender.h"
  9. #include "studiorendercontext.h"
  10. #include "materialsystem/imaterialsystem.h"
  11. #include "materialsystem/imaterialsystemhardwareconfig.h"
  12. #include "materialsystem/imaterial.h"
  13. #include "materialsystem/imaterialvar.h"
  14. #include "materialsystem/imesh.h"
  15. #include "optimize.h"
  16. #include "mathlib/vmatrix.h"
  17. #include "tier0/vprof.h"
  18. #include "tier1/strtools.h"
  19. #include "tier1/keyvalues.h"
  20. #include "tier0/memalloc.h"
  21. #include "convar.h"
  22. #include "materialsystem/itexture.h"
  23. #include "tier2/tier2.h"
  24. // memdbgon must be the last include file in a .cpp file!!!
  25. #include "tier0/memdbgon.h"
  26. //-----------------------------------------------------------------------------
  27. // Singleton instance
  28. //-----------------------------------------------------------------------------
  29. CStudioRender g_StudioRender;
  30. CStudioRender *g_pStudioRenderImp = &g_StudioRender;
  31. //-----------------------------------------------------------------------------
  32. // Activate to get stats
  33. //-----------------------------------------------------------------------------
  34. //#define REPORT_FLEX_STATS 1
  35. #ifdef REPORT_FLEX_STATS
  36. static int s_nModelsDrawn = 0;
  37. static int s_nActiveFlexCount = 0;
  38. static ConVar r_flexstats( "r_flexstats", "0", FCVAR_CHEAT );
  39. #endif
  40. // Multiplicative factor on LOD switch points. See GetLODForMetric() in studio.h
  41. static ConVar r_lod_switch_scale( "r_lod_switch_scale", "1", FCVAR_HIDDEN );
  42. #ifndef _CERT
  43. static ConVar mat_rendered_faces_count( "mat_rendered_faces_count", "0", FCVAR_CHEAT, "Set to N to count how many faces each model draws each frame and spew the top N offenders from the last 150 frames (use 'mat_rendered_faces_spew' to spew all models rendered in the current frame)" );
  44. static ConVar mat_print_top_model_vert_counts( "mat_print_top_model_vert_counts", "0", 0, "Constantly print to screen the top N models as measured by total faces rendered this frame");
  45. bool ModelFaceCountHashCompareFunc( studiohwdata_t *const &a, studiohwdata_t *const &b ) { return a == b; }
  46. uint32 ModelFaceCountHashKeyFunc( studiohwdata_t *const &a ) { return HashIntConventional( (int32)(intp)a ); }
  47. #endif // !_CERT
  48. //-----------------------------------------------------------------------------
  49. // Constructor
  50. //-----------------------------------------------------------------------------
  51. CStudioRender::CStudioRender()
  52. #ifndef _CERT
  53. : m_ModelFaceCountHash( 1024, 0, 0, ModelFaceCountHashCompareFunc, ModelFaceCountHashKeyFunc )
  54. #endif
  55. {
  56. m_pRC = NULL;
  57. m_pBoneToWorld = NULL;
  58. m_pFlexWeights = NULL;
  59. m_pFlexDelayedWeights = NULL;
  60. m_pStudioHdr = NULL;
  61. m_pStudioMeshes = NULL;
  62. m_pSubModel = NULL;
  63. m_pStudioHWData = NULL;
  64. m_pGlintTexture = NULL;
  65. m_GlintWidth = 0;
  66. m_GlintHeight = 0;
  67. m_pCurrentFlashlight = 0;
  68. // Cache-align our important matrices
  69. g_pMemAlloc->PushAllocDbgInfo( __FILE__, __LINE__ );
  70. m_PoseToWorld = (matrix3x4_t*)MemAlloc_AllocAligned( MAXSTUDIOBONES * sizeof(matrix3x4_t), 32 );
  71. m_PoseToDecal = (matrix3x4_t*)MemAlloc_AllocAligned( MAXSTUDIOBONES * sizeof(matrix3x4_t), 32 );
  72. g_pMemAlloc->PopAllocDbgInfo();
  73. m_nDecalId = 1;
  74. }
  75. CStudioRender::~CStudioRender()
  76. {
  77. MemAlloc_FreeAligned(m_PoseToWorld);
  78. MemAlloc_FreeAligned(m_PoseToDecal);
  79. }
  80. void CStudioRender::InitDebugMaterials( void )
  81. {
  82. // Four Wireframe Materials: ( ZBuffer, DisplacementMapped )
  83. m_pMaterialWireframe[0][0] = g_pMaterialSystem->FindMaterial( "//platform/materials/debug/debugmrmwireframe", TEXTURE_GROUP_OTHER, true );
  84. m_pMaterialWireframe[0][0]->IncrementReferenceCount();
  85. m_pMaterialWireframe[1][0] = g_pMaterialSystem->FindMaterial( "//platform/materials/debug/debugmrmwireframezbuffer", TEXTURE_GROUP_OTHER, true );
  86. m_pMaterialWireframe[1][0]->IncrementReferenceCount();
  87. m_pMaterialWireframe[0][1] = g_pMaterialSystem->FindMaterial( "//platform/materials/debug/debugmrmwireframedisplaced", TEXTURE_GROUP_OTHER, true );
  88. m_pMaterialWireframe[0][1]->IncrementReferenceCount();
  89. m_pMaterialWireframe[1][1] = g_pMaterialSystem->FindMaterial( "//platform/materials/debug/debugmrmwireframezbufferdisplaced", TEXTURE_GROUP_OTHER, true );
  90. m_pMaterialWireframe[1][1]->IncrementReferenceCount();
  91. m_pMaterialMRMNormals = g_pMaterialSystem->FindMaterial( "//platform/materials/debug/debugmrmnormals", TEXTURE_GROUP_OTHER, true );
  92. m_pMaterialMRMNormals->IncrementReferenceCount();
  93. m_pMaterialTangentFrame = g_pMaterialSystem->FindMaterial( "//platform/materials/debug/debugvertexcolor", TEXTURE_GROUP_OTHER, true );
  94. m_pMaterialTangentFrame->IncrementReferenceCount();
  95. m_pMaterialTranslucentModelHulls = g_pMaterialSystem->FindMaterial( "//platform/materials/debug/debugtranslucentmodelhulls", TEXTURE_GROUP_OTHER, true );
  96. m_pMaterialTranslucentModelHulls->IncrementReferenceCount();
  97. m_pMaterialSolidModelHulls = g_pMaterialSystem->FindMaterial( "//platform/materials/debug/debugsolidmodelhulls", TEXTURE_GROUP_OTHER, true );
  98. m_pMaterialSolidModelHulls->IncrementReferenceCount();
  99. m_pMaterialAdditiveVertexColorVertexAlpha = g_pMaterialSystem->FindMaterial( "//platform/materials/debug/additivevertexcolorvertexalpha", TEXTURE_GROUP_OTHER, true );
  100. m_pMaterialAdditiveVertexColorVertexAlpha->IncrementReferenceCount();
  101. m_pMaterialModelBones = g_pMaterialSystem->FindMaterial( "//platform/materials/debug/debugmodelbones", TEXTURE_GROUP_OTHER, true );
  102. m_pMaterialModelBones->IncrementReferenceCount();
  103. m_pMaterialModelEnvCubemap = g_pMaterialSystem->FindMaterial( "//platform/materials/debug/env_cubemap_model", TEXTURE_GROUP_OTHER, true );
  104. m_pMaterialModelEnvCubemap->IncrementReferenceCount();
  105. m_pMaterialWorldWireframe = g_pMaterialSystem->FindMaterial( "//platform/materials/debug/debugworldwireframe", TEXTURE_GROUP_OTHER, true );
  106. m_pMaterialWorldWireframe->IncrementReferenceCount();
  107. KeyValues *pVMTKeyValues = new KeyValues( "DepthWrite" );
  108. pVMTKeyValues->SetInt( "$no_fullbright", 1 );
  109. pVMTKeyValues->SetInt( "$alphatest", 0 );
  110. pVMTKeyValues->SetInt( "$nocull", 0 );
  111. pVMTKeyValues->SetInt( "$treesway", 0 );
  112. pVMTKeyValues->SetInt("$color_depth", 0);
  113. m_pDepthWrite[0][0][0] = g_pMaterialSystem->FindProceduralMaterial("__DepthWrite000", TEXTURE_GROUP_OTHER, pVMTKeyValues);
  114. m_pDepthWrite[0][0][0]->IncrementReferenceCount();
  115. pVMTKeyValues = new KeyValues( "DepthWrite" );
  116. pVMTKeyValues->SetInt( "$no_fullbright", 1 );
  117. pVMTKeyValues->SetInt( "$alphatest", 0 );
  118. pVMTKeyValues->SetInt( "$nocull", 1 );
  119. pVMTKeyValues->SetInt( "$treesway", 0 );
  120. pVMTKeyValues->SetInt("$color_depth", 0);
  121. m_pDepthWrite[0][1][0] = g_pMaterialSystem->FindProceduralMaterial("__DepthWrite010", TEXTURE_GROUP_OTHER, pVMTKeyValues);
  122. m_pDepthWrite[0][1][0]->IncrementReferenceCount();
  123. pVMTKeyValues = new KeyValues( "DepthWrite" );
  124. pVMTKeyValues->SetInt( "$no_fullbright", 1 );
  125. pVMTKeyValues->SetInt( "$alphatest", 1 );
  126. pVMTKeyValues->SetInt( "$nocull", 0 );
  127. pVMTKeyValues->SetInt( "$treesway", 0 );
  128. pVMTKeyValues->SetInt("$color_depth", 0);
  129. m_pDepthWrite[1][0][0] = g_pMaterialSystem->FindProceduralMaterial("__DepthWrite100", TEXTURE_GROUP_OTHER, pVMTKeyValues);
  130. m_pDepthWrite[1][0][0]->IncrementReferenceCount();
  131. pVMTKeyValues = new KeyValues( "DepthWrite" );
  132. pVMTKeyValues->SetInt( "$no_fullbright", 1 );
  133. pVMTKeyValues->SetInt( "$alphatest", 1 );
  134. pVMTKeyValues->SetInt( "$nocull", 1 );
  135. pVMTKeyValues->SetInt( "$treesway", 0 );
  136. pVMTKeyValues->SetInt("$color_depth", 0);
  137. m_pDepthWrite[1][1][0] = g_pMaterialSystem->FindProceduralMaterial("__DepthWrite110", TEXTURE_GROUP_OTHER, pVMTKeyValues);
  138. m_pDepthWrite[1][1][0]->IncrementReferenceCount();
  139. pVMTKeyValues = new KeyValues( "DepthWrite" );
  140. pVMTKeyValues->SetInt( "$no_fullbright", 1 );
  141. pVMTKeyValues->SetInt( "$alphatest", 0 );
  142. pVMTKeyValues->SetInt( "$nocull", 0 );
  143. pVMTKeyValues->SetInt( "$treesway", 1 );
  144. pVMTKeyValues->SetInt("$color_depth", 0);
  145. m_pDepthWrite[0][0][1] = g_pMaterialSystem->FindProceduralMaterial("__DepthWrite001", TEXTURE_GROUP_OTHER, pVMTKeyValues);
  146. m_pDepthWrite[0][0][1]->IncrementReferenceCount();
  147. pVMTKeyValues = new KeyValues( "DepthWrite" );
  148. pVMTKeyValues->SetInt( "$no_fullbright", 1 );
  149. pVMTKeyValues->SetInt( "$alphatest", 0 );
  150. pVMTKeyValues->SetInt( "$nocull", 1 );
  151. pVMTKeyValues->SetInt( "$treesway", 1 );
  152. pVMTKeyValues->SetInt("$color_depth", 0);
  153. m_pDepthWrite[0][1][1] = g_pMaterialSystem->FindProceduralMaterial("__DepthWrite011", TEXTURE_GROUP_OTHER, pVMTKeyValues);
  154. m_pDepthWrite[0][1][1]->IncrementReferenceCount();
  155. pVMTKeyValues = new KeyValues( "DepthWrite" );
  156. pVMTKeyValues->SetInt( "$no_fullbright", 1 );
  157. pVMTKeyValues->SetInt( "$alphatest", 1 );
  158. pVMTKeyValues->SetInt( "$nocull", 0 );
  159. pVMTKeyValues->SetInt( "$treesway", 1 );
  160. pVMTKeyValues->SetInt("$color_depth", 0);
  161. m_pDepthWrite[1][0][1] = g_pMaterialSystem->FindProceduralMaterial("__DepthWrite101", TEXTURE_GROUP_OTHER, pVMTKeyValues);
  162. m_pDepthWrite[1][0][1]->IncrementReferenceCount();
  163. pVMTKeyValues = new KeyValues( "DepthWrite" );
  164. pVMTKeyValues->SetInt( "$no_fullbright", 1 );
  165. pVMTKeyValues->SetInt( "$alphatest", 1 );
  166. pVMTKeyValues->SetInt( "$nocull", 1 );
  167. pVMTKeyValues->SetInt( "$treesway", 1 );
  168. pVMTKeyValues->SetInt("$color_depth", 0);
  169. m_pDepthWrite[1][1][1] = g_pMaterialSystem->FindProceduralMaterial("__DepthWrite111", TEXTURE_GROUP_OTHER, pVMTKeyValues);
  170. m_pDepthWrite[1][1][1]->IncrementReferenceCount();
  171. // Full frame depth as color (r32f)
  172. pVMTKeyValues = new KeyValues( "DepthWrite" );
  173. pVMTKeyValues->SetInt( "$no_fullbright", 1 );
  174. pVMTKeyValues->SetInt( "$alphatest", 0 );
  175. pVMTKeyValues->SetInt( "$nocull", 0 );
  176. pVMTKeyValues->SetInt( "$treesway", 0 );
  177. pVMTKeyValues->SetInt( "$color_depth", 1 );
  178. m_pSSAODepthWrite[ 0 ][ 0 ][ 0 ] = g_pMaterialSystem->FindProceduralMaterial( "__ColorDepthWrite000", TEXTURE_GROUP_OTHER, pVMTKeyValues );
  179. m_pSSAODepthWrite[ 0 ][ 0 ][ 0 ]->IncrementReferenceCount();
  180. pVMTKeyValues = new KeyValues( "DepthWrite" );
  181. pVMTKeyValues->SetInt( "$no_fullbright", 1 );
  182. pVMTKeyValues->SetInt( "$alphatest", 0 );
  183. pVMTKeyValues->SetInt( "$nocull", 1 );
  184. pVMTKeyValues->SetInt( "$treesway", 0 );
  185. pVMTKeyValues->SetInt( "$color_depth", 1 );
  186. m_pSSAODepthWrite[ 0 ][ 1 ][ 0 ] = g_pMaterialSystem->FindProceduralMaterial( "__ColorDepthWrite010", TEXTURE_GROUP_OTHER, pVMTKeyValues );
  187. m_pSSAODepthWrite[ 0 ][ 1 ][ 0 ]->IncrementReferenceCount();
  188. pVMTKeyValues = new KeyValues( "DepthWrite" );
  189. pVMTKeyValues->SetInt( "$no_fullbright", 1 );
  190. pVMTKeyValues->SetInt( "$alphatest", 1 );
  191. pVMTKeyValues->SetInt( "$nocull", 0 );
  192. pVMTKeyValues->SetInt( "$treesway", 0 );
  193. pVMTKeyValues->SetInt( "$color_depth", 1 );
  194. m_pSSAODepthWrite[ 1 ][ 0 ][ 0 ] = g_pMaterialSystem->FindProceduralMaterial( "__ColorDepthWrite100", TEXTURE_GROUP_OTHER, pVMTKeyValues );
  195. m_pSSAODepthWrite[ 1 ][ 0 ][ 0 ]->IncrementReferenceCount();
  196. pVMTKeyValues = new KeyValues( "DepthWrite" );
  197. pVMTKeyValues->SetInt( "$no_fullbright", 1 );
  198. pVMTKeyValues->SetInt( "$alphatest", 1 );
  199. pVMTKeyValues->SetInt( "$nocull", 1 );
  200. pVMTKeyValues->SetInt( "$treesway", 0 );
  201. pVMTKeyValues->SetInt( "$color_depth", 1 );
  202. m_pSSAODepthWrite[ 1 ][ 1 ][ 0 ] = g_pMaterialSystem->FindProceduralMaterial( "__ColorDepthWrite110", TEXTURE_GROUP_OTHER, pVMTKeyValues );
  203. m_pSSAODepthWrite[ 1 ][ 1 ][ 0 ]->IncrementReferenceCount();
  204. pVMTKeyValues = new KeyValues( "DepthWrite" );
  205. pVMTKeyValues->SetInt( "$no_fullbright", 1 );
  206. pVMTKeyValues->SetInt( "$alphatest", 0 );
  207. pVMTKeyValues->SetInt( "$nocull", 0 );
  208. pVMTKeyValues->SetInt( "$treesway", 1 );
  209. pVMTKeyValues->SetInt( "$color_depth", 1 );
  210. m_pSSAODepthWrite[ 0 ][ 0 ][ 1 ] = g_pMaterialSystem->FindProceduralMaterial( "__ColorDepthWrite001", TEXTURE_GROUP_OTHER, pVMTKeyValues );
  211. m_pSSAODepthWrite[ 0 ][ 0 ][ 1 ]->IncrementReferenceCount();
  212. pVMTKeyValues = new KeyValues( "DepthWrite" );
  213. pVMTKeyValues->SetInt( "$no_fullbright", 1 );
  214. pVMTKeyValues->SetInt( "$alphatest", 0 );
  215. pVMTKeyValues->SetInt( "$nocull", 1 );
  216. pVMTKeyValues->SetInt( "$treesway", 1 );
  217. pVMTKeyValues->SetInt( "$color_depth", 1 );
  218. m_pSSAODepthWrite[ 0 ][ 1 ][ 1 ] = g_pMaterialSystem->FindProceduralMaterial( "__ColorDepthWrite011", TEXTURE_GROUP_OTHER, pVMTKeyValues );
  219. m_pSSAODepthWrite[ 0 ][ 1 ][ 1 ]->IncrementReferenceCount();
  220. pVMTKeyValues = new KeyValues( "DepthWrite" );
  221. pVMTKeyValues->SetInt( "$no_fullbright", 1 );
  222. pVMTKeyValues->SetInt( "$alphatest", 1 );
  223. pVMTKeyValues->SetInt( "$nocull", 0 );
  224. pVMTKeyValues->SetInt( "$treesway", 1 );
  225. pVMTKeyValues->SetInt( "$color_depth", 1 );
  226. m_pSSAODepthWrite[ 1 ][ 0 ][ 1 ] = g_pMaterialSystem->FindProceduralMaterial( "__ColorDepthWrite101", TEXTURE_GROUP_OTHER, pVMTKeyValues );
  227. m_pSSAODepthWrite[ 1 ][ 0 ][ 1 ]->IncrementReferenceCount();
  228. pVMTKeyValues = new KeyValues( "DepthWrite" );
  229. pVMTKeyValues->SetInt( "$no_fullbright", 1 );
  230. pVMTKeyValues->SetInt( "$alphatest", 1 );
  231. pVMTKeyValues->SetInt( "$nocull", 1 );
  232. pVMTKeyValues->SetInt( "$treesway", 1 );
  233. pVMTKeyValues->SetInt( "$color_depth", 1 );
  234. m_pSSAODepthWrite[ 1 ][ 1 ][ 1 ] = g_pMaterialSystem->FindProceduralMaterial( "__ColorDepthWrite111", TEXTURE_GROUP_OTHER, pVMTKeyValues );
  235. m_pSSAODepthWrite[ 1 ][ 1 ][ 1 ]->IncrementReferenceCount();
  236. pVMTKeyValues = new KeyValues( "EyeGlint" );
  237. m_pGlintBuildMaterial = g_pMaterialSystem->CreateMaterial( "___glintbuildmaterial", pVMTKeyValues );
  238. pVMTKeyValues = new KeyValues( "unlitgeneric" );
  239. pVMTKeyValues->SetInt( "$color", 0 );
  240. pVMTKeyValues->SetInt( "$nocull", 1 );
  241. pVMTKeyValues->SetInt( "$writez", 0 );
  242. m_pMaterialSolidBackfacePrepass = g_pMaterialSystem->FindProceduralMaterial( "__utilBackfacePrepass", TEXTURE_GROUP_OTHER, pVMTKeyValues );
  243. m_pMaterialSolidBackfacePrepass->IncrementReferenceCount();
  244. }
  245. void CStudioRender::ShutdownDebugMaterials( void )
  246. {
  247. for ( int i=0; i<2; i++ )
  248. {
  249. for ( int j=0; j<2; j++ )
  250. {
  251. if ( m_pMaterialWireframe[i][j] )
  252. {
  253. m_pMaterialWireframe[i][j]->DecrementReferenceCount();
  254. m_pMaterialWireframe[i][j] = NULL;
  255. }
  256. }
  257. }
  258. if ( m_pMaterialMRMNormals )
  259. {
  260. m_pMaterialMRMNormals->DecrementReferenceCount();
  261. m_pMaterialMRMNormals = NULL;
  262. }
  263. if ( m_pMaterialTangentFrame )
  264. {
  265. m_pMaterialTangentFrame->DecrementReferenceCount();
  266. m_pMaterialTangentFrame = NULL;
  267. }
  268. if ( m_pMaterialTranslucentModelHulls )
  269. {
  270. m_pMaterialTranslucentModelHulls->DecrementReferenceCount();
  271. m_pMaterialTranslucentModelHulls = NULL;
  272. }
  273. if ( m_pMaterialSolidModelHulls )
  274. {
  275. m_pMaterialSolidModelHulls->DecrementReferenceCount();
  276. m_pMaterialSolidModelHulls = NULL;
  277. }
  278. if ( m_pMaterialAdditiveVertexColorVertexAlpha )
  279. {
  280. m_pMaterialAdditiveVertexColorVertexAlpha->DecrementReferenceCount();
  281. m_pMaterialAdditiveVertexColorVertexAlpha = NULL;
  282. }
  283. if ( m_pMaterialModelBones )
  284. {
  285. m_pMaterialModelBones->DecrementReferenceCount();
  286. m_pMaterialModelBones = NULL;
  287. }
  288. if ( m_pMaterialModelEnvCubemap )
  289. {
  290. m_pMaterialModelEnvCubemap->DecrementReferenceCount();
  291. m_pMaterialModelEnvCubemap = NULL;
  292. }
  293. if ( m_pMaterialWorldWireframe )
  294. {
  295. m_pMaterialWorldWireframe->DecrementReferenceCount();
  296. m_pMaterialWorldWireframe = NULL;
  297. }
  298. // DepthWrite materials
  299. for ( int32 i = 0; i < 8; i++ )
  300. {
  301. if ( m_pDepthWrite[ ( i & 0x4 ) >> 2 ][ ( i & 0x2 ) >> 1 ][ i & 0x1 ] )
  302. {
  303. m_pDepthWrite[ ( i & 0x4 ) >> 2 ][ ( i & 0x2 ) >> 1 ][ i & 0x1 ]->DecrementReferenceCount();
  304. }
  305. if ( m_pSSAODepthWrite[ ( i & 0x4 ) >> 2 ][ ( i & 0x2 ) >> 1 ][ i & 0x1 ] )
  306. {
  307. m_pSSAODepthWrite[ ( i & 0x4 ) >> 2 ][ ( i & 0x2 ) >> 1 ][ i & 0x1 ]->DecrementReferenceCount();
  308. }
  309. }
  310. if ( m_pGlintBuildMaterial )
  311. {
  312. m_pGlintBuildMaterial->DecrementReferenceCount();
  313. m_pGlintBuildMaterial = NULL;
  314. }
  315. if ( m_pMaterialSolidBackfacePrepass )
  316. {
  317. m_pMaterialSolidBackfacePrepass->DecrementReferenceCount();
  318. m_pMaterialSolidBackfacePrepass = NULL;
  319. }
  320. }
  321. static void ReleaseMaterialSystemObjects( int nChangeFlags )
  322. {
  323. // g_StudioRender.UncacheGlint();
  324. }
  325. static void RestoreMaterialSystemObjects( int nChangeFlags )
  326. {
  327. // g_StudioRender.PrecacheGlint();
  328. }
  329. //-----------------------------------------------------------------------------
  330. // Init, shutdown
  331. //-----------------------------------------------------------------------------
  332. InitReturnVal_t CStudioRender::Init()
  333. {
  334. if ( g_pMaterialSystem && g_pMaterialSystemHardwareConfig )
  335. {
  336. g_pMaterialSystem->AddReleaseFunc( ReleaseMaterialSystemObjects );
  337. g_pMaterialSystem->AddRestoreFunc( RestoreMaterialSystemObjects );
  338. InitDebugMaterials();
  339. return INIT_OK;
  340. }
  341. return INIT_FAILED;
  342. }
  343. void CStudioRender::Shutdown( void )
  344. {
  345. UncacheGlint();
  346. ShutdownDebugMaterials();
  347. if ( g_pMaterialSystem )
  348. {
  349. g_pMaterialSystem->RemoveReleaseFunc( ReleaseMaterialSystemObjects );
  350. g_pMaterialSystem->RemoveRestoreFunc( RestoreMaterialSystemObjects );
  351. }
  352. }
  353. //-----------------------------------------------------------------------------
  354. // Begin/End frame methods
  355. //-----------------------------------------------------------------------------
  356. void CStudioRender::BeginFrame( void )
  357. {
  358. #ifndef _CERT
  359. // Clear the model face count hash table for the coming frame
  360. if ( mat_rendered_faces_count.GetBool() || mat_print_top_model_vert_counts.GetBool() )
  361. m_ModelFaceCountHash.RemoveAll();
  362. #endif // !_CERT
  363. PrecacheGlint();
  364. }
  365. void CStudioRender::EndFrame( void )
  366. {
  367. #ifndef _CERT
  368. UpdateModelFaceCounts();
  369. #endif // !_CERT
  370. CleanupDecals();
  371. }
  372. //-----------------------------------------------------------------------------
  373. // Sets the lighting render state
  374. //-----------------------------------------------------------------------------
  375. void CStudioRender::SetLightingRenderState()
  376. {
  377. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  378. // FIXME: What happens when we use the fixed function pipeline but vertex shaders
  379. // are active? For the time being this only works because everything that does
  380. // vertex lighting does, in fact, have a vertex shader which is used to render it.
  381. pRenderContext->SetAmbientLightCube( m_pRC->m_LightBoxColors );
  382. if ( m_pRC->m_Config.bSoftwareLighting )
  383. {
  384. pRenderContext->DisableAllLocalLights();
  385. }
  386. else
  387. {
  388. pRenderContext->SetLights( m_pRC->m_NumLocalLights, m_pRC->m_LocalLights );
  389. }
  390. }
  391. //-----------------------------------------------------------------------------
  392. // Shadow state (affects the models as they are rendered)
  393. //-----------------------------------------------------------------------------
  394. void CStudioRender::AddShadow( IMaterial* pMaterial, void* pProxyData, FlashlightState_t *pFlashlightState, VMatrix *pWorldToTexture, ITexture *pFlashlightDepthTexture )
  395. {
  396. int i = m_ShadowState.AddToTail();
  397. ShadowState_t& state = m_ShadowState[i];
  398. state.m_pMaterial = pMaterial;
  399. state.m_pProxyData = pProxyData;
  400. state.m_pFlashlightState = pFlashlightState;
  401. state.m_pWorldToTexture = pWorldToTexture;
  402. state.m_pFlashlightDepthTexture = pFlashlightDepthTexture;
  403. }
  404. void CStudioRender::ClearAllShadows()
  405. {
  406. m_ShadowState.RemoveAll();
  407. }
  408. void CStudioRender::GetFlexStats( )
  409. {
  410. #ifdef REPORT_FLEX_STATS
  411. static bool s_bLastFlexStats = false;
  412. bool bDoStats = r_flexstats.GetInt() != 0;
  413. if ( bDoStats )
  414. {
  415. if ( !s_bLastFlexStats )
  416. {
  417. s_nModelsDrawn = 0;
  418. s_nActiveFlexCount = 0;
  419. }
  420. // Count number of active weights
  421. int nActiveFlexCount = 0;
  422. for ( int i = 0; i < MAXSTUDIOFLEXDESC; ++i )
  423. {
  424. if ( fabs( m_FlexWeights[i] ) >= 0.001f || fabs( m_FlexDelayedWeights[i] ) >= 0.001f )
  425. {
  426. ++nActiveFlexCount;
  427. }
  428. }
  429. ++s_nModelsDrawn;
  430. s_nActiveFlexCount += nActiveFlexCount;
  431. }
  432. else
  433. {
  434. if ( s_bLastFlexStats )
  435. {
  436. if ( s_nModelsDrawn )
  437. {
  438. Msg( "Average number of flexes/model: %d\n", s_nActiveFlexCount / s_nModelsDrawn );
  439. }
  440. else
  441. {
  442. Msg( "No models rendered to take stats of\n" );
  443. }
  444. s_nModelsDrawn = 0;
  445. s_nActiveFlexCount = 0;
  446. }
  447. }
  448. s_bLastFlexStats = bDoStats;
  449. #endif
  450. }
  451. ConVar cl_skipslowpath( "cl_skipslowpath", "0", FCVAR_CHEAT | FCVAR_MATERIAL_SYSTEM_THREAD, "Set to 1 to skip any models that don't go through the model fast path" );
  452. //-----------------------------------------------------------------------------
  453. // Main model rendering entry point
  454. //-----------------------------------------------------------------------------
  455. void CStudioRender::DrawModel( const DrawModelInfo_t& info, const StudioRenderContext_t &rc,
  456. matrix3x4_t *pBoneToWorld, const FlexWeights_t &flex, int flags )
  457. {
  458. if ( cl_skipslowpath.GetBool () )
  459. return;
  460. VPROF( "CStudioRender::DrawModel");
  461. if ( ( flags & STUDIORENDER_MODEL_IS_CACHEABLE ) && !g_pMDLCache->IsDataLoaded( VoidPtrToMDLHandle( info.m_pStudioHdr->VirtualModel() ), MDLCACHE_STUDIOHWDATA ) )
  462. {
  463. // cacheable models may have had their hw data evicted while they were queued for rendering
  464. return;
  465. }
  466. m_pRC = const_cast< StudioRenderContext_t* >( &rc );
  467. m_pFlexWeights = flex.m_pFlexWeights;
  468. m_pFlexDelayedWeights = flex.m_pFlexDelayedWeights;
  469. m_pBoneToWorld = pBoneToWorld;
  470. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  471. // Disable flex if we're told to...
  472. bool flexConfig = m_pRC->m_Config.bFlex;
  473. if (flags & STUDIORENDER_DRAW_NO_FLEXES)
  474. {
  475. m_pRC->m_Config.bFlex = false;
  476. }
  477. // Enable wireframe if we're told to...
  478. bool bWireframe = m_pRC->m_Config.bWireframe;
  479. if ( flags & STUDIORENDER_DRAW_WIREFRAME )
  480. {
  481. m_pRC->m_Config.bWireframe = true;
  482. }
  483. int boneMask = BONE_USED_BY_VERTEX_AT_LOD( info.m_Lod );
  484. // Preserve the matrices if we're skinning
  485. pRenderContext->MatrixMode( MATERIAL_MODEL );
  486. pRenderContext->PushMatrix();
  487. pRenderContext->LoadIdentity();
  488. m_VertexCache.StartModel();
  489. m_pStudioHdr = info.m_pStudioHdr;
  490. m_pStudioMeshes = info.m_pHardwareData->m_pLODs[info.m_Lod].m_pMeshData;
  491. m_pStudioHWData = info.m_pHardwareData;
  492. #if PIX_ENABLE
  493. char szPIXEventName[128];
  494. sprintf( szPIXEventName, "%s*", m_pStudioHdr->name ); // PIX
  495. PIXEVENT( pRenderContext, szPIXEventName );
  496. #endif
  497. // Bone to world must be set before calling drawmodel; it uses that here
  498. ComputePoseToWorld( m_PoseToWorld, m_pStudioHdr, boneMask, m_pRC->m_ViewOrigin, pBoneToWorld );
  499. bool bOldFlashlightState = false;
  500. if ( pRenderContext->IsCullingEnabledForSinglePassFlashlight() && IsGameConsole() )
  501. {
  502. bOldFlashlightState = pRenderContext->GetFlashlightMode();
  503. pRenderContext->SetFlashlightMode( m_ShadowState.Count() > 0 );
  504. }
  505. if ( ( flags & STUDIORENDER_NO_PRIMARY_DRAW ) == 0 ) // if this flag is set, then we are drawing multiple shadows in separate calls ( probably for capture )
  506. {
  507. R_StudioRenderModel( pRenderContext, info.m_Skin, info.m_Body, info.m_HitboxSet, info.m_pClientEntity,
  508. info.m_pHardwareData->m_pLODs[info.m_Lod].ppMaterials,
  509. info.m_pHardwareData->m_pLODs[info.m_Lod].pMaterialFlags, flags, boneMask, info.m_Lod, info.m_pColorMeshes);
  510. }
  511. if ( pRenderContext->IsCullingEnabledForSinglePassFlashlight() && IsGameConsole() )
  512. {
  513. pRenderContext->SetFlashlightMode( bOldFlashlightState );
  514. }
  515. // Draw all the decals on this model
  516. // If the model is not in memory, this code may not function correctly
  517. // This code assumes the model has been rendered!
  518. // So skip if the model hasn't been rendered
  519. // Also, skip if we're rendering to the shadow depth map
  520. if ( ( m_pStudioMeshes != 0 ) && !( flags & ( STUDIORENDER_SHADOWDEPTHTEXTURE | STUDIORENDER_SSAODEPTHTEXTURE ) ) )
  521. {
  522. // Draw shadows
  523. if ( !( flags & STUDIORENDER_DRAW_NO_SHADOWS ) )
  524. {
  525. DrawShadows( info, flags, boneMask );
  526. }
  527. if ( ( ( flags & STUDIORENDER_DRAW_GROUP_MASK ) != STUDIORENDER_DRAW_TRANSLUCENT_ONLY ) && !( flags & STUDIORENDER_SKIP_DECALS ) )
  528. {
  529. DrawDecal( info, info.m_Lod, info.m_Body );
  530. }
  531. if( (flags & STUDIORENDER_DRAW_GROUP_MASK) != STUDIORENDER_DRAW_TRANSLUCENT_ONLY &&
  532. !( flags & STUDIORENDER_DRAW_NO_SHADOWS ) && !( flags & STUDIORENDER_SKIP_DECALS ) )
  533. {
  534. DrawFlashlightDecals( info, info.m_Lod );
  535. }
  536. }
  537. // Restore the matrices if we're skinning
  538. pRenderContext->MatrixMode( MATERIAL_MODEL );
  539. pRenderContext->PopMatrix();
  540. // Restore the configs
  541. m_pRC->m_Config.bFlex = flexConfig;
  542. m_pRC->m_Config.bWireframe = bWireframe;
  543. #ifdef REPORT_FLEX_STATS
  544. GetFlexStats();
  545. #endif
  546. pRenderContext->SetNumBoneWeights( 0 );
  547. m_pRC = NULL;
  548. m_pBoneToWorld = NULL;
  549. m_pFlexWeights = NULL;
  550. m_pFlexDelayedWeights = NULL;
  551. m_pStudioHdr = NULL;
  552. m_pStudioMeshes = NULL;
  553. m_pStudioHWData = NULL;
  554. }
  555. void CStudioRender::DrawModelStaticProp( const DrawModelInfo_t& info,
  556. const StudioRenderContext_t &rc, const matrix3x4_t& rootToWorld, int flags )
  557. {
  558. if ( cl_skipslowpath.GetBool () )
  559. return;
  560. VPROF( "CStudioRender::DrawModelStaticProp");
  561. m_pRC = const_cast<StudioRenderContext_t*>( &rc );
  562. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  563. memcpy( &m_StaticPropRootToWorld, &rootToWorld, sizeof(matrix3x4_t) );
  564. memcpy( &m_PoseToWorld[0], &rootToWorld, sizeof(matrix3x4_t) );
  565. m_pBoneToWorld = &m_StaticPropRootToWorld;
  566. bool flexConfig = m_pRC->m_Config.bFlex;
  567. m_pRC->m_Config.bFlex = false;
  568. bool bWireframe = m_pRC->m_Config.bWireframe;
  569. if ( flags & STUDIORENDER_DRAW_WIREFRAME )
  570. {
  571. m_pRC->m_Config.bWireframe = true;
  572. }
  573. int lod = info.m_Lod;
  574. m_pStudioHdr = info.m_pStudioHdr;
  575. m_pStudioMeshes = info.m_pHardwareData->m_pLODs[lod].m_pMeshData;
  576. m_pStudioHWData = info.m_pHardwareData;
  577. R_StudioRenderModel( pRenderContext, info.m_Skin, info.m_Body, info.m_HitboxSet, info.m_pClientEntity,
  578. info.m_pHardwareData->m_pLODs[lod].ppMaterials,
  579. info.m_pHardwareData->m_pLODs[lod].pMaterialFlags, flags, BONE_USED_BY_ANYTHING, lod, info.m_pColorMeshes);
  580. // If we're not shadow depth mapping
  581. if ( ( flags & ( STUDIORENDER_SHADOWDEPTHTEXTURE | STUDIORENDER_SSAODEPTHTEXTURE ) ) == 0 )
  582. {
  583. // Draw shadows
  584. if ( !( flags & STUDIORENDER_DRAW_NO_SHADOWS ) )
  585. {
  586. DrawShadows( info, flags, BONE_USED_BY_ANYTHING );
  587. }
  588. // FIXME: Should this occur in a separate call?
  589. // Draw all the decals on this model
  590. if ( ( ( flags & STUDIORENDER_DRAW_GROUP_MASK ) != STUDIORENDER_DRAW_TRANSLUCENT_ONLY ) && !( flags & STUDIORENDER_SKIP_DECALS ) )
  591. {
  592. DrawDecal( info, lod, info.m_Body );
  593. }
  594. if( (flags & STUDIORENDER_DRAW_GROUP_MASK) != STUDIORENDER_DRAW_TRANSLUCENT_ONLY &&
  595. !( flags & STUDIORENDER_DRAW_NO_SHADOWS ) && !( flags & STUDIORENDER_SKIP_DECALS ) )
  596. {
  597. DrawFlashlightDecals( info, lod );
  598. }
  599. }
  600. // Restore the configs
  601. m_pRC->m_Config.bFlex = flexConfig;
  602. m_pRC->m_Config.bWireframe = bWireframe;
  603. pRenderContext->SetNumBoneWeights( 0 );
  604. m_pBoneToWorld = NULL;
  605. m_pRC = NULL;
  606. m_pStudioHdr = NULL;
  607. m_pStudioMeshes = NULL;
  608. m_pStudioHWData = NULL;
  609. }
  610. //-----------------------------------------------------------------------------
  611. // Used to render instances
  612. //-----------------------------------------------------------------------------
  613. struct BaseMeshRenderData_t
  614. {
  615. studiomeshgroup_t *m_pGroup;
  616. mstudiomesh_t *m_pMesh;
  617. IMaterial *m_pMaterial;
  618. };
  619. struct ShadowMeshRenderData_t : public BaseMeshRenderData_t
  620. {
  621. StudioShadowArrayInstanceData_t *m_pInstance;
  622. IMaterial *m_pSrcMaterial;
  623. VertexCompressionType_t m_nCompressionType;
  624. int m_nMeshBoneCount;
  625. bool m_bIsAlphaTested;
  626. bool m_bUsesTreeSway;
  627. };
  628. struct MeshRenderData_t : public BaseMeshRenderData_t
  629. {
  630. StudioArrayInstanceData_t *m_pInstance;
  631. };
  632. struct MeshRenderData2_t : public BaseMeshRenderData_t
  633. {
  634. StudioArrayInstanceData_t *m_pInstance;
  635. int16 m_nCompressionType; // VertexCompressionType_t smooshed to 16 bits
  636. int16 m_nMeshBoneCount;
  637. };
  638. //-----------------------------------------------------------------------------
  639. // Counts the number of meshes to draw
  640. //-----------------------------------------------------------------------------
  641. int CStudioRender::CountMeshesToDraw( const StudioModelArrayInfo_t &drawInfo, int nCount, StudioArrayInstanceData_t *pInstanceData, int nInstanceStride, int nTimesRendered )
  642. {
  643. VPROF( "CStudioRender::CountMeshesToDraw" );
  644. #ifndef _CERT
  645. bool bCountRenderedFaces = mat_rendered_faces_count.GetBool() || mat_print_top_model_vert_counts.GetBool();
  646. #endif // !_CERT
  647. StudioArrayInstanceData_t *pCurInstance = pInstanceData;
  648. int nTotalMeshCount = 0;
  649. for ( int i = 0; i < nCount; ++i, pCurInstance = (StudioArrayInstanceData_t*)( (char*)pCurInstance + nInstanceStride ) )
  650. {
  651. // This subarray has the same skin + body + lod
  652. int nLod = pCurInstance->m_nLOD;
  653. // get the studio mesh data for this lod
  654. studiomeshdata_t *pMeshDataBase = drawInfo.m_pHardwareData->m_pLODs[nLod].m_pMeshData;
  655. #ifndef _CERT
  656. // Each model counts how many rendered faces it accounts for each frame:
  657. if ( bCountRenderedFaces )
  658. drawInfo.m_pHardwareData->UpdateFacesRenderedCount( drawInfo.m_pStudioHdr, m_ModelFaceCountHash, nLod, nTimesRendered );
  659. #endif // !_CERT
  660. int nBody = pCurInstance->m_nBody;
  661. for ( int body = 0; body < drawInfo.m_pStudioHdr->numbodyparts; ++body )
  662. {
  663. mstudiobodyparts_t *pbodypart = drawInfo.m_pStudioHdr->pBodypart( body );
  664. int index = nBody / pbodypart->base;
  665. index = index % pbodypart->nummodels;
  666. mstudiomodel_t *pSubmodel = pbodypart->pModel( index );
  667. for ( int meshIndex = 0; meshIndex < pSubmodel->nummeshes; ++meshIndex )
  668. {
  669. mstudiomesh_t *pMesh = pSubmodel->pMesh(meshIndex);
  670. studiomeshdata_t *pMeshData = &pMeshDataBase[pMesh->meshid];
  671. nTotalMeshCount += pMeshData->m_NumGroup;
  672. }
  673. }
  674. }
  675. return nTotalMeshCount;
  676. }
  677. //-----------------------------------------------------------------------------
  678. // Counts the number of meshes to draw
  679. //-----------------------------------------------------------------------------
  680. int CStudioRender::CountMeshesToDraw( const StudioModelArrayInfo2_t &drawInfo, int nCount, StudioArrayData_t *pArrayData, int nInstanceStride, int nTimesRendered )
  681. {
  682. VPROF( "CStudioRender::CountMeshesToDraw" );
  683. #ifndef _CERT
  684. bool bCountRenderedFaces = mat_rendered_faces_count.GetBool() || mat_print_top_model_vert_counts.GetBool();
  685. #endif // !_CERT
  686. int nTotalMeshCount = 0;
  687. for ( int i = 0; i < nCount; ++i )
  688. {
  689. StudioArrayData_t &arrayData = pArrayData[i];
  690. StudioArrayInstanceData_t *pCurInstance = (StudioArrayInstanceData_t*)( arrayData.m_pInstanceData );
  691. for ( int j = 0; j < arrayData.m_nCount; ++j, pCurInstance = (StudioArrayInstanceData_t*)( (char*)pCurInstance + nInstanceStride ) )
  692. {
  693. // This subarray has the same skin + body + lod
  694. int nLod = pCurInstance->m_nLOD;
  695. // get the studio mesh data for this lod
  696. studiomeshdata_t *pMeshDataBase = arrayData.m_pHardwareData->m_pLODs[nLod].m_pMeshData;
  697. #ifndef _CERT
  698. // Each model counts how many rendered faces it accounts for each frame:
  699. if ( bCountRenderedFaces )
  700. arrayData.m_pHardwareData->UpdateFacesRenderedCount( arrayData.m_pStudioHdr, m_ModelFaceCountHash, nLod, nTimesRendered );
  701. #endif // !_CERT
  702. int nBody = pCurInstance->m_nBody;
  703. for ( int body = 0; body < arrayData.m_pStudioHdr->numbodyparts; ++body )
  704. {
  705. mstudiobodyparts_t *pbodypart = arrayData.m_pStudioHdr->pBodypart( body );
  706. int index = nBody / pbodypart->base;
  707. index = index % pbodypart->nummodels;
  708. mstudiomodel_t *pSubmodel = pbodypart->pModel( index );
  709. for ( int meshIndex = 0; meshIndex < pSubmodel->nummeshes; ++meshIndex )
  710. {
  711. mstudiomesh_t *pMesh = pSubmodel->pMesh(meshIndex);
  712. studiomeshdata_t *pMeshData = &pMeshDataBase[pMesh->meshid];
  713. nTotalMeshCount += pMeshData->m_NumGroup;
  714. }
  715. }
  716. }
  717. }
  718. return nTotalMeshCount;
  719. }
  720. //-----------------------------------------------------------------------------
  721. // Sort models function
  722. //-----------------------------------------------------------------------------
  723. inline bool CStudioRender::SortLessFunc( const MeshRenderData_t &left, const MeshRenderData_t &right )
  724. {
  725. if ( left.m_pMaterial != right.m_pMaterial )
  726. return left.m_pMaterial > right.m_pMaterial;
  727. if ( left.m_pGroup->m_pMesh != right.m_pGroup->m_pMesh )
  728. return left.m_pGroup->m_pMesh > right.m_pGroup->m_pMesh;
  729. if ( left.m_pInstance->m_pEnvCubemapTexture != right.m_pInstance->m_pEnvCubemapTexture )
  730. return left.m_pInstance->m_pEnvCubemapTexture > right.m_pInstance->m_pEnvCubemapTexture;
  731. bool bLeftHasLighting = ( left.m_pInstance->m_pLightingState != NULL );
  732. bool bRightHasLighting = ( right.m_pInstance->m_pLightingState != NULL );
  733. if ( bLeftHasLighting != bRightHasLighting )
  734. return bLeftHasLighting;
  735. if ( !bLeftHasLighting )
  736. return false;
  737. return left.m_pInstance->m_pLightingState->m_nLocalLightCount > right.m_pInstance->m_pLightingState->m_nLocalLightCount;
  738. }
  739. //-----------------------------------------------------------------------------
  740. // Sort models function
  741. //-----------------------------------------------------------------------------
  742. inline bool CStudioRender::SortLessFunc2( const MeshRenderData2_t &left, const MeshRenderData2_t &right )
  743. {
  744. if ( left.m_pMaterial != right.m_pMaterial )
  745. return left.m_pMaterial > right.m_pMaterial;
  746. if ( left.m_nCompressionType != right.m_nCompressionType )
  747. return left.m_nCompressionType > right.m_nCompressionType;
  748. if ( left.m_nMeshBoneCount != right.m_nMeshBoneCount )
  749. return left.m_nMeshBoneCount > right.m_nMeshBoneCount;
  750. bool bLeftHasColorMesh = ( left.m_pInstance->m_pColorMeshInfo != NULL );
  751. bool bRightHasColorMesh = ( right.m_pInstance->m_pColorMeshInfo != NULL );
  752. if ( bLeftHasColorMesh != bRightHasColorMesh )
  753. return bLeftHasColorMesh < bRightHasColorMesh;
  754. if ( left.m_pInstance->m_pEnvCubemapTexture != right.m_pInstance->m_pEnvCubemapTexture )
  755. return left.m_pInstance->m_pEnvCubemapTexture > right.m_pInstance->m_pEnvCubemapTexture;
  756. if ( left.m_pGroup->m_pMesh != right.m_pGroup->m_pMesh )
  757. return left.m_pGroup->m_pMesh > right.m_pGroup->m_pMesh;
  758. bool bLeftHasLighting = ( left.m_pInstance->m_pLightingState != NULL );
  759. bool bRightHasLighting = ( right.m_pInstance->m_pLightingState != NULL );
  760. if ( bLeftHasLighting != bRightHasLighting )
  761. return bLeftHasLighting;
  762. if ( !bLeftHasLighting )
  763. return false;
  764. return left.m_pInstance->m_pLightingState->m_nLocalLightCount > right.m_pInstance->m_pLightingState->m_nLocalLightCount;
  765. }
  766. //-----------------------------------------------------------------------------
  767. // Builds the list of things to render in what order
  768. //-----------------------------------------------------------------------------
  769. int CStudioRender::BuildSortedRenderList( MeshRenderData_t *pRenderData, int *pTotalStripCount, const StudioModelArrayInfo_t &drawInfo,
  770. int nCount, StudioArrayInstanceData_t *pInstanceData, int nInstanceStride, int nFlags )
  771. {
  772. SNPROF( "CStudioRender::BuildSortedRenderList" );
  773. studiohdr_t *pStudioHdr = drawInfo.m_pStudioHdr;
  774. short *pSkinRefBase = pStudioHdr->pSkinref( 0 );
  775. bool bSkipTranslucent = ( nFlags & STUDIORENDER_DRAW_OPAQUE_ONLY ) != 0;
  776. bool bSkipOpaque = ( nFlags & STUDIORENDER_DRAW_TRANSLUCENT_ONLY ) != 0;
  777. bool bSelectiveOverride = ( m_pRC->m_nForcedMaterialType == OVERRIDE_SELECTIVE );
  778. *pTotalStripCount = 0;
  779. StudioArrayInstanceData_t *pCurInstance = pInstanceData;
  780. int nRenderDataCount = 0;
  781. for ( int i = 0; i < nCount; ++i, pCurInstance = (StudioArrayInstanceData_t*)( (char*)pCurInstance + nInstanceStride ) )
  782. {
  783. // This subarray has the same skin + body + lod
  784. int nLod = pCurInstance->m_nLOD;
  785. // get the studio mesh data for this lod
  786. studiomeshdata_t *pMeshDataBase = drawInfo.m_pHardwareData->m_pLODs[nLod].m_pMeshData;
  787. IMaterial **ppMaterials = drawInfo.m_pHardwareData->m_pLODs[nLod].ppMaterials;
  788. short *pSkinRef = pSkinRefBase;
  789. int skin = pCurInstance->m_nSkin;
  790. if ( skin > 0 && skin < pStudioHdr->numskinfamilies )
  791. {
  792. pSkinRef += ( skin * pStudioHdr->numskinref );
  793. }
  794. int nBody = pCurInstance->m_nBody;
  795. for ( int body = 0; body < pStudioHdr->numbodyparts; ++body )
  796. {
  797. mstudiobodyparts_t *pbodypart = pStudioHdr->pBodypart( body );
  798. int index = nBody / pbodypart->base;
  799. index = index % pbodypart->nummodels;
  800. mstudiomodel_t *pSubmodel = pbodypart->pModel( index );
  801. for ( int meshIndex = 0; meshIndex < pSubmodel->nummeshes; ++meshIndex )
  802. {
  803. mstudiomesh_t *pMesh = pSubmodel->pMesh(meshIndex);
  804. studiomeshdata_t *pMeshData = &pMeshDataBase[ pMesh->meshid ];
  805. IMaterial *pMaterial = ppMaterials[ pSkinRef[ pMesh->material ] ];
  806. bool bIsTranslucent = pMaterial->IsTranslucentUnderModulation( pCurInstance->m_DiffuseModulation.w );
  807. if ( bSkipTranslucent && bIsTranslucent )
  808. continue;
  809. else if ( bSkipOpaque && !bIsTranslucent )
  810. continue;
  811. Assert( pMeshData );
  812. // Assert( pMeshData->m_NumGroup ); // can't Assert on m_NumGroup since it can be zero on lods.
  813. for ( int g = 0; g < pMeshData->m_NumGroup; ++g )
  814. {
  815. studiomeshgroup_t* pGroup = &pMeshData->m_pMeshGroup[g];
  816. MeshRenderData_t &data = pRenderData[nRenderDataCount++];
  817. int nOverrideIndex = GetForcedMaterialOverrideIndex( pSkinRef[ pMesh->material ] );
  818. if ( bSelectiveOverride && nOverrideIndex != -1 )
  819. {
  820. data.m_pMaterial = m_pRC->m_pForcedMaterial[ nOverrideIndex ];
  821. }
  822. else
  823. {
  824. data.m_pMaterial = pMaterial;
  825. }
  826. data.m_pGroup = pGroup;
  827. data.m_pInstance = pCurInstance;
  828. data.m_pMesh = pMesh;
  829. *pTotalStripCount += pGroup->m_NumStrips;
  830. }
  831. }
  832. }
  833. }
  834. std::make_heap( pRenderData, pRenderData + nRenderDataCount, SortLessFunc );
  835. std::sort_heap( pRenderData, pRenderData + nRenderDataCount, SortLessFunc );
  836. return nRenderDataCount;
  837. }
  838. //-----------------------------------------------------------------------------
  839. // Builds the list of things to render in what order
  840. //-----------------------------------------------------------------------------
  841. int CStudioRender::BuildSortedRenderList( MeshRenderData2_t *pRenderData, int *pTotalStripCount, const StudioModelArrayInfo2_t &drawInfo,
  842. int nCount, StudioArrayData_t *pArrayData, int nInstanceStride, int nFlags )
  843. {
  844. SNPROF( "CStudioRender::BuildSortedRenderList" );
  845. bool bSkipTranslucent = ( nFlags & STUDIORENDER_DRAW_OPAQUE_ONLY ) != 0;
  846. bool bSkipOpaque = ( nFlags & STUDIORENDER_DRAW_TRANSLUCENT_ONLY ) != 0;
  847. bool bSelectiveOverride = ( m_pRC->m_nForcedMaterialType == OVERRIDE_SELECTIVE );
  848. *pTotalStripCount = 0;
  849. int nRenderDataCount = 0;
  850. for ( int a = 0; a < nCount; ++a )
  851. {
  852. StudioArrayData_t &arrayData = pArrayData[a];
  853. studiohdr_t *pStudioHdr = arrayData.m_pStudioHdr;
  854. short *pSkinRefBase = pStudioHdr->pSkinref( 0 );
  855. StudioArrayInstanceData_t *pCurInstance = (StudioArrayInstanceData_t*)( arrayData.m_pInstanceData );
  856. for ( int i = 0; i < arrayData.m_nCount; ++i, pCurInstance = (StudioArrayInstanceData_t*)( (char*)pCurInstance + nInstanceStride ) )
  857. {
  858. // This subarray has the same skin + body + lod
  859. int nLod = pCurInstance->m_nLOD;
  860. // get the studio mesh data for this lod
  861. studiomeshdata_t *pMeshDataBase = arrayData.m_pHardwareData->m_pLODs[nLod].m_pMeshData;
  862. IMaterial **ppMaterials = arrayData.m_pHardwareData->m_pLODs[nLod].ppMaterials;
  863. short *pSkinRef = pSkinRefBase;
  864. int skin = pCurInstance->m_nSkin;
  865. if ( skin > 0 && skin < pStudioHdr->numskinfamilies )
  866. {
  867. pSkinRef += ( skin * pStudioHdr->numskinref );
  868. }
  869. int nBody = pCurInstance->m_nBody;
  870. for ( int body = 0; body < pStudioHdr->numbodyparts; ++body )
  871. {
  872. mstudiobodyparts_t *pbodypart = pStudioHdr->pBodypart( body );
  873. int index = nBody / pbodypart->base;
  874. index = index % pbodypart->nummodels;
  875. mstudiomodel_t *pSubmodel = pbodypart->pModel( index );
  876. for ( int meshIndex = 0; meshIndex < pSubmodel->nummeshes; ++meshIndex )
  877. {
  878. mstudiomesh_t *pMesh = pSubmodel->pMesh(meshIndex);
  879. studiomeshdata_t *pMeshData = &pMeshDataBase[ pMesh->meshid ];
  880. IMaterial *pMaterial = ppMaterials[ pSkinRef[ pMesh->material ] ];
  881. bool bIsTranslucent = pMaterial->IsTranslucentUnderModulation( pCurInstance->m_DiffuseModulation.w );
  882. if ( bSkipTranslucent && bIsTranslucent )
  883. continue;
  884. else if ( bSkipOpaque && !bIsTranslucent )
  885. continue;
  886. Assert( pMeshData );
  887. // Assert( pMeshData->m_NumGroup ); // can't Assert on m_NumGroup since it can be zero on lods.
  888. for ( int g = 0; g < pMeshData->m_NumGroup; ++g )
  889. {
  890. studiomeshgroup_t* pGroup = &pMeshData->m_pMeshGroup[g];
  891. MeshRenderData2_t &data = pRenderData[nRenderDataCount++];
  892. int nOverrideIndex = GetForcedMaterialOverrideIndex( pSkinRef[ pMesh->material ] );
  893. if ( bSelectiveOverride && nOverrideIndex != -1 )
  894. {
  895. data.m_pMaterial = m_pRC->m_pForcedMaterial[ nOverrideIndex ];
  896. }
  897. else
  898. {
  899. data.m_pMaterial = pMaterial;
  900. }
  901. data.m_pGroup = pGroup;
  902. data.m_pInstance = pCurInstance;
  903. data.m_pMesh = pMesh;
  904. data.m_nCompressionType = CompressionType( pGroup->m_pMesh->GetVertexFormat() );
  905. data.m_nMeshBoneCount = NumBoneWeights( pGroup->m_pMesh->GetVertexFormat() );
  906. data.m_pInstance->m_bColorMeshHasIndirectLightingOnly = ( pStudioHdr->flags & STUDIOHDR_BAKED_VERTEX_LIGHTING_IS_INDIRECT_ONLY ) ? true : false;
  907. *pTotalStripCount += pGroup->m_NumStrips;
  908. }
  909. }
  910. }
  911. }
  912. }
  913. std::make_heap( pRenderData, pRenderData + nRenderDataCount, SortLessFunc2 );
  914. std::sort_heap( pRenderData, pRenderData + nRenderDataCount, SortLessFunc2 );
  915. return nRenderDataCount;
  916. }
  917. //-----------------------------------------------------------------------------
  918. // BuildForcedMaterialRenderList
  919. //-----------------------------------------------------------------------------
  920. void CStudioRender::BuildForcedMaterialRenderList( MeshRenderData_t *pRenderData,
  921. int *pTotalStripCount, const StudioModelArrayInfo_t &drawInfo, const StudioRenderContext_t &rc,
  922. int nCount, StudioArrayInstanceData_t *pInstanceData, int nInstanceStride )
  923. {
  924. VPROF( "CStudioRender::BuildForcedMaterialRenderList" );
  925. studiohdr_t *pStudioHdr = drawInfo.m_pStudioHdr;
  926. *pTotalStripCount = 0;
  927. StudioArrayInstanceData_t *pCurInstance = pInstanceData;
  928. int nRenderDataCount = 0;
  929. for ( int i = 0; i < nCount; ++i, pCurInstance = (StudioArrayInstanceData_t*)( (char*)pCurInstance + nInstanceStride ) )
  930. {
  931. // This subarray has the same skin + body + lod
  932. int nLod = pCurInstance->m_nLOD;
  933. // get the studio mesh data for this lod
  934. studiomeshdata_t *pMeshDataBase = drawInfo.m_pHardwareData->m_pLODs[nLod].m_pMeshData;
  935. int nBody = pCurInstance->m_nBody;
  936. for ( int body = 0; body < pStudioHdr->numbodyparts; ++body )
  937. {
  938. mstudiobodyparts_t *pbodypart = pStudioHdr->pBodypart( body );
  939. int index = nBody / pbodypart->base;
  940. index = index % pbodypart->nummodels;
  941. mstudiomodel_t *pSubmodel = pbodypart->pModel( index );
  942. for ( int meshIndex = 0; meshIndex < pSubmodel->nummeshes; ++meshIndex )
  943. {
  944. mstudiomesh_t *pMesh = pSubmodel->pMesh(meshIndex);
  945. studiomeshdata_t *pMeshData = &pMeshDataBase[pMesh->meshid];
  946. Assert( pMeshData && pMeshData->m_NumGroup );
  947. for ( int g = 0; g < pMeshData->m_NumGroup; ++g )
  948. {
  949. studiomeshgroup_t* pGroup = &pMeshData->m_pMeshGroup[g];
  950. MeshRenderData_t &data = pRenderData[nRenderDataCount++];
  951. data.m_pMaterial = rc.m_pForcedMaterial[ 0 ];
  952. data.m_pGroup = pGroup;
  953. data.m_pInstance = pCurInstance;
  954. data.m_pMesh = pMesh;
  955. *pTotalStripCount += pGroup->m_NumStrips;
  956. }
  957. }
  958. }
  959. }
  960. }
  961. //-----------------------------------------------------------------------------
  962. // BuildForcedMaterialRenderList
  963. //-----------------------------------------------------------------------------
  964. void CStudioRender::BuildForcedMaterialRenderList( MeshRenderData2_t *pRenderData,
  965. int *pTotalStripCount, const StudioModelArrayInfo2_t &drawInfo, const StudioRenderContext_t &rc,
  966. int nCount, StudioArrayData_t *pArrayData, int nInstanceStride )
  967. {
  968. VPROF( "CStudioRender::BuildForcedMaterialRenderList" );
  969. *pTotalStripCount = 0;
  970. int nRenderDataCount = 0;
  971. for ( int a = 0; a < nCount; ++a )
  972. {
  973. StudioArrayData_t &arrayData = pArrayData[a];
  974. studiohdr_t *pStudioHdr = arrayData.m_pStudioHdr;
  975. StudioArrayInstanceData_t *pCurInstance = (StudioArrayInstanceData_t*)( arrayData.m_pInstanceData );
  976. for ( int i = 0; i < arrayData.m_nCount; ++i, pCurInstance = (StudioArrayInstanceData_t*)( (char*)pCurInstance + nInstanceStride ) )
  977. {
  978. // This subarray has the same skin + body + lod
  979. int nLod = pCurInstance->m_nLOD;
  980. // get the studio mesh data for this lod
  981. studiomeshdata_t *pMeshDataBase = arrayData.m_pHardwareData->m_pLODs[nLod].m_pMeshData;
  982. int nBody = pCurInstance->m_nBody;
  983. for ( int body = 0; body < pStudioHdr->numbodyparts; ++body )
  984. {
  985. mstudiobodyparts_t *pbodypart = pStudioHdr->pBodypart( body );
  986. int index = nBody / pbodypart->base;
  987. index = index % pbodypart->nummodels;
  988. mstudiomodel_t *pSubmodel = pbodypart->pModel( index );
  989. for ( int meshIndex = 0; meshIndex < pSubmodel->nummeshes; ++meshIndex )
  990. {
  991. mstudiomesh_t *pMesh = pSubmodel->pMesh(meshIndex);
  992. studiomeshdata_t *pMeshData = &pMeshDataBase[pMesh->meshid];
  993. Assert( pMeshData && pMeshData->m_NumGroup );
  994. for ( int g = 0; g < pMeshData->m_NumGroup; ++g )
  995. {
  996. studiomeshgroup_t* pGroup = &pMeshData->m_pMeshGroup[g];
  997. MeshRenderData2_t &data = pRenderData[nRenderDataCount++];
  998. data.m_pMaterial = rc.m_pForcedMaterial[ 0 ];
  999. data.m_pGroup = pGroup;
  1000. data.m_pInstance = pCurInstance;
  1001. data.m_pMesh = pMesh;
  1002. data.m_nCompressionType = CompressionType( pGroup->m_pMesh->GetVertexFormat() );
  1003. data.m_nMeshBoneCount = NumBoneWeights( pGroup->m_pMesh->GetVertexFormat() );
  1004. *pTotalStripCount += pGroup->m_NumStrips;
  1005. }
  1006. }
  1007. }
  1008. }
  1009. }
  1010. }
  1011. //-----------------------------------------------------------------------------
  1012. // Restores meshes, if necessary
  1013. //-----------------------------------------------------------------------------
  1014. void CStudioRender::RestoreMeshes( int nCount, BaseMeshRenderData_t *pRenderData, int nStride )
  1015. {
  1016. #ifdef IS_WINDOWS_PC
  1017. // FIXME: Can we build a list of unique studiomeshdata_ts?
  1018. for ( int i = 0; i < nCount; ++i, pRenderData = (BaseMeshRenderData_t*)( (unsigned char*)pRenderData + nStride ) )
  1019. {
  1020. BaseMeshRenderData_t &data = *pRenderData;
  1021. studiomeshgroup_t *pGroup = data.m_pGroup;
  1022. // Older models are merely flexed while new ones are also delta flexed
  1023. Assert( !( pGroup->m_Flags & MESHGROUP_IS_DELTA_FLEXED ) );
  1024. // Needed when we switch back and forth between hardware + software lighting
  1025. if ( !pGroup->m_MeshNeedsRestore )
  1026. continue;
  1027. IMesh *pMesh = pGroup->m_pMesh;
  1028. VertexCompressionType_t compressionType = CompressionType( pMesh->GetVertexFormat() );
  1029. switch ( compressionType )
  1030. {
  1031. case VERTEX_COMPRESSION_ON:
  1032. R_StudioRestoreMesh<VERTEX_COMPRESSION_ON>( data.m_pMesh, pGroup );
  1033. break;
  1034. case VERTEX_COMPRESSION_NONE:
  1035. default:
  1036. R_StudioRestoreMesh<VERTEX_COMPRESSION_NONE>( data.m_pMesh, pGroup );
  1037. break;
  1038. }
  1039. pGroup->m_MeshNeedsRestore = false;
  1040. }
  1041. #endif
  1042. }
  1043. //-----------------------------------------------------------------------------
  1044. // Allocate temporary arrays either on the stack, or from the heap.
  1045. // Prevents using all the stack when *lots* of objects are rendered to CSM's.
  1046. //-----------------------------------------------------------------------------
  1047. #if defined( CSTRIKE15 ) // 7ls && !defined( _GAMECONSOLE )
  1048. #define STUDIORENDER_TEMP_DATA_MALLOC( typeName, p, n ) const int nTempDataSize##p = (n); void *pvFree##p = NULL; typeName *p = (typeName *) ( ( nTempDataSize##p < 64*1024 ) ? stackalloc( nTempDataSize##p ) : ( pvFree##p = malloc( nTempDataSize##p ) ) );
  1049. #define STUDIORENDER_TEMP_DATA_FREE( p ) free( pvFree##p )
  1050. #else
  1051. #define STUDIORENDER_TEMP_DATA_MALLOC( typeName, p, n ) typeName *p = (typeName *) stackalloc(n);
  1052. #define STUDIORENDER_TEMP_DATA_FREE( p )
  1053. #endif
  1054. //-----------------------------------------------------------------------------
  1055. // Draws meshes
  1056. //-----------------------------------------------------------------------------
  1057. void CStudioRender::DrawMeshRenderData( IMatRenderContext *pRenderContext,
  1058. const StudioModelArrayInfo_t &drawInfo, int nCount, MeshRenderData_t *pRenderData, int nTotalStripCount, int nFlashlightMask )
  1059. {
  1060. SNPROF( "CStudioRender::DrawMeshRenderData" );
  1061. int nInstanceCount = 0;
  1062. STUDIORENDER_TEMP_DATA_MALLOC( MeshInstanceData_t, pInstance, nTotalStripCount * sizeof(MeshInstanceData_t) );
  1063. IMaterial *pLastMaterial = NULL;
  1064. IMesh *pLastMesh = NULL;
  1065. #ifdef _GAMECONSOLE
  1066. bool bLastUsingFlashlight = false;
  1067. bool bSavedFlashlightEnable = pRenderContext->GetFlashlightMode();
  1068. #endif // _GAMECONSOLE
  1069. int nMaxBoneCount = 0;
  1070. int nMaxLightCount = 0;
  1071. bool bIsSkinned = drawInfo.m_pStudioHdr->numbones > 1;
  1072. #if PIX_ENABLE
  1073. char szPIXEventName[128];
  1074. sprintf( szPIXEventName, "%s*", drawInfo.m_pStudioHdr->name ); // PIX
  1075. PIXEVENT( pRenderContext, szPIXEventName );
  1076. #endif
  1077. for ( int i = 0; i < nCount; ++i )
  1078. {
  1079. MeshRenderData_t &data = pRenderData[i];
  1080. StudioArrayInstanceData_t *pCurrInstance = data.m_pInstance;
  1081. // Skip models not affected by this flashlight
  1082. if ( nFlashlightMask && ( ( nFlashlightMask & pCurrInstance->m_nFlashlightUsage ) == 0 ) )
  1083. continue;
  1084. if ( ( pLastMaterial != data.m_pMaterial ) || ( pLastMesh != data.m_pGroup->m_pMesh )
  1085. #ifdef _GAMECONSOLE
  1086. || ( bLastUsingFlashlight != ( pCurrInstance->m_nFlashlightUsage != 0 ) )
  1087. #endif // _GAMECONSOLE
  1088. )
  1089. {
  1090. if ( nInstanceCount > 0 )
  1091. {
  1092. #ifdef _GAMECONSOLE
  1093. if ( pRenderContext->IsCullingEnabledForSinglePassFlashlight() )
  1094. {
  1095. pRenderContext->SetFlashlightMode( bLastUsingFlashlight );
  1096. }
  1097. #endif // _GAMECONSOLE
  1098. pRenderContext->SetNumBoneWeights( bIsSkinned ? nMaxBoneCount : 0 );
  1099. pRenderContext->Bind( pLastMaterial, NULL );
  1100. pRenderContext->DrawInstances( nInstanceCount, pInstance );
  1101. }
  1102. nInstanceCount = 0;
  1103. nMaxBoneCount = 0;
  1104. nMaxLightCount = 0;
  1105. pLastMesh = data.m_pGroup->m_pMesh;
  1106. pLastMaterial = data.m_pMaterial;
  1107. #ifdef _GAMECONSOLE
  1108. bLastUsingFlashlight = pCurrInstance->m_nFlashlightUsage != 0;
  1109. #endif // _GAMECONSOLE
  1110. }
  1111. studiomeshgroup_t* pGroup = data.m_pGroup;
  1112. for ( int j = 0; j < pGroup->m_NumStrips; ++j )
  1113. {
  1114. OptimizedModel::StripHeader_t* pStrip = &pGroup->m_pStripData[j];
  1115. Assert( nInstanceCount < nTotalStripCount );
  1116. MeshInstanceData_t &instance = pInstance[nInstanceCount++];
  1117. instance.m_pEnvCubemap = pCurrInstance->m_pEnvCubemapTexture;
  1118. instance.m_pPoseToWorld = pCurrInstance->m_pPoseToWorld;
  1119. instance.m_pLightingState = pCurrInstance->m_pLightingState;
  1120. if ( pCurrInstance->m_pColorMeshInfo )
  1121. {
  1122. const ColorMeshInfo_t &colorMesh = pCurrInstance->m_pColorMeshInfo[ pGroup->m_ColorMeshID ];
  1123. instance.m_pColorBuffer = colorMesh.m_pMesh;
  1124. instance.m_nColorVertexOffsetInBytes = colorMesh.m_nVertOffsetInBytes;
  1125. }
  1126. else
  1127. {
  1128. instance.m_pColorBuffer = NULL;
  1129. instance.m_nColorVertexOffsetInBytes = 0;
  1130. }
  1131. instance.m_nBoneCount = pStrip->numBoneStateChanges;
  1132. instance.m_pBoneRemap = ( instance.m_nBoneCount > 0 ) ? (MeshBoneRemap_t*)( pStrip->pBoneStateChange(0) ) : NULL;
  1133. instance.m_nIndexOffset = pStrip->indexOffset;
  1134. instance.m_nIndexCount = pStrip->numIndices;
  1135. instance.m_nPrimType = MATERIAL_TRIANGLES;
  1136. instance.m_pVertexBuffer = data.m_pGroup->m_pMesh;
  1137. instance.m_pIndexBuffer = data.m_pGroup->m_pMesh;
  1138. instance.m_nVertexOffsetInBytes = 0;
  1139. instance.m_pStencilState = pCurrInstance->m_pStencilState;
  1140. instance.m_DiffuseModulation = pCurrInstance->m_DiffuseModulation;
  1141. instance.m_nLightmapPageId = MATERIAL_SYSTEM_LIGHTMAP_PAGE_INVALID;
  1142. instance.m_bColorBufferHasIndirectLightingOnly = ( drawInfo.m_pStudioHdr->flags & STUDIOHDR_BAKED_VERTEX_LIGHTING_IS_INDIRECT_ONLY ) ? true : false;
  1143. nMaxBoneCount = MAX( nMaxBoneCount, pStrip->numBones );
  1144. }
  1145. }
  1146. if ( nInstanceCount > 0 )
  1147. {
  1148. #ifdef _GAMECONSOLE
  1149. if ( pRenderContext->IsCullingEnabledForSinglePassFlashlight() )
  1150. {
  1151. pRenderContext->SetFlashlightMode( bLastUsingFlashlight );
  1152. }
  1153. #endif // _GAMECONSOLE
  1154. pRenderContext->SetNumBoneWeights( bIsSkinned ? nMaxBoneCount : 0 );
  1155. pRenderContext->Bind( pLastMaterial, NULL );
  1156. pRenderContext->DrawInstances( nInstanceCount, pInstance );
  1157. }
  1158. #ifdef _GAMECONSOLE
  1159. pRenderContext->SetFlashlightMode( bSavedFlashlightEnable );
  1160. #endif // _GAMECONSOLE
  1161. pRenderContext->SetNumBoneWeights( 0 );
  1162. STUDIORENDER_TEMP_DATA_FREE( pInstance );
  1163. }
  1164. //-----------------------------------------------------------------------------
  1165. // Draws meshes
  1166. //-----------------------------------------------------------------------------
  1167. void CStudioRender::DrawMeshRenderData( IMatRenderContext *pRenderContext,
  1168. const StudioModelArrayInfo2_t &drawInfo, int nCount, MeshRenderData2_t *pRenderData, int nTotalStripCount, int nFlashlightMask )
  1169. {
  1170. SNPROF( "CStudioRender::DrawMeshRenderData" );
  1171. int nInstanceCount = 0;
  1172. int nMaxBatchSize = IsGameConsole() ? CONSOLE_MAX_MODEL_FAST_PATH_BATCH_SIZE : nTotalStripCount;
  1173. STUDIORENDER_TEMP_DATA_MALLOC( MeshInstanceData_t, pInstance, nMaxBatchSize * sizeof(MeshInstanceData_t) );
  1174. IMaterial *pLastMaterial = NULL;
  1175. int nMaxBoneCount = 0;
  1176. int nMaxLightCount = 0;
  1177. int nLastMeshBoneCount = 0;
  1178. VertexCompressionType_t nLastCompressionType = VERTEX_COMPRESSION_INVALID;
  1179. bool bLastMeshUsedColorMesh = false;
  1180. #ifdef _GAMECONSOLE
  1181. bool bLastUsingFlashlight = false;
  1182. bool bSavedFlashlightEnable = pRenderContext->GetFlashlightMode();
  1183. #endif // _GAMECONSOLE
  1184. int nStartingStripIndex = 0; // used to interrupt batching within a group if the number of strips exceeds the max batch size
  1185. for ( int i = 0; i < nCount; ++i )
  1186. {
  1187. MeshRenderData2_t &data = pRenderData[i];
  1188. StudioArrayInstanceData_t *pCurrInstance = data.m_pInstance;
  1189. // Skip models not affected by this flashlight
  1190. if ( nFlashlightMask && ( ( nFlashlightMask & pCurrInstance->m_nFlashlightUsage ) == 0 ) )
  1191. continue;
  1192. bool bUsingColorMesh = ( pCurrInstance->m_pColorMeshInfo != NULL );
  1193. if ( ( pLastMaterial != data.m_pMaterial ) || // shadow material is different
  1194. ( nLastCompressionType != ( int )data.m_nCompressionType ) || // compression type is different
  1195. ( nLastMeshBoneCount != data.m_nMeshBoneCount ) || // # of bones in the mesh data is different
  1196. ( bLastMeshUsedColorMesh != bUsingColorMesh ) || // Lighting type is different
  1197. ( IsGameConsole() && ( nInstanceCount >= nMaxBatchSize ) ) // max # of batches to render at once due to stack limitations on console
  1198. #ifdef _GAMECONSOLE
  1199. || ( bLastUsingFlashlight != ( pCurrInstance->m_nFlashlightUsage != 0 ) )
  1200. #endif // _GAMECONSOLE
  1201. )
  1202. {
  1203. if ( nInstanceCount > 0 )
  1204. {
  1205. #ifdef _GAMECONSOLE
  1206. if ( pRenderContext->IsCullingEnabledForSinglePassFlashlight() )
  1207. {
  1208. pRenderContext->SetFlashlightMode( bLastUsingFlashlight );
  1209. }
  1210. #endif // _GAMECONSOLE
  1211. pRenderContext->SetNumBoneWeights( nLastMeshBoneCount > 0 ? nMaxBoneCount : 0 );
  1212. pRenderContext->Bind( pLastMaterial, NULL );
  1213. pRenderContext->DrawInstances( nInstanceCount, pInstance );
  1214. }
  1215. nInstanceCount = 0;
  1216. nMaxBoneCount = 0;
  1217. nMaxLightCount = 0;
  1218. nLastCompressionType = ( VertexCompressionType_t )( int )data.m_nCompressionType;
  1219. pLastMaterial = data.m_pMaterial;
  1220. nLastMeshBoneCount = data.m_nMeshBoneCount;
  1221. bLastMeshUsedColorMesh = bUsingColorMesh;
  1222. #ifdef _GAMECONSOLE
  1223. bLastUsingFlashlight = pCurrInstance->m_nFlashlightUsage != 0;
  1224. #endif // _GAMECONSOLE
  1225. }
  1226. studiomeshgroup_t* pGroup = data.m_pGroup;
  1227. int j;
  1228. for ( j = nStartingStripIndex; j < pGroup->m_NumStrips; ++j )
  1229. {
  1230. OptimizedModel::StripHeader_t* pStrip = &pGroup->m_pStripData[j];
  1231. MeshInstanceData_t &instance = pInstance[nInstanceCount++];
  1232. instance.m_pEnvCubemap = pCurrInstance->m_pEnvCubemapTexture;
  1233. instance.m_pPoseToWorld = pCurrInstance->m_pPoseToWorld;
  1234. instance.m_pLightingState = pCurrInstance->m_pLightingState;
  1235. if ( pCurrInstance->m_pColorMeshInfo )
  1236. {
  1237. const ColorMeshInfo_t &colorMesh = pCurrInstance->m_pColorMeshInfo[ pGroup->m_ColorMeshID ];
  1238. instance.m_pColorBuffer = colorMesh.m_pMesh;
  1239. instance.m_nColorVertexOffsetInBytes = colorMesh.m_nVertOffsetInBytes;
  1240. }
  1241. else
  1242. {
  1243. instance.m_pColorBuffer = NULL;
  1244. instance.m_nColorVertexOffsetInBytes = 0;
  1245. }
  1246. instance.m_nBoneCount = pStrip->numBoneStateChanges;
  1247. instance.m_pBoneRemap = ( instance.m_nBoneCount > 0 ) ? (MeshBoneRemap_t*)( pStrip->pBoneStateChange(0) ) : NULL;
  1248. instance.m_nIndexOffset = pStrip->indexOffset;
  1249. instance.m_nIndexCount = pStrip->numIndices;
  1250. instance.m_nPrimType = MATERIAL_TRIANGLES;
  1251. instance.m_pVertexBuffer = data.m_pGroup->m_pMesh;
  1252. instance.m_pIndexBuffer = data.m_pGroup->m_pMesh;
  1253. instance.m_nVertexOffsetInBytes = 0;
  1254. instance.m_pStencilState = pCurrInstance->m_pStencilState;
  1255. instance.m_DiffuseModulation = pCurrInstance->m_DiffuseModulation;
  1256. instance.m_nLightmapPageId = MATERIAL_SYSTEM_LIGHTMAP_PAGE_INVALID;
  1257. instance.m_bColorBufferHasIndirectLightingOnly = pCurrInstance->m_bColorMeshHasIndirectLightingOnly;
  1258. nMaxBoneCount = MAX( nMaxBoneCount, pStrip->numBones );
  1259. if ( IsGameConsole() && nInstanceCount >= nMaxBatchSize )
  1260. {
  1261. break;
  1262. }
  1263. }
  1264. if ( IsGameConsole() && j < pGroup->m_NumStrips )
  1265. {
  1266. // We're going to have to process this pRenderData[] entry again,
  1267. // but start iterating from a higher strip index next time.
  1268. nStartingStripIndex = j + 1;
  1269. -- i;
  1270. }
  1271. else
  1272. {
  1273. nStartingStripIndex = 0;
  1274. }
  1275. }
  1276. if ( nInstanceCount > 0 )
  1277. {
  1278. #ifdef _GAMECONSOLE
  1279. if ( pRenderContext->IsCullingEnabledForSinglePassFlashlight() )
  1280. {
  1281. pRenderContext->SetFlashlightMode( bLastUsingFlashlight );
  1282. }
  1283. #endif // _GAMECONSOLE
  1284. pRenderContext->SetNumBoneWeights( nLastMeshBoneCount > 0 ? nMaxBoneCount : 0 );
  1285. pRenderContext->Bind( pLastMaterial, NULL );
  1286. pRenderContext->DrawInstances( nInstanceCount, pInstance );
  1287. }
  1288. #ifdef _GAMECONSOLE
  1289. pRenderContext->SetFlashlightMode( bSavedFlashlightEnable );
  1290. #endif // _GAMECONSOLE
  1291. pRenderContext->SetNumBoneWeights( 0 );
  1292. STUDIORENDER_TEMP_DATA_FREE( pInstance );
  1293. }
  1294. //-----------------------------------------------------------------------------
  1295. // Draws meshes illuminated by the flashlight
  1296. //-----------------------------------------------------------------------------
  1297. extern ConVar r_flashlightscissor;
  1298. void CStudioRender::DrawModelArrayFlashlight( IMatRenderContext *pRenderContext, const StudioModelArrayInfo_t &drawInfo, int nCount, MeshRenderData_t *pRenderData, int nTotalStripCount )
  1299. {
  1300. int nFlashlightCount = drawInfo.m_nFlashlightCount;
  1301. if ( !nFlashlightCount )
  1302. return;
  1303. pRenderContext->SetFlashlightMode( true );
  1304. bool bDoScissor = r_flashlightscissor.GetBool() && ( pRenderContext->GetRenderTarget() == NULL );
  1305. int i;
  1306. for ( i = 0; i < nFlashlightCount; ++i )
  1307. {
  1308. FlashlightInstance_t &flashlight = drawInfo.m_pFlashlights[i];
  1309. const FlashlightState_t& state = flashlight.m_FlashlightState;
  1310. if ( bDoScissor )
  1311. {
  1312. if ( state.DoScissor() )
  1313. {
  1314. pRenderContext->PushScissorRect( state.GetLeft(), state.GetTop(), state.GetRight(), state.GetBottom() );
  1315. }
  1316. }
  1317. if ( !flashlight.m_pDebugMaterial )
  1318. {
  1319. pRenderContext->SetFlashlightStateEx( state, flashlight.m_WorldToTexture, flashlight.m_pFlashlightDepthTexture );
  1320. DrawMeshRenderData( pRenderContext, drawInfo, nCount, pRenderData, nTotalStripCount, ( 1 << i ) );
  1321. }
  1322. else
  1323. {
  1324. // Debugging mode where we render wireframe on models hit by the flashlight
  1325. // FIXME: Could make this faster, but why bother? It's a debugging mode.
  1326. int nSizeInBytes = nCount * sizeof(MeshRenderData_t);
  1327. STUDIORENDER_TEMP_DATA_MALLOC( MeshRenderData_t, pTempData, nSizeInBytes );
  1328. memcpy( pTempData, pRenderData, nSizeInBytes );
  1329. for ( int j = 0; j < nCount; ++j )
  1330. {
  1331. pTempData[j].m_pMaterial = flashlight.m_pDebugMaterial;
  1332. }
  1333. pRenderContext->SetFlashlightMode( false );
  1334. DrawMeshRenderData( pRenderContext, drawInfo, nCount, pTempData, nTotalStripCount, ( 1 << i ) );
  1335. pRenderContext->SetFlashlightMode( true );
  1336. STUDIORENDER_TEMP_DATA_FREE( pTempData );
  1337. }
  1338. if ( bDoScissor && state.DoScissor() )
  1339. {
  1340. pRenderContext->PopScissorRect();
  1341. }
  1342. }
  1343. pRenderContext->SetFlashlightMode( false );
  1344. }
  1345. //-----------------------------------------------------------------------------
  1346. // Draws meshes illuminated by the flashlight
  1347. //-----------------------------------------------------------------------------
  1348. void CStudioRender::DrawModelArrayFlashlight( IMatRenderContext *pRenderContext, const StudioModelArrayInfo2_t &drawInfo, int nCount, MeshRenderData2_t *pRenderData, int nTotalStripCount )
  1349. {
  1350. int nFlashlightCount = drawInfo.m_nFlashlightCount;
  1351. if ( !nFlashlightCount )
  1352. return;
  1353. pRenderContext->SetFlashlightMode( true );
  1354. bool bDoScissor = r_flashlightscissor.GetBool() && ( pRenderContext->GetRenderTarget() == NULL );
  1355. int i;
  1356. for ( i = 0; i < nFlashlightCount; ++i )
  1357. {
  1358. FlashlightInstance_t &flashlight = drawInfo.m_pFlashlights[i];
  1359. const FlashlightState_t& state = flashlight.m_FlashlightState;
  1360. if ( bDoScissor )
  1361. {
  1362. if ( state.DoScissor() )
  1363. {
  1364. pRenderContext->PushScissorRect( state.GetLeft(), state.GetTop(), state.GetRight(), state.GetBottom() );
  1365. }
  1366. }
  1367. if ( !flashlight.m_pDebugMaterial )
  1368. {
  1369. pRenderContext->SetFlashlightStateEx( state, flashlight.m_WorldToTexture, flashlight.m_pFlashlightDepthTexture );
  1370. DrawMeshRenderData( pRenderContext, drawInfo, nCount, pRenderData, nTotalStripCount, ( 1 << i ) );
  1371. }
  1372. else
  1373. {
  1374. // Debugging mode where we render wireframe on models hit by the flashlight
  1375. // FIXME: Could make this faster, but why bother? It's a debugging mode.
  1376. int nSizeInBytes = nCount * sizeof(MeshRenderData2_t);
  1377. STUDIORENDER_TEMP_DATA_MALLOC( MeshRenderData2_t, pTempData, nSizeInBytes );
  1378. memcpy( pTempData, pRenderData, nSizeInBytes );
  1379. for ( int j = 0; j < nCount; ++j )
  1380. {
  1381. pTempData[j].m_pMaterial = flashlight.m_pDebugMaterial;
  1382. }
  1383. pRenderContext->SetFlashlightMode( false );
  1384. DrawMeshRenderData( pRenderContext, drawInfo, nCount, pTempData, nTotalStripCount, ( 1 << i ) );
  1385. pRenderContext->SetFlashlightMode( true );
  1386. STUDIORENDER_TEMP_DATA_FREE( pTempData );
  1387. }
  1388. if ( bDoScissor && state.DoScissor() )
  1389. {
  1390. pRenderContext->PopScissorRect();
  1391. }
  1392. }
  1393. pRenderContext->SetFlashlightMode( false );
  1394. }
  1395. //-----------------------------------------------------------------------------
  1396. // Draws decals illuminated by the flashlight
  1397. //-----------------------------------------------------------------------------
  1398. void CStudioRender::DrawModelArrayFlashlightDecals( IMatRenderContext *pRenderContext, studiohdr_t *pStudioHdr, int nFlashlightCount, FlashlightInstance_t *pFlashlights, int nCount, DecalRenderData_t *pRenderData )
  1399. {
  1400. if ( !nFlashlightCount )
  1401. return;
  1402. pRenderContext->SetFlashlightMode( true );
  1403. bool bDoScissor = r_flashlightscissor.GetBool() && ( pRenderContext->GetRenderTarget() == NULL );
  1404. int i;
  1405. for ( i = 0; i < nFlashlightCount; ++i )
  1406. {
  1407. FlashlightInstance_t &flashlight = pFlashlights[i];
  1408. const FlashlightState_t& state = flashlight.m_FlashlightState;
  1409. if ( bDoScissor )
  1410. {
  1411. if ( state.DoScissor() )
  1412. {
  1413. pRenderContext->PushScissorRect( state.GetLeft(), state.GetTop(), state.GetRight(), state.GetBottom() );
  1414. }
  1415. }
  1416. if ( !flashlight.m_pDebugMaterial )
  1417. {
  1418. pRenderContext->SetFlashlightStateEx( state, flashlight.m_WorldToTexture, flashlight.m_pFlashlightDepthTexture );
  1419. DrawModelArrayDecals( pRenderContext, pStudioHdr, nCount, pRenderData, ( 1 << i ) );
  1420. }
  1421. else
  1422. {
  1423. // Debugging mode where we render wireframe on models hit by the flashlight
  1424. // FIXME: Could make this faster, but why bother? It's a debugging mode.
  1425. int nSizeInBytes = nCount * sizeof(DecalRenderData_t);
  1426. STUDIORENDER_TEMP_DATA_MALLOC( DecalRenderData_t, pTempData, nSizeInBytes );
  1427. memcpy( pTempData, pRenderData, nSizeInBytes );
  1428. for ( int j = 0; j < nCount; ++j )
  1429. {
  1430. pTempData[j].m_pRenderMaterial = flashlight.m_pDebugMaterial;
  1431. }
  1432. pRenderContext->SetFlashlightMode( false );
  1433. DrawModelArrayDecals( pRenderContext, pStudioHdr, nCount, pTempData, ( 1 << i ) );
  1434. pRenderContext->SetFlashlightMode( true );
  1435. STUDIORENDER_TEMP_DATA_FREE( pTempData );
  1436. }
  1437. if ( bDoScissor && state.DoScissor() )
  1438. {
  1439. pRenderContext->PopScissorRect();
  1440. }
  1441. }
  1442. pRenderContext->SetFlashlightMode( false );
  1443. }
  1444. int CStudioRender::CountDecalMeshesToDraw( int nCount, StudioArrayInstanceData_t *pInstanceData, int nInstanceStride )
  1445. {
  1446. VPROF( "CStudioRender::CountDecalMeshesToDraw" );
  1447. int nDecalMeshCount = 0;
  1448. StudioArrayInstanceData_t *pCurInstance = pInstanceData;
  1449. for ( int i = 0; i < nCount; ++i, pCurInstance = (StudioArrayInstanceData_t*)( (char*)pCurInstance + nInstanceStride ) )
  1450. {
  1451. StudioDecalHandle_t handle = pCurInstance->m_Decals;
  1452. if ( handle == STUDIORENDER_DECAL_INVALID )
  1453. continue;
  1454. const DecalModelList_t& list = m_DecalList[(intp)handle];
  1455. unsigned short mat = list.m_pLod[pCurInstance->m_nLOD].m_FirstMaterial;
  1456. for ( ; mat != m_DecalMaterial.InvalidIndex(); mat = m_DecalMaterial.Next(mat))
  1457. {
  1458. ++nDecalMeshCount;
  1459. }
  1460. }
  1461. return nDecalMeshCount;
  1462. }
  1463. //-----------------------------------------------------------------------------
  1464. // Sort decals function
  1465. //-----------------------------------------------------------------------------
  1466. inline bool CStudioRender::SortDecalsLessFunc( const DecalRenderData_t &left, const DecalRenderData_t &right )
  1467. {
  1468. if ( left.m_pDecalMaterial->m_pvProxyUserData != right.m_pDecalMaterial->m_pvProxyUserData )
  1469. {
  1470. int nUniqueID_Left = int( reinterpret_cast< uintp >( left.m_pDecalMaterial->m_pvProxyUserData ) ) & 0xFFFFFF;
  1471. int nUniqueID_Right = int( reinterpret_cast< uintp >( right.m_pDecalMaterial->m_pvProxyUserData ) ) & 0xFFFFFF;
  1472. if ( nUniqueID_Left != nUniqueID_Right )
  1473. {
  1474. if ( nUniqueID_Left && nUniqueID_Right )
  1475. return nUniqueID_Left < nUniqueID_Right;
  1476. else
  1477. return nUniqueID_Left > nUniqueID_Right; // if left is player decal, and right is non-proxied then true means to render player decal earlier
  1478. }
  1479. }
  1480. if ( left.m_pDecalMaterial->m_pMaterial != right.m_pDecalMaterial->m_pMaterial )
  1481. return left.m_pDecalMaterial->m_pMaterial > right.m_pDecalMaterial->m_pMaterial;
  1482. if ( left.m_pInstance->m_pEnvCubemapTexture != right.m_pInstance->m_pEnvCubemapTexture )
  1483. return left.m_pInstance->m_pEnvCubemapTexture > right.m_pInstance->m_pEnvCubemapTexture;
  1484. bool bLeftHasLighting = ( left.m_pInstance->m_pLightingState != NULL );
  1485. bool bRightHasLighting = ( right.m_pInstance->m_pLightingState != NULL );
  1486. if ( bLeftHasLighting != bRightHasLighting )
  1487. return bLeftHasLighting;
  1488. if ( !bLeftHasLighting )
  1489. return false;
  1490. return left.m_pInstance->m_pLightingState->m_nLocalLightCount > right.m_pInstance->m_pLightingState->m_nLocalLightCount;
  1491. }
  1492. //-----------------------------------------------------------------------------
  1493. // Sorts decals to render
  1494. //-----------------------------------------------------------------------------
  1495. int CStudioRender::BuildSortedDecalRenderList( DecalRenderData_t *pDecalRenderData, int nCount, StudioArrayInstanceData_t *pInstanceData, int nInstanceStride )
  1496. {
  1497. VPROF( "CStudioRender::BuildSortedDecalRenderList" );
  1498. int nDecalMeshCount = 0;
  1499. StudioArrayInstanceData_t *pCurInstance = pInstanceData;
  1500. for ( int i = 0; i < nCount; ++i, pCurInstance = (StudioArrayInstanceData_t*)( (char*)pCurInstance + nInstanceStride ) )
  1501. {
  1502. StudioDecalHandle_t handle = pCurInstance->m_Decals;
  1503. if ( handle == STUDIORENDER_DECAL_INVALID )
  1504. continue;
  1505. const DecalModelList_t& list = m_DecalList[(intp)handle];
  1506. unsigned short mat = list.m_pLod[pCurInstance->m_nLOD].m_FirstMaterial;
  1507. for ( ; mat != m_DecalMaterial.InvalidIndex(); mat = m_DecalMaterial.Next(mat))
  1508. {
  1509. DecalMaterial_t *pDecalMaterial = &m_DecalMaterial[mat];
  1510. // It's possible for the index count to become zero due to decal retirement
  1511. int indexCount = pDecalMaterial->m_Indices.Count();
  1512. if ( indexCount == 0 )
  1513. continue;
  1514. DecalRenderData_t &decalRenderData = pDecalRenderData[nDecalMeshCount++];
  1515. decalRenderData.m_pDecalMaterial = pDecalMaterial;
  1516. decalRenderData.m_pInstance = pCurInstance;
  1517. decalRenderData.m_pRenderMaterial = pDecalMaterial->m_pMaterial;
  1518. decalRenderData.m_bIsVertexLit = pDecalMaterial->m_pMaterial->IsVertexLit();
  1519. }
  1520. }
  1521. // Debug mode
  1522. if ( m_pRC->m_Config.bWireframeDecals )
  1523. {
  1524. for ( int i = 0; i < nDecalMeshCount; ++i )
  1525. {
  1526. pDecalRenderData[i].m_pRenderMaterial = m_pMaterialWireframe[0][0]; // TODO: support displacement mapping
  1527. }
  1528. }
  1529. std::make_heap( pDecalRenderData, pDecalRenderData + nDecalMeshCount, SortDecalsLessFunc );
  1530. std::sort_heap( pDecalRenderData, pDecalRenderData + nDecalMeshCount, SortDecalsLessFunc );
  1531. return nDecalMeshCount;
  1532. }
  1533. //-----------------------------------------------------------------------------
  1534. // Main entry point for drawing an array of instances
  1535. //-----------------------------------------------------------------------------
  1536. void CStudioRender::DrawModelArray( const StudioModelArrayInfo_t &drawInfo, const StudioRenderContext_t &rc,
  1537. int nCount, StudioArrayInstanceData_t *pInstanceData, int nInstanceStride, int nFlags )
  1538. {
  1539. m_pRC = const_cast< StudioRenderContext_t* >( &rc );
  1540. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1541. // Preserve the matrices if we're skinning
  1542. pRenderContext->MatrixMode( MATERIAL_MODEL );
  1543. pRenderContext->PushMatrix();
  1544. pRenderContext->LoadIdentity();
  1545. // Count number of meshes per instance
  1546. bool bDoShadows = ( ( nFlags & STUDIORENDER_DRAW_NO_SHADOWS ) == 0 );
  1547. bool bSinglePassFlashlight = IsGameConsole();
  1548. int nTimesRendered = 1 + ( bSinglePassFlashlight ? 0 : ( bDoShadows ? drawInfo.m_nFlashlightCount : 1 ) );
  1549. int nTotalMeshCount = CountMeshesToDraw( drawInfo, nCount, pInstanceData, nInstanceStride, nTimesRendered );
  1550. // Build list of meshes to render
  1551. int nTotalStripCount;
  1552. STUDIORENDER_TEMP_DATA_MALLOC( MeshRenderData_t, pRenderData, nTotalMeshCount * sizeof(MeshRenderData_t) );
  1553. if ( !rc.m_pForcedMaterial[ 0 ] || rc.m_nForcedMaterialType == OVERRIDE_SELECTIVE )
  1554. {
  1555. nTotalMeshCount = BuildSortedRenderList( pRenderData, &nTotalStripCount, drawInfo, nCount, pInstanceData, nInstanceStride, nFlags );
  1556. }
  1557. else
  1558. {
  1559. BuildForcedMaterialRenderList( pRenderData, &nTotalStripCount, drawInfo, rc, nCount, pInstanceData, nInstanceStride );
  1560. }
  1561. // Restore meshes, if necessary
  1562. RestoreMeshes( nTotalMeshCount, pRenderData, sizeof(MeshRenderData_t) );
  1563. // Draw, baby, draw!
  1564. DrawMeshRenderData( pRenderContext, drawInfo, nTotalMeshCount, pRenderData, nTotalStripCount, 0 );
  1565. // Draw all flashlights
  1566. if ( bDoShadows && !bSinglePassFlashlight )
  1567. {
  1568. DrawModelArrayFlashlight( pRenderContext, drawInfo, nTotalMeshCount, pRenderData, nTotalStripCount );
  1569. }
  1570. // Count number of decals meshes per instance
  1571. int nTotalDecalCount = CountDecalMeshesToDraw( nCount, pInstanceData, nInstanceStride );
  1572. STUDIORENDER_TEMP_DATA_MALLOC( DecalRenderData_t, pDecalData, nTotalDecalCount * sizeof(DecalRenderData_t) );
  1573. // Build list of decals to render
  1574. nTotalDecalCount = BuildSortedDecalRenderList( pDecalData, nCount, pInstanceData, nInstanceStride );
  1575. // Draw all decals
  1576. DrawModelArrayDecals( pRenderContext, drawInfo.m_pStudioHdr, nTotalDecalCount, pDecalData, 0 );
  1577. // Illuminate decals by the flashlight
  1578. if ( bDoShadows && !bSinglePassFlashlight )
  1579. {
  1580. DrawModelArrayFlashlightDecals( pRenderContext, drawInfo.m_pStudioHdr, drawInfo.m_nFlashlightCount, drawInfo.m_pFlashlights, nTotalDecalCount, pDecalData );
  1581. }
  1582. pRenderContext->MatrixMode( MATERIAL_MODEL );
  1583. pRenderContext->PopMatrix();
  1584. pRenderContext->SetNumBoneWeights( 0 );
  1585. STUDIORENDER_TEMP_DATA_FREE( pRenderData );
  1586. STUDIORENDER_TEMP_DATA_FREE( pDecalData );
  1587. }
  1588. //-----------------------------------------------------------------------------
  1589. // More optimal version?
  1590. //-----------------------------------------------------------------------------
  1591. void CStudioRender::DrawModelArray2( const StudioModelArrayInfo2_t &drawInfo, const StudioRenderContext_t &rc,
  1592. int nCount, StudioArrayData_t *pArrayData, int nInstanceStride, int nFlags )
  1593. {
  1594. m_pRC = const_cast< StudioRenderContext_t* >( &rc );
  1595. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1596. // Preserve the matrices if we're skinning
  1597. pRenderContext->MatrixMode( MATERIAL_MODEL );
  1598. pRenderContext->PushMatrix();
  1599. pRenderContext->LoadIdentity();
  1600. // Count number of meshes per instance
  1601. bool bDoShadows = ( ( nFlags & STUDIORENDER_DRAW_NO_SHADOWS ) == 0 );
  1602. bool bSinglePassFlashlight = IsGameConsole();
  1603. int nTimesRendered = 1 + ( bSinglePassFlashlight ? 0 : ( bDoShadows ? drawInfo.m_nFlashlightCount : 1 ) );
  1604. int nTotalMeshCount = CountMeshesToDraw( drawInfo, nCount, pArrayData, nInstanceStride, nTimesRendered );
  1605. // Build list of meshes to render
  1606. int nTotalStripCount;
  1607. STUDIORENDER_TEMP_DATA_MALLOC( MeshRenderData2_t, pRenderData, nTotalMeshCount * sizeof(MeshRenderData2_t) );
  1608. if ( !rc.m_pForcedMaterial[ 0 ] || rc.m_nForcedMaterialType == OVERRIDE_SELECTIVE )
  1609. {
  1610. nTotalMeshCount = BuildSortedRenderList( pRenderData, &nTotalStripCount, drawInfo, nCount, pArrayData, nInstanceStride, nFlags );
  1611. }
  1612. else
  1613. {
  1614. BuildForcedMaterialRenderList( pRenderData, &nTotalStripCount, drawInfo, rc, nCount, pArrayData, nInstanceStride );
  1615. }
  1616. // Restore meshes, if necessary
  1617. RestoreMeshes( nTotalMeshCount, pRenderData, sizeof(MeshRenderData2_t) );
  1618. // Draw, baby, draw!
  1619. DrawMeshRenderData( pRenderContext, drawInfo, nTotalMeshCount, pRenderData, nTotalStripCount, 0 );
  1620. // Draw all flashlights
  1621. if ( bDoShadows && !bSinglePassFlashlight )
  1622. {
  1623. DrawModelArrayFlashlight( pRenderContext, drawInfo, nTotalMeshCount, pRenderData, nTotalStripCount );
  1624. }
  1625. // Count number of decals meshes per instance
  1626. for ( int i = 0; i < nCount; ++i )
  1627. {
  1628. StudioArrayData_t &arrayData = pArrayData[i];
  1629. StudioArrayInstanceData_t *pGroupInstances = ( StudioArrayInstanceData_t * )( arrayData.m_pInstanceData );
  1630. int nTotalDecalCount = CountDecalMeshesToDraw( arrayData.m_nCount, pGroupInstances, nInstanceStride );
  1631. STUDIORENDER_TEMP_DATA_MALLOC( DecalRenderData_t, pDecalData, nTotalDecalCount * sizeof(DecalRenderData_t) );
  1632. // Build list of decals to render
  1633. nTotalDecalCount = BuildSortedDecalRenderList( pDecalData, arrayData.m_nCount, pGroupInstances, nInstanceStride );
  1634. // Draw all decals
  1635. DrawModelArrayDecals( pRenderContext, arrayData.m_pStudioHdr, nTotalDecalCount, pDecalData, 0 );
  1636. // Illuminate decals by the flashlight
  1637. if ( bDoShadows && !bSinglePassFlashlight )
  1638. {
  1639. DrawModelArrayFlashlightDecals( pRenderContext, arrayData.m_pStudioHdr, drawInfo.m_nFlashlightCount, drawInfo.m_pFlashlights, nTotalDecalCount, pDecalData );
  1640. }
  1641. STUDIORENDER_TEMP_DATA_FREE( pDecalData );
  1642. }
  1643. pRenderContext->MatrixMode( MATERIAL_MODEL );
  1644. pRenderContext->PopMatrix();
  1645. pRenderContext->SetNumBoneWeights( 0 );
  1646. STUDIORENDER_TEMP_DATA_FREE( pRenderData );
  1647. }
  1648. //-----------------------------------------------------------------------------
  1649. // Counts the number of meshes to draw ( shadow rendering )
  1650. //-----------------------------------------------------------------------------
  1651. int CStudioRender::CountMeshesToDraw( int nCount, StudioArrayData_t *pShadowData, int nInstanceStride )
  1652. {
  1653. VPROF( "CStudioRender::CountMeshesToDraw (shadow)" );
  1654. #ifndef _CERT
  1655. bool bCountRenderedFaces = mat_rendered_faces_count.GetBool() || mat_print_top_model_vert_counts.GetBool();
  1656. #endif // !_CERT
  1657. int nTotalMeshCount = 0;
  1658. for ( int i = 0; i < nCount; ++i )
  1659. {
  1660. StudioArrayData_t &shadow = pShadowData[i];
  1661. StudioShadowArrayInstanceData_t *pCurInstance = ( StudioShadowArrayInstanceData_t* )shadow.m_pInstanceData;
  1662. for ( int j = 0; j < shadow.m_nCount; ++j, pCurInstance = ( StudioShadowArrayInstanceData_t* )( (uint8*)pCurInstance + nInstanceStride ) )
  1663. {
  1664. // This subarray has the same skin + body + lod
  1665. int nLod = pCurInstance->m_nLOD;
  1666. // get the studio mesh data for this lod
  1667. studiomeshdata_t *pMeshDataBase = shadow.m_pHardwareData->m_pLODs[nLod].m_pMeshData;
  1668. #ifndef _CERT
  1669. // Each model counts how many rendered faces it accounts for each frame:
  1670. if ( bCountRenderedFaces )
  1671. shadow.m_pHardwareData->UpdateFacesRenderedCount( shadow.m_pStudioHdr, m_ModelFaceCountHash, nLod, 1 );
  1672. #endif // !_CERT
  1673. int nBody = pCurInstance->m_nBody;
  1674. for ( int body = 0; body < shadow.m_pStudioHdr->numbodyparts; ++body )
  1675. {
  1676. mstudiobodyparts_t *pbodypart = shadow.m_pStudioHdr->pBodypart( body );
  1677. int index = nBody / pbodypart->base;
  1678. index = index % pbodypart->nummodels;
  1679. mstudiomodel_t *pSubmodel = pbodypart->pModel( index );
  1680. for ( int meshIndex = 0; meshIndex < pSubmodel->nummeshes; ++meshIndex )
  1681. {
  1682. mstudiomesh_t *pMesh = pSubmodel->pMesh(meshIndex);
  1683. studiomeshdata_t *pMeshData = &pMeshDataBase[pMesh->meshid];
  1684. nTotalMeshCount += pMeshData->m_NumGroup;
  1685. }
  1686. }
  1687. }
  1688. }
  1689. return nTotalMeshCount;
  1690. }
  1691. //-----------------------------------------------------------------------------
  1692. // Sets up a depth write material based on an initial material
  1693. //-----------------------------------------------------------------------------
  1694. void CStudioRender::GetDepthWriteMaterial( IMaterial** ppDepthMaterial, bool *pIsAlphaTested, bool *pUsesTreeSway, IMaterial *pSrcMaterial, bool bIsTranslucentUnderModulation, bool bIsSSAODepthWrite )
  1695. {
  1696. static unsigned int originalTextureVarCache = 0;
  1697. static unsigned int nOriginalTreeSwayVarCache = 0;
  1698. IMaterialVar *pOriginalTextureVar = pSrcMaterial->FindVarFast( "$basetexture", &originalTextureVarCache );
  1699. IMaterialVar *pOriginalTreeSwayVar = pSrcMaterial->FindVarFast( "$treesway", &nOriginalTreeSwayVarCache );
  1700. // Select proper override material
  1701. int nAlphaTest = (int) ( ( pSrcMaterial->IsAlphaTested() || bIsTranslucentUnderModulation ) && pOriginalTextureVar->IsTexture() ); // alpha tested base texture
  1702. int nNoCull = (int) pSrcMaterial->IsTwoSided();
  1703. int nTreeSway = (int) ( pOriginalTreeSwayVar && pOriginalTreeSwayVar->GetIntValue() );
  1704. if ( !bIsSSAODepthWrite )
  1705. {
  1706. *ppDepthMaterial = m_pDepthWrite[ nAlphaTest ][ nNoCull ][ nTreeSway ];
  1707. }
  1708. else
  1709. {
  1710. *ppDepthMaterial = m_pSSAODepthWrite[ nAlphaTest ][ nNoCull ][ nTreeSway ];
  1711. }
  1712. *pIsAlphaTested = ( nAlphaTest != 0 );
  1713. *pUsesTreeSway = ( nTreeSway != 0 );
  1714. }
  1715. //-----------------------------------------------------------------------------
  1716. // Sets up a depth write material based on an initial material
  1717. //-----------------------------------------------------------------------------
  1718. void CStudioRender::SetupAlphaTestedDepthWrite( IMaterial* pDepthMaterial, IMaterial *pSrcMaterial )
  1719. {
  1720. static unsigned int originalTextureVarCache = 0;
  1721. IMaterialVar *pOriginalTextureVar = pSrcMaterial->FindVarFast( "$basetexture", &originalTextureVarCache );
  1722. static unsigned int originalTextureFrameVarCache = 0;
  1723. IMaterialVar *pOriginalTextureFrameVar = pSrcMaterial->FindVarFast( "$frame", &originalTextureFrameVarCache );
  1724. static unsigned int originalAlphaRefCache = 0;
  1725. IMaterialVar *pOriginalAlphaRefVar = pSrcMaterial->FindVarFast( "$AlphaTestReference", &originalAlphaRefCache );
  1726. static unsigned int textureVarCache = 0;
  1727. IMaterialVar *pTextureVar = pDepthMaterial->FindVarFast( "$basetexture", &textureVarCache );
  1728. static unsigned int textureFrameVarCache = 0;
  1729. IMaterialVar *pTextureFrameVar = pDepthMaterial->FindVarFast( "$frame", &textureFrameVarCache );
  1730. static unsigned int alphaRefCache = 0;
  1731. IMaterialVar *pAlphaRefVar = pDepthMaterial->FindVarFast( "$AlphaTestReference", &alphaRefCache );
  1732. if ( pOriginalTextureVar->IsTexture() ) // If $basetexture is defined
  1733. {
  1734. if( pTextureVar && pOriginalTextureVar )
  1735. {
  1736. pTextureVar->SetTextureValue( pOriginalTextureVar->GetTextureValue() );
  1737. }
  1738. if( pTextureFrameVar && pOriginalTextureFrameVar )
  1739. {
  1740. pTextureFrameVar->SetIntValue( pOriginalTextureFrameVar->GetIntValue() );
  1741. }
  1742. if( pAlphaRefVar && pOriginalAlphaRefVar )
  1743. {
  1744. pAlphaRefVar->SetFloatValue( pOriginalAlphaRefVar->GetFloatValue() );
  1745. }
  1746. }
  1747. }
  1748. //-----------------------------------------------------------------------------
  1749. // Sets up a depth write material based on an initial material
  1750. //-----------------------------------------------------------------------------
  1751. void CStudioRender::SetupTreeSwayDepthWrite( IMaterial* pDepthMaterial, IMaterial *pSrcMaterial )
  1752. {
  1753. static const char* paramNames[14] =
  1754. {
  1755. "$treeswayheight",
  1756. "$treeswaystartheight",
  1757. "$treeswayradius",
  1758. "$treeswaystartradius",
  1759. "$treeswayspeed",
  1760. "$treeswayspeedhighwindmultiplier",
  1761. "$treeswaystrength",
  1762. "$treeswayscrumblespeed",
  1763. "$treeswayscrumblestrength",
  1764. "$treeswayscrumblefrequency",
  1765. "$treeswayfalloffexp",
  1766. "$treeswayscrumblefalloffexp",
  1767. "$treeswayspeedlerpstart",
  1768. "$treeswayspeedlerpend",
  1769. };
  1770. static unsigned int originalVarCache[14] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  1771. static unsigned int varCache[14] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  1772. IMaterialVar *pOriginalVar = NULL;
  1773. IMaterialVar *pVar = NULL;
  1774. for ( int32 i = 0; i < ARRAYSIZE( paramNames ); i++ )
  1775. {
  1776. pOriginalVar = pSrcMaterial->FindVarFast( paramNames[i], originalVarCache + i );
  1777. pVar = pDepthMaterial->FindVarFast( paramNames[i], varCache + i );
  1778. if( pOriginalVar && pVar )
  1779. {
  1780. pVar->SetFloatValue( pOriginalVar->GetFloatValue() );
  1781. }
  1782. }
  1783. }
  1784. //-----------------------------------------------------------------------------
  1785. // Sort models function
  1786. //-----------------------------------------------------------------------------
  1787. inline bool CStudioRender::ShadowSortLessFunc( const ShadowMeshRenderData_t &left, const ShadowMeshRenderData_t &right )
  1788. {
  1789. if ( left.m_pMaterial != right.m_pMaterial )
  1790. return left.m_pMaterial > right.m_pMaterial;
  1791. if ( left.m_bIsAlphaTested && right.m_bIsAlphaTested )
  1792. {
  1793. if ( left.m_pSrcMaterial != right.m_pSrcMaterial )
  1794. return left.m_pSrcMaterial > right.m_pSrcMaterial;
  1795. }
  1796. if ( left.m_bUsesTreeSway && right.m_bUsesTreeSway )
  1797. {
  1798. if ( left.m_pSrcMaterial != right.m_pSrcMaterial )
  1799. return left.m_pSrcMaterial > right.m_pSrcMaterial;
  1800. }
  1801. if ( left.m_nCompressionType != right.m_nCompressionType )
  1802. return left.m_nCompressionType > right.m_nCompressionType;
  1803. if ( left.m_nMeshBoneCount != right.m_nMeshBoneCount )
  1804. return left.m_nMeshBoneCount > right.m_nMeshBoneCount;
  1805. return left.m_pGroup->m_pMesh > right.m_pGroup->m_pMesh;
  1806. }
  1807. //-----------------------------------------------------------------------------
  1808. // BuildShadowRenderList
  1809. //-----------------------------------------------------------------------------
  1810. int CStudioRender::BuildShadowRenderList( ShadowMeshRenderData_t *pRenderData, int *pTotalStripCount,
  1811. int nCount, StudioArrayData_t *pShadowData, int nInstanceStride, int flags )
  1812. {
  1813. VPROF( "CStudioRender::BuildShadowRenderList" );
  1814. *pTotalStripCount = 0;
  1815. int nRenderDataCount = 0;
  1816. for ( int i = 0; i < nCount; ++i )
  1817. {
  1818. StudioArrayData_t &shadow = pShadowData[i];
  1819. studiohdr_t *pStudioHdr = shadow.m_pStudioHdr;
  1820. short *pSkinRefBase = pStudioHdr->pSkinref( 0 );
  1821. StudioShadowArrayInstanceData_t *pCurInstance = ( StudioShadowArrayInstanceData_t* )shadow.m_pInstanceData;
  1822. for ( int j = 0; j < shadow.m_nCount; ++j, pCurInstance = ( StudioShadowArrayInstanceData_t* )( (uint8*)pCurInstance + nInstanceStride ) )
  1823. {
  1824. // This subarray has the same skin + body + lod
  1825. int nLod = pCurInstance->m_nLOD;
  1826. // get the studio mesh data for this lod
  1827. studiomeshdata_t *pMeshDataBase = shadow.m_pHardwareData->m_pLODs[nLod].m_pMeshData;
  1828. IMaterial **ppMaterials = shadow.m_pHardwareData->m_pLODs[nLod].ppMaterials;
  1829. short *pSkinRef = pSkinRefBase;
  1830. int skin = pCurInstance->m_nSkin;
  1831. if ( skin > 0 && skin < pStudioHdr->numskinfamilies )
  1832. {
  1833. pSkinRef += ( skin * pStudioHdr->numskinref );
  1834. }
  1835. int nBody = pCurInstance->m_nBody;
  1836. for ( int body = 0; body < pStudioHdr->numbodyparts; ++body )
  1837. {
  1838. mstudiobodyparts_t *pbodypart = pStudioHdr->pBodypart( body );
  1839. int index = nBody / pbodypart->base;
  1840. index = index % pbodypart->nummodels;
  1841. mstudiomodel_t *pSubmodel = pbodypart->pModel( index );
  1842. for ( int meshIndex = 0; meshIndex < pSubmodel->nummeshes; ++meshIndex )
  1843. {
  1844. mstudiomesh_t *pMesh = pSubmodel->pMesh(meshIndex);
  1845. studiomeshdata_t *pMeshData = &pMeshDataBase[pMesh->meshid];
  1846. Assert( pMeshData );
  1847. //Assert( pMeshData->m_NumGroup ); // Can't assume that this is non-zero for lods with removed meshes.
  1848. IMaterial *pMaterial = ppMaterials[ pSkinRef[ pMesh->material ] ];
  1849. // Used on cstrike15 to efficiently render translucent renderables into csm shadow buffers
  1850. if ( ( flags & STUDIORENDER_SHADOWDEPTHTEXTURE_INCLUDE_TRANSLUCENT_MATERIALS ) == 0 )
  1851. {
  1852. // Bail if the material is still considered translucent after setting the AlphaModulate to 1.0
  1853. if ( pMaterial->IsTranslucentUnderModulation() )
  1854. continue;
  1855. }
  1856. IMaterial *pDepthMaterial;
  1857. bool bIsAlphaTested = false;
  1858. bool bUsesTreeSway = false;
  1859. GetDepthWriteMaterial( &pDepthMaterial, &bIsAlphaTested, &bUsesTreeSway, pMaterial, pMaterial->IsTranslucentUnderModulation(), ( flags & STUDIORENDER_SSAODEPTHTEXTURE ) ? true : false );
  1860. for ( int g = 0; g < pMeshData->m_NumGroup; ++g )
  1861. {
  1862. studiomeshgroup_t* pGroup = &pMeshData->m_pMeshGroup[g];
  1863. VertexCompressionType_t nCompressionType = CompressionType( pGroup->m_pMesh->GetVertexFormat() );
  1864. ShadowMeshRenderData_t &data = pRenderData[nRenderDataCount++];
  1865. data.m_pGroup = pGroup;
  1866. data.m_pInstance = pCurInstance;
  1867. data.m_pMesh = pMesh;
  1868. data.m_pMaterial = pDepthMaterial;
  1869. data.m_pSrcMaterial = pMaterial;
  1870. data.m_nCompressionType = nCompressionType;
  1871. data.m_nMeshBoneCount = NumBoneWeights( pGroup->m_pMesh->GetVertexFormat() );
  1872. data.m_bIsAlphaTested = bIsAlphaTested;
  1873. data.m_bUsesTreeSway = bUsesTreeSway;
  1874. *pTotalStripCount += pGroup->m_NumStrips;
  1875. }
  1876. }
  1877. }
  1878. }
  1879. }
  1880. std::make_heap( pRenderData, pRenderData + nRenderDataCount, ShadowSortLessFunc );
  1881. std::sort_heap( pRenderData, pRenderData + nRenderDataCount, ShadowSortLessFunc );
  1882. return nRenderDataCount;
  1883. }
  1884. //-----------------------------------------------------------------------------
  1885. // Draws shadow meshes
  1886. //-----------------------------------------------------------------------------
  1887. void CStudioRender::DrawShadowMeshRenderData( IMatRenderContext *pRenderContext,
  1888. int nCount, ShadowMeshRenderData_t *pRenderData, int nTotalStripCount )
  1889. {
  1890. VPROF( "CStudioRender::DrawShadowMeshRenderData" );
  1891. int nInstanceCount = 0;
  1892. STUDIORENDER_TEMP_DATA_MALLOC( MeshInstanceData_t, pInstance, nTotalStripCount * sizeof(MeshInstanceData_t) );
  1893. int nMaxBoneCount = 0;
  1894. int nLastMeshBoneCount = 0;
  1895. IMaterial *pLastMaterial = NULL;
  1896. IMaterial *pLastSrcMaterial = NULL;
  1897. bool bIsAlphaTested = false;
  1898. bool bUsesTreeSway = false;
  1899. VertexCompressionType_t nLastCompressionType = VERTEX_COMPRESSION_INVALID;
  1900. for ( int i = 0; i < nCount; ++i )
  1901. {
  1902. ShadowMeshRenderData_t &data = pRenderData[i];
  1903. StudioShadowArrayInstanceData_t *pCurrInstance = data.m_pInstance;
  1904. if ( ( pLastMaterial != data.m_pMaterial ) || // shadow material is different
  1905. ( bIsAlphaTested && ( pLastSrcMaterial != data.m_pSrcMaterial ) ) || // alpha channel is different
  1906. ( bUsesTreeSway && ( pLastSrcMaterial != data.m_pSrcMaterial ) ) || // tree sway params are different
  1907. ( nLastCompressionType != data.m_nCompressionType ) || // compression type is different
  1908. ( nLastMeshBoneCount != data.m_nMeshBoneCount ) ) // # of bones in the mesh data is different
  1909. {
  1910. if ( nInstanceCount > 0 )
  1911. {
  1912. if ( bIsAlphaTested )
  1913. {
  1914. SetupAlphaTestedDepthWrite( pLastMaterial, pLastSrcMaterial );
  1915. }
  1916. if ( bUsesTreeSway )
  1917. {
  1918. SetupTreeSwayDepthWrite( pLastMaterial, pLastSrcMaterial );
  1919. }
  1920. pRenderContext->SetNumBoneWeights( nLastMeshBoneCount > 0 ? nMaxBoneCount : 0 );
  1921. pRenderContext->Bind( pLastMaterial, NULL );
  1922. pRenderContext->DrawInstances( nInstanceCount, pInstance );
  1923. }
  1924. nInstanceCount = 0;
  1925. nMaxBoneCount = 0;
  1926. nLastCompressionType = data.m_nCompressionType;
  1927. pLastMaterial = data.m_pMaterial;
  1928. pLastSrcMaterial = data.m_pSrcMaterial;
  1929. nLastMeshBoneCount = data.m_nMeshBoneCount;
  1930. bIsAlphaTested = data.m_bIsAlphaTested;
  1931. bUsesTreeSway = data.m_bUsesTreeSway;
  1932. }
  1933. studiomeshgroup_t* pGroup = data.m_pGroup;
  1934. for ( int j = 0; j < pGroup->m_NumStrips; ++j )
  1935. {
  1936. OptimizedModel::StripHeader_t* pStrip = &pGroup->m_pStripData[j];
  1937. Assert( nInstanceCount < nTotalStripCount );
  1938. MeshInstanceData_t &instance = pInstance[nInstanceCount++];
  1939. instance.m_pEnvCubemap = NULL;
  1940. instance.m_pPoseToWorld = pCurrInstance->m_pPoseToWorld;
  1941. instance.m_pLightingState = NULL;
  1942. instance.m_nBoneCount = pStrip->numBoneStateChanges;
  1943. instance.m_pBoneRemap = ( instance.m_nBoneCount > 0 ) ? (MeshBoneRemap_t*)( pStrip->pBoneStateChange(0) ) : NULL;
  1944. instance.m_nIndexOffset = pStrip->indexOffset;
  1945. instance.m_nIndexCount = pStrip->numIndices;
  1946. instance.m_nPrimType = MATERIAL_TRIANGLES;
  1947. instance.m_pColorBuffer = NULL;
  1948. instance.m_nColorVertexOffsetInBytes = 0;
  1949. instance.m_pStencilState = NULL;
  1950. instance.m_pVertexBuffer = pGroup->m_pMesh;
  1951. instance.m_pIndexBuffer = pGroup->m_pMesh;
  1952. instance.m_nVertexOffsetInBytes = 0;
  1953. instance.m_DiffuseModulation.Init( 1.0f, 1.0f, 1.0f, 1.0f );
  1954. instance.m_nLightmapPageId = MATERIAL_SYSTEM_LIGHTMAP_PAGE_INVALID;
  1955. instance.m_bColorBufferHasIndirectLightingOnly = false;
  1956. nMaxBoneCount = MAX( nMaxBoneCount, pStrip->numBones );
  1957. }
  1958. }
  1959. if ( nInstanceCount > 0 )
  1960. {
  1961. if ( bIsAlphaTested )
  1962. {
  1963. SetupAlphaTestedDepthWrite( pLastMaterial, pLastSrcMaterial );
  1964. }
  1965. if ( bUsesTreeSway )
  1966. {
  1967. SetupTreeSwayDepthWrite( pLastMaterial, pLastSrcMaterial );
  1968. }
  1969. pRenderContext->SetNumBoneWeights( nLastMeshBoneCount > 0 ? nMaxBoneCount : 0 );
  1970. pRenderContext->Bind( pLastMaterial, NULL );
  1971. pRenderContext->DrawInstances( nInstanceCount, pInstance );
  1972. }
  1973. pRenderContext->SetNumBoneWeights( 0 );
  1974. STUDIORENDER_TEMP_DATA_FREE( pInstance );
  1975. }
  1976. //-----------------------------------------------------------------------------
  1977. // Draws all models to the shadow depth buffer
  1978. //-----------------------------------------------------------------------------
  1979. void CStudioRender::DrawModelShadowArray( const StudioRenderContext_t &rc, int nCount, StudioArrayData_t *pShadowData, int nInstanceStride, int flags )
  1980. {
  1981. m_pRC = const_cast< StudioRenderContext_t* >( &rc );
  1982. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1983. // Preserve the matrices if we're skinning
  1984. pRenderContext->MatrixMode( MATERIAL_MODEL );
  1985. pRenderContext->PushMatrix();
  1986. pRenderContext->LoadIdentity();
  1987. // Count number of meshes to draw
  1988. int nTotalMeshCount = CountMeshesToDraw( nCount, pShadowData, nInstanceStride );
  1989. // Build list of meshes to render
  1990. int nTotalStripCount;
  1991. STUDIORENDER_TEMP_DATA_MALLOC( ShadowMeshRenderData_t, pRenderData, nTotalMeshCount * sizeof(ShadowMeshRenderData_t) );
  1992. nTotalMeshCount = BuildShadowRenderList( pRenderData, &nTotalStripCount, nCount, pShadowData, nInstanceStride, flags );
  1993. // Restore meshes, if necessary
  1994. RestoreMeshes( nTotalMeshCount, pRenderData, sizeof(ShadowMeshRenderData_t) );
  1995. // Draw, baby, draw!
  1996. DrawShadowMeshRenderData( pRenderContext, nTotalMeshCount, pRenderData, nTotalStripCount );
  1997. pRenderContext->MatrixMode( MATERIAL_MODEL );
  1998. pRenderContext->PopMatrix();
  1999. pRenderContext->SetNumBoneWeights( 0 );
  2000. STUDIORENDER_TEMP_DATA_FREE( pRenderData );
  2001. }
  2002. void CStudioRender::ComputeDiffuseModulation( Vector4D *pDiffuseModulation )
  2003. {
  2004. if ( ( m_pRC->m_nForcedMaterialType != OVERRIDE_DEPTH_WRITE ) && ( m_pRC->m_nForcedMaterialType != OVERRIDE_SSAO_DEPTH_WRITE ) )
  2005. {
  2006. pDiffuseModulation->Init( m_pRC->m_ColorMod[0], m_pRC->m_ColorMod[1], m_pRC->m_ColorMod[2], m_pRC->m_AlphaMod );
  2007. }
  2008. else
  2009. {
  2010. pDiffuseModulation->Init( 1.0f, 1.0f, 1.0f, 1.0f );
  2011. }
  2012. }
  2013. // this is a fast path that does not support debug modes or transparency (or skeletons obviously)
  2014. // pass in an array of instances and draw them
  2015. void CStudioRender::DrawModelArrayStaticProp( const DrawModelInfo_t& info,
  2016. const StudioRenderContext_t &rc, int nInstanceCount, const MeshInstanceData_t *pInstanceData, ColorMeshInfo_t **pColorMeshes )
  2017. {
  2018. VPROF( "CStudioRender::DrawModelArrayStaticProp");
  2019. m_pRC = const_cast<StudioRenderContext_t*>( &rc );
  2020. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  2021. pRenderContext->SetNumBoneWeights( 0 );
  2022. pRenderContext->MatrixMode( MATERIAL_MODEL );
  2023. // this is needed by R_SetupSkinAndLighting
  2024. bool flexConfig = m_pRC->m_Config.bFlex;
  2025. m_pRC->m_Config.bFlex = false;
  2026. bool bWireframe = m_pRC->m_Config.bWireframe;
  2027. m_pRC->m_Config.bWireframe = false;
  2028. m_bSkippedMeshes = false;
  2029. m_bDrawTranslucentSubModels = false;
  2030. int lod = info.m_Lod;
  2031. m_pStudioHdr = info.m_pStudioHdr;
  2032. m_pStudioMeshes = info.m_pHardwareData->m_pLODs[lod].m_pMeshData;
  2033. m_pStudioHWData = info.m_pHardwareData;
  2034. #if PIX_ENABLE
  2035. char szPIXEventName[128];
  2036. sprintf( szPIXEventName, "%s*", m_pStudioHdr->name ); // PIX
  2037. PIXEVENT( pRenderContext, szPIXEventName );
  2038. #endif
  2039. // Build list of submodels
  2040. Assert(m_pStudioHdr->numbodyparts==1);
  2041. mstudiobodyparts_t *pbodypart = m_pStudioHdr->pBodypart( 0 );
  2042. m_pSubModel = pbodypart->pModel( 0 );
  2043. // get skinref array
  2044. int skin = info.m_Skin;
  2045. int *pMaterialFlags = info.m_pHardwareData->m_pLODs[lod].pMaterialFlags;
  2046. short *pskinref = m_pStudioHdr->pSkinref( 0 );
  2047. if ( skin > 0 && skin < m_pStudioHdr->numskinfamilies )
  2048. {
  2049. pskinref += ( skin * m_pStudioHdr->numskinref );
  2050. }
  2051. #ifndef _CERT
  2052. int nFacesPerModel = 0;
  2053. #endif // !_CERT
  2054. // draw each mesh
  2055. for ( int i = 0; i < m_pSubModel->nummeshes; ++i)
  2056. {
  2057. mstudiomesh_t *pmesh = m_pSubModel->pMesh(i);
  2058. studiomeshdata_t *pMeshData = &m_pStudioMeshes[pmesh->meshid];
  2059. Assert( pMeshData );
  2060. if ( !pMeshData->m_NumGroup )
  2061. continue;
  2062. if ( !pMaterialFlags )
  2063. continue;
  2064. int materialFlags = pMaterialFlags[pskinref[pmesh->material]];
  2065. StudioModelLighting_t lighting = LIGHTING_HARDWARE;
  2066. IMaterial* pMaterial = R_StudioSetupSkinAndLighting( pRenderContext, pskinref[ pmesh->material ], info.m_pHardwareData->m_pLODs[lod].ppMaterials, materialFlags, info.m_pClientEntity, info.m_pColorMeshes, lighting );
  2067. if ( !pMaterial )
  2068. continue;
  2069. // if this fails you've got a static prop with an eyeball!
  2070. Assert( pmesh->materialtype != 1 );
  2071. for ( int j = 0; j < pMeshData->m_NumGroup; ++j )
  2072. {
  2073. studiomeshgroup_t* pGroup = &pMeshData->m_pMeshGroup[j];
  2074. // Needed when we switch back and forth between hardware + software lighting
  2075. #ifdef IS_WINDOWS_PC
  2076. if ( IsPC() && pGroup->m_MeshNeedsRestore )
  2077. {
  2078. VertexCompressionType_t compressionType = CompressionType( pGroup->m_pMesh->GetVertexFormat() );
  2079. switch ( compressionType )
  2080. {
  2081. case VERTEX_COMPRESSION_ON:
  2082. R_StudioRestoreMesh<VERTEX_COMPRESSION_ON>( pmesh, pGroup );
  2083. case VERTEX_COMPRESSION_NONE:
  2084. default:
  2085. R_StudioRestoreMesh<VERTEX_COMPRESSION_NONE>( pmesh, pGroup );
  2086. break;
  2087. }
  2088. pGroup->m_MeshNeedsRestore = false;
  2089. }
  2090. #endif
  2091. IMesh *pMesh = pGroup->m_pMesh;
  2092. for ( int k = 0; k < nInstanceCount; k++ )
  2093. {
  2094. const MeshInstanceData_t &instance = pInstanceData[k];
  2095. if ( instance.m_pEnvCubemap )
  2096. {
  2097. pRenderContext->BindLocalCubemap( const_cast<ITexture *>( instance.m_pEnvCubemap ) );
  2098. }
  2099. if ( pColorMeshes[k] )
  2100. {
  2101. pMesh->SetColorMesh( pColorMeshes[k][pGroup->m_ColorMeshID].m_pMesh, pColorMeshes[k][pGroup->m_ColorMeshID].m_nVertOffsetInBytes );
  2102. }
  2103. else
  2104. {
  2105. pMesh->SetColorMesh( NULL, 0 );
  2106. }
  2107. pRenderContext->LoadMatrix( *instance.m_pPoseToWorld );
  2108. for ( int strip = 0; strip < pGroup->m_NumStrips; ++strip )
  2109. {
  2110. OptimizedModel::StripHeader_t* pStrip = &pGroup->m_pStripData[strip];
  2111. pMesh->SetPrimitiveType( GetPrimitiveTypeForStripHeaderFlags( pStrip->flags ) );
  2112. pMesh->DrawModulated( instance.m_DiffuseModulation, pStrip->indexOffset, pStrip->numIndices );
  2113. #ifndef _CERT
  2114. // Count # faces per instance for the first instance only
  2115. if ( k == 0 )
  2116. {
  2117. // This code does not work with SubD but we're not really using that anyways
  2118. Assert( GetPrimitiveTypeForStripHeaderFlags( pStrip->flags ) == MATERIAL_TRIANGLES );
  2119. nFacesPerModel += pStrip->numIndices / 3;
  2120. }
  2121. #endif // !_CERT
  2122. }
  2123. }
  2124. pMesh->SetColorMesh( NULL, 0 );
  2125. }
  2126. }
  2127. #ifndef _CERT
  2128. if ( mat_rendered_faces_count.GetBool() || mat_print_top_model_vert_counts.GetBool() )
  2129. {
  2130. // Each model counts how many rendered faces it accounts for each frame:
  2131. m_pStudioHWData->UpdateFacesRenderedCount( m_pStudioHdr, m_ModelFaceCountHash, lod, nInstanceCount, nFacesPerModel );
  2132. }
  2133. #endif // !_CERT
  2134. // Restore the configs
  2135. m_pRC->m_Config.bFlex = flexConfig;
  2136. m_pRC->m_Config.bWireframe = bWireframe;
  2137. m_pRC = NULL;
  2138. m_pStudioHdr = NULL;
  2139. m_pStudioMeshes = NULL;
  2140. m_pStudioHWData = NULL;
  2141. }
  2142. #ifndef _CERT
  2143. bool FacesRenderedInfoCompareFunc( IStudioRender::FacesRenderedInfo_t const &a, IStudioRender::FacesRenderedInfo_t const &b ) { return a.pStudioHdr == b.pStudioHdr; }
  2144. uint32 FacesRenderedInfoKeyFunc( IStudioRender::FacesRenderedInfo_t const &a ) { return HashIntConventional( (int32)(intp)a.pStudioHdr ); }
  2145. int FacesRenderedInfoSort( const void *a, const void *b )
  2146. {
  2147. IStudioRender::FacesRenderedInfo_t *A = (IStudioRender::FacesRenderedInfo_t *)a, *B = (IStudioRender::FacesRenderedInfo_t *)b;
  2148. return ( A->nFaceCount > B->nFaceCount ) ? -1 : +1;
  2149. }
  2150. void UpdateAndSpewFacesRenderedHistory( CUtlVector< IStudioRender::FacesRenderedInfo_t > &newItems, int nTotal, int nSpewFromCurrentFrame, int nSpewFromHistory, bool bClearHistory )
  2151. {
  2152. static const int NUM_ITEMS_TO_TRACK = 20;
  2153. static const int NUM_FRAMES_TO_TRACK = 20;
  2154. static IStudioRender::FacesRenderedInfo_t history[ NUM_FRAMES_TO_TRACK ][ NUM_ITEMS_TO_TRACK ];
  2155. static int nItems = 0, nOldestItem = 0;
  2156. IStudioRender::FacesRenderedInfo_t emptyItem = { NULL, 0 };
  2157. if ( bClearHistory )
  2158. {
  2159. nItems = nOldestItem = 0;
  2160. return;
  2161. }
  2162. if ( !nTotal )
  2163. return;
  2164. // Record the top 'NUM_ITEMS_TO_TRACK' models for the last rendered frame:
  2165. int nCurItem = ( nOldestItem + nItems ) % NUM_FRAMES_TO_TRACK;
  2166. if ( nItems == NUM_FRAMES_TO_TRACK )
  2167. nOldestItem = ( nOldestItem + 1 ) % NUM_FRAMES_TO_TRACK;
  2168. nItems = MIN( ( nItems + 1 ), NUM_FRAMES_TO_TRACK );
  2169. for ( int i = 0; i < NUM_ITEMS_TO_TRACK; i++ )
  2170. {
  2171. history[ nCurItem ][ i ] = ( i < newItems.Count() ) ? newItems[ i ] : emptyItem;
  2172. }
  2173. nSpewFromCurrentFrame = MIN( nSpewFromCurrentFrame, newItems.Count() );
  2174. if ( nSpewFromCurrentFrame )
  2175. {
  2176. // Spew the top N offenders from this frame to the console
  2177. Msg( "Faces rendered this frame, by model:\n" );
  2178. for ( int i = 0; i < nSpewFromCurrentFrame; i++ )
  2179. {
  2180. Msg( "%-7d (%-3d times, %-7d avg) %s\n", newItems[ i ].nFaceCount, newItems[ i ].nRenderCount, ( int )( ( float )newItems[ i ].nFaceCount / ( float )newItems[ i ].nRenderCount ), newItems[ i ].pStudioHdr->name );
  2181. }
  2182. }
  2183. else
  2184. {
  2185. static float lastSpewTime = 0.0f;
  2186. if ( Plat_FloatTime() < ( lastSpewTime + 0.25f ) )
  2187. return;
  2188. lastSpewTime = Plat_FloatTime();
  2189. // Spew the N most expensive models over the last 'NUM_FRAMES_TO_TRACK' frames:
  2190. CUtlHash< IStudioRender::FacesRenderedInfo_t > topItemHash( 64, 0, 0, FacesRenderedInfoCompareFunc, FacesRenderedInfoKeyFunc );
  2191. for ( int i = 0; i < nItems; i++ )
  2192. {
  2193. IStudioRender::FacesRenderedInfo_t *items = history[ ( nOldestItem + i ) % NUM_FRAMES_TO_TRACK ];
  2194. for ( int j = 0; j < NUM_ITEMS_TO_TRACK; j++ )
  2195. {
  2196. if ( !items[ j ].nFaceCount )
  2197. continue;
  2198. UtlHashHandle_t h = topItemHash.Find( items[ j ] );
  2199. if ( h != topItemHash.InvalidHandle() )
  2200. {
  2201. IStudioRender::FacesRenderedInfo_t &topItem = topItemHash[ h ];
  2202. topItem.nFaceCount = MAX( items[ j ].nFaceCount, topItem.nFaceCount );
  2203. continue;
  2204. }
  2205. topItemHash.Insert( items[ j ] );
  2206. }
  2207. }
  2208. CUtlVector< IStudioRender::FacesRenderedInfo_t > topItems;
  2209. for ( UtlHashHandle_t h = topItemHash.GetFirstHandle(); h != topItemHash.InvalidHandle(); h = topItemHash.GetNextHandle( h ) )
  2210. {
  2211. topItems.AddToTail( topItemHash[ h ] );
  2212. }
  2213. qsort( topItems.Base(), topItems.Count(), sizeof( topItems[0] ), FacesRenderedInfoSort );
  2214. for ( int j = 0; j < MIN( nSpewFromHistory, NUM_ITEMS_TO_TRACK ); j++ )
  2215. {
  2216. if ( j < topItems.Count() )
  2217. ConMsg( "%-7d (%-3d times, %-7d avg) %s\n", topItems[ j ].nFaceCount, topItems[ j ].nRenderCount, ( int )( ( float )topItems[ j ].nFaceCount / ( float )topItems[ j ].nRenderCount ), topItems[ j ].pStudioHdr->name );
  2218. }
  2219. ConMsg( "%-7d total model faces rendered this frame (mat_rendered_faces_count)\n", nTotal );
  2220. }
  2221. }
  2222. int BuildFacesRenderedInfoListForMostRecentFrame( CUtlVector< IStudioRender::FacesRenderedInfo_t > &items, CUtlHash< studiohwdata_t * > &hash )
  2223. {
  2224. int nTotal = 0;
  2225. for ( UtlHashHandle_t h = hash.GetFirstHandle(); h != hash.InvalidHandle(); h = hash.GetNextHandle( h ) )
  2226. {
  2227. studiohwdata_t *pHwData = hash[ h ];
  2228. if ( pHwData->m_pStudioHdr )
  2229. {
  2230. IStudioRender::FacesRenderedInfo_t item = { pHwData->m_pStudioHdr, pHwData->m_NumFacesRenderedThisFrame, pHwData->m_NumTimesRenderedThisFrame };
  2231. items.AddToTail( item );
  2232. nTotal += pHwData->m_NumFacesRenderedThisFrame;
  2233. }
  2234. }
  2235. // Sort models by face count (biggest first)
  2236. qsort( items.Base(), items.Count(), sizeof( items[0] ), FacesRenderedInfoSort );
  2237. return nTotal;
  2238. }
  2239. void CStudioRender::UpdateModelFaceCounts( int nSpewFromCurrentFrame, bool bClearHistory )
  2240. {
  2241. CUtlVector< IStudioRender::FacesRenderedInfo_t > items;
  2242. if ( bClearHistory )
  2243. {
  2244. UpdateAndSpewFacesRenderedHistory( items, 0, 0, 0, bClearHistory );
  2245. }
  2246. else if ( mat_rendered_faces_count.GetBool() )
  2247. {
  2248. int nTotal = BuildFacesRenderedInfoListForMostRecentFrame( items, m_ModelFaceCountHash );
  2249. UpdateAndSpewFacesRenderedHistory( items, nTotal, nSpewFromCurrentFrame, mat_rendered_faces_count.GetInt(), false );
  2250. mat_rendered_faces_count.SetValue( 0 ); // set back to 0 so we don't spew anymore
  2251. }
  2252. }
  2253. int CStudioRender::GetForcedMaterialOverrideIndex( int nMaterialIndex )
  2254. {
  2255. if ( m_pRC )
  2256. {
  2257. for ( int i = 0; i < m_pRC->m_nForcedMaterialIndexCount; i++ )
  2258. {
  2259. if ( m_pRC->m_nForcedMaterialIndex[ i ] == nMaterialIndex )
  2260. {
  2261. return i;
  2262. }
  2263. }
  2264. }
  2265. return -1;
  2266. }
  2267. void CStudioRender::GatherRenderedFaceInfo( IStudioRender::FaceInfoCallbackFunc_t pFunc )
  2268. {
  2269. int nTopN = mat_print_top_model_vert_counts.GetInt();
  2270. if ( nTopN )
  2271. {
  2272. CUtlVector< IStudioRender::FacesRenderedInfo_t > items;
  2273. int nTotal = BuildFacesRenderedInfoListForMostRecentFrame( items, m_ModelFaceCountHash );
  2274. if ( items.Count() > 0 )
  2275. {
  2276. nTopN = MIN( nTopN, items.Count());
  2277. pFunc( nTopN, items.Base(), nTotal );
  2278. }
  2279. }
  2280. }
  2281. CON_COMMAND( mat_rendered_faces_spew, "'mat_rendered_faces_spew <n>' Spew the number of faces rendered for the top N models used this frame (mat_rendered_faces_count must be set to use this)" )
  2282. {
  2283. int nNumToSpew = ( args.ArgC() > 1 ) ? Q_atoi( args[ 1 ] ) : INT_MAX;
  2284. if ( !mat_rendered_faces_count.GetBool() )
  2285. {
  2286. Msg( "ERROR: mat_rendered_faces_count must be set in order to use mat_rendered_faces_spew\n" );
  2287. return;
  2288. }
  2289. g_StudioRender.UpdateModelFaceCounts( nNumToSpew );
  2290. }
  2291. #endif // !_CERT