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.

1430 lines
49 KiB

  1. //===== Copyright � 1996-2007, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #include "render_pch.h"
  9. #include "brushbatchrender.h"
  10. #include "icliententity.h"
  11. #include "r_decal.h"
  12. #include "gl_rsurf.h"
  13. #include "tier0/vprof.h"
  14. #include <algorithm>
  15. CBrushBatchRender g_BrushBatchRenderer;
  16. FORCEINLINE void ModulateMaterial( IMaterial *pMaterial, float *pOldColor )
  17. {
  18. if ( g_bIsBlendingOrModulating )
  19. {
  20. pOldColor[3] = pMaterial->GetAlphaModulation( );
  21. pMaterial->GetColorModulation( &pOldColor[0], &pOldColor[1], &pOldColor[2] );
  22. pMaterial->AlphaModulate( r_blend );
  23. pMaterial->ColorModulate( r_colormod[0], r_colormod[1], r_colormod[2] );
  24. }
  25. }
  26. FORCEINLINE void UnModulateMaterial( IMaterial *pMaterial, float *pOldColor )
  27. {
  28. if ( g_bIsBlendingOrModulating )
  29. {
  30. pMaterial->AlphaModulate( pOldColor[3] );
  31. pMaterial->ColorModulate( pOldColor[0], pOldColor[1], pOldColor[2] );
  32. }
  33. }
  34. int __cdecl CBrushBatchRender::SurfaceCmp(const surfacelist_t *s0, const surfacelist_t *s1 )
  35. {
  36. int sortID0 = MSurf_MaterialSortID( s0->surfID );
  37. int sortID1 = MSurf_MaterialSortID( s1->surfID );
  38. return sortID0 - sortID1;
  39. }
  40. // Builds a transrender_t, then executes it's drawing commands
  41. void CBrushBatchRender::DrawTranslucentBrushModel( IMatRenderContext *pRenderContext, model_t *model, IClientEntity *baseentity )
  42. {
  43. transrender_t render;
  44. render.pLastBatch = NULL;
  45. render.pLastNode = NULL;
  46. render.nodeCount = 0;
  47. render.surfaceCount = 0;
  48. render.batchCount = 0;
  49. render.decalSurfaceCount = 0;
  50. BuildTransLists_r( render, model, model->brush.pShared->nodes + model->brush.firstnode );
  51. void *pProxyData = baseentity ? baseentity->GetClientRenderable() : NULL;
  52. DrawTransLists( pRenderContext, render, pProxyData );
  53. }
  54. void CBrushBatchRender::AddSurfaceToBatch( transrender_t &render, transnode_t *pNode, transbatch_t *pBatch, SurfaceHandle_t surfID )
  55. {
  56. pBatch->surfaceCount++;
  57. Assert(render.surfaceCount < MAX_TRANS_SURFACES);
  58. pBatch->indexCount += (MSurf_VertCount( surfID )-2)*3;
  59. render.surfaces[render.surfaceCount] = surfID;
  60. render.surfaceCount++;
  61. if ( SurfaceHasDecals( surfID ) || MSurf_ShadowDecals( surfID ) != SHADOW_DECAL_HANDLE_INVALID )
  62. {
  63. Assert(render.decalSurfaceCount < MAX_TRANS_DECALS);
  64. pNode->decalSurfaceCount++;
  65. render.decalSurfaces[render.decalSurfaceCount] = surfID;
  66. render.decalSurfaceCount++;
  67. }
  68. }
  69. void CBrushBatchRender::AddTransNode( transrender_t &render )
  70. {
  71. render.pLastNode = &render.nodes[render.nodeCount];
  72. render.nodeCount++;
  73. Assert(render.nodeCount < MAX_TRANS_NODES);
  74. render.pLastBatch = NULL;
  75. render.pLastNode->firstBatch = render.batchCount;
  76. render.pLastNode->firstDecalSurface = render.decalSurfaceCount;
  77. render.pLastNode->batchCount = 0;
  78. render.pLastNode->decalSurfaceCount = 0;
  79. }
  80. void CBrushBatchRender::AddTransBatch( transrender_t &render, SurfaceHandle_t surfID )
  81. {
  82. transbatch_t &batch = render.batches[render.pLastNode->firstBatch + render.pLastNode->batchCount];
  83. Assert(render.batchCount < MAX_TRANS_BATCHES);
  84. render.pLastNode->batchCount++;
  85. render.batchCount++;
  86. batch.firstSurface = render.surfaceCount;
  87. batch.surfaceCount = 0;
  88. batch.pMaterial = MSurf_TexInfo( surfID )->material;
  89. batch.sortID = MSurf_MaterialSortID( surfID );
  90. batch.indexCount = 0;
  91. render.pLastBatch = &batch;
  92. AddSurfaceToBatch( render, render.pLastNode, &batch, surfID );
  93. }
  94. // build node lists
  95. void CBrushBatchRender::BuildTransLists_r( transrender_t &render, model_t *model, mnode_t *node )
  96. {
  97. float dot;
  98. if (node->contents >= 0)
  99. return;
  100. // node is just a decision point, so go down the apropriate sides
  101. // find which side of the node we are on
  102. cplane_t *plane = node->plane;
  103. if ( plane->type <= PLANE_Z )
  104. {
  105. dot = modelorg[plane->type] - plane->dist;
  106. }
  107. else
  108. {
  109. dot = DotProduct (modelorg, plane->normal) - plane->dist;
  110. }
  111. int side = (dot >= 0) ? 0 : 1;
  112. // back side first - translucent surfaces need to render in back to front order
  113. // to appear correctly.
  114. BuildTransLists_r(render, model, node->children[!side]);
  115. // emit all surfaces on node
  116. CUtlVectorFixed<surfacelist_t, 256> sortList;
  117. SurfaceHandle_t surfID = SurfaceHandleFromIndex( node->firstsurface, model->brush.pShared );
  118. for ( int i = 0; i < node->numsurfaces; i++, surfID++ )
  119. {
  120. // skip opaque surfaces
  121. if ( MSurf_Flags(surfID) & SURFDRAW_TRANS )
  122. {
  123. if ( ((MSurf_Flags( surfID ) & SURFDRAW_NOCULL) == 0) )
  124. {
  125. // Backface cull here, so they won't do any more work
  126. if ( ( side ^ !!(MSurf_Flags( surfID ) & SURFDRAW_PLANEBACK)) )
  127. continue;
  128. }
  129. // If this can be appended to the previous batch, do so
  130. int sortID = MSurf_MaterialSortID( surfID );
  131. if ( render.pLastBatch && render.pLastBatch->sortID == sortID )
  132. {
  133. AddSurfaceToBatch( render, render.pLastNode, render.pLastBatch, surfID );
  134. }
  135. else
  136. {
  137. // save it off for sorting, then a later append
  138. int sortIndex = sortList.AddToTail();
  139. sortList[sortIndex].surfID = surfID;
  140. }
  141. }
  142. }
  143. // We've got surfaces on this node that can't be added to the previous node
  144. if ( sortList.Count() )
  145. {
  146. // sort by material
  147. sortList.Sort( SurfaceCmp );
  148. // add a new sort group
  149. AddTransNode( render );
  150. int lastSortID = -1;
  151. // now add the optimal number of batches to that group
  152. for ( int i = 0; i < sortList.Count(); i++ )
  153. {
  154. surfID = sortList[i].surfID;
  155. int sortID = MSurf_MaterialSortID( surfID );
  156. if ( lastSortID == sortID )
  157. {
  158. // can be drawn in a single call with the current list of surfaces, append
  159. AddSurfaceToBatch( render, render.pLastNode, render.pLastBatch, surfID );
  160. }
  161. else
  162. {
  163. // requires a break (material/lightmap change).
  164. AddTransBatch( render, surfID );
  165. lastSortID = sortID;
  166. }
  167. }
  168. // don't batch across decals or decals will sort incorrectly
  169. if ( render.pLastNode->decalSurfaceCount )
  170. {
  171. render.pLastNode = NULL;
  172. render.pLastBatch = NULL;
  173. }
  174. }
  175. // front side
  176. BuildTransLists_r(render, model, node->children[side]);
  177. }
  178. void CBrushBatchRender::DrawTransLists( IMatRenderContext *pRenderContext, transrender_t &render, void *pProxyData )
  179. {
  180. PIXEVENT( pRenderContext, "DrawTransLists()" );
  181. bool skipLight = false;
  182. if ( g_pMaterialSystemConfig->nFullbright == 1 )
  183. {
  184. pRenderContext->BindLightmapPage( MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP );
  185. skipLight = true;
  186. }
  187. float pOldColor[4];
  188. for ( int i = 0; i < render.nodeCount; i++ )
  189. {
  190. int j;
  191. const transnode_t &node = render.nodes[i];
  192. for ( j = 0; j < node.batchCount; j++ )
  193. {
  194. const transbatch_t &batch = render.batches[node.firstBatch+j];
  195. CMeshBuilder meshBuilder;
  196. IMaterial *pMaterial = batch.pMaterial;
  197. ModulateMaterial( pMaterial, pOldColor );
  198. if ( !skipLight )
  199. {
  200. pRenderContext->BindLightmapPage( materialSortInfoArray[batch.sortID].lightmapPageID );
  201. }
  202. pRenderContext->Bind( pMaterial, pProxyData );
  203. IMesh *pBuildMesh = pRenderContext->GetDynamicMesh( false, g_WorldStaticMeshes[batch.sortID], NULL, NULL );
  204. meshBuilder.Begin( pBuildMesh, MATERIAL_TRIANGLES, 0, batch.indexCount );
  205. for ( int k = 0; k < batch.surfaceCount; k++ )
  206. {
  207. SurfaceHandle_t surfID = render.surfaces[batch.firstSurface + k];
  208. Assert( !(MSurf_Flags( surfID ) & SURFDRAW_NODRAW) );
  209. BuildIndicesForSurface( meshBuilder, surfID );
  210. }
  211. meshBuilder.End( false, true );
  212. // Don't leave the material in a bogus state
  213. UnModulateMaterial( pMaterial, pOldColor );
  214. }
  215. if ( node.decalSurfaceCount )
  216. {
  217. for ( j = 0; j < node.decalSurfaceCount; j++ )
  218. {
  219. SurfaceHandle_t surfID = render.decalSurfaces[node.firstDecalSurface + j];
  220. Assert( !(MSurf_Flags( surfID ) & SURFDRAW_NODRAW) );
  221. if( SurfaceHasDecals( surfID ) )
  222. {
  223. DecalSurfaceAdd( surfID, BRUSHMODEL_DECAL_SORT_GROUP );
  224. }
  225. // Add shadows too....
  226. ShadowDecalHandle_t decalHandle = MSurf_ShadowDecals( surfID );
  227. if (decalHandle != SHADOW_DECAL_HANDLE_INVALID)
  228. {
  229. g_pShadowMgr->AddShadowsOnSurfaceToRenderList( decalHandle );
  230. }
  231. }
  232. // Now draw the decals + shadows for this node
  233. // This order relative to the surfaces is important for translucency to work correctly.
  234. DecalSurfaceDraw(pRenderContext, BRUSHMODEL_DECAL_SORT_GROUP);
  235. // FIXME: Decals are not being rendered while illuminated by the flashlight
  236. // FIXME: Need to draw decals in flashlight rendering mode
  237. // Retire decals on opaque world surfaces
  238. R_DecalFlushDestroyList();
  239. DecalSurfacesInit( true );
  240. // Draw all shadows on the brush
  241. g_pShadowMgr->RenderProjectedTextures( pRenderContext );
  242. }
  243. if ( g_ShaderDebug.anydebug )
  244. {
  245. CUtlVector<msurface2_t *> brushList;
  246. for ( j = 0; j < node.batchCount; j++ )
  247. {
  248. const transbatch_t &batch = render.batches[node.firstBatch+j];
  249. for ( int k = 0; k < batch.surfaceCount; k++ )
  250. {
  251. brushList.AddToTail( render.surfaces[batch.firstSurface + k] );
  252. }
  253. }
  254. DrawDebugInformation( pRenderContext, brushList.Base(), brushList.Count() );
  255. }
  256. }
  257. }
  258. //-----------------------------------------------------------------------------
  259. // Purpose: This is used when the mat_dxlevel is changed to reset the brush
  260. // models.
  261. //-----------------------------------------------------------------------------
  262. void R_BrushBatchInit( void )
  263. {
  264. g_BrushBatchRenderer.LevelInit();
  265. }
  266. void CBrushBatchRender::LevelInit()
  267. {
  268. AUTO_LOCK( m_Mutex );
  269. unsigned short iNext;
  270. for( unsigned short i=m_renderList.Head(); i != m_renderList.InvalidIndex(); i=iNext )
  271. {
  272. iNext = m_renderList.Next(i);
  273. delete m_renderList.Element(i);
  274. }
  275. m_renderList.Purge();
  276. ClearRenderHandles();
  277. }
  278. void CBrushBatchRender::ClearRenderHandles( void )
  279. {
  280. for ( int iBrush = 1 ; iBrush < host_state.worldbrush->numsubmodels ; ++iBrush )
  281. {
  282. char szBrushModel[5]; // inline model names "*1", "*2" etc
  283. Q_snprintf( szBrushModel, sizeof( szBrushModel ), "*%i", iBrush );
  284. model_t *pModel = modelloader->GetModelForName( szBrushModel, IModelLoader::FMODELLOADER_SERVER );
  285. if ( pModel )
  286. {
  287. pModel->brush.renderHandle = 0;
  288. }
  289. }
  290. }
  291. // Create a compact, optimal list of rendering commands for the opaque parts of a brush model
  292. // NOTE: This just skips translucent surfaces assuming a separate transrender_t pass!
  293. CBrushBatchRender::brushrender_t *CBrushBatchRender::FindOrCreateRenderBatch( model_t *pModel )
  294. {
  295. if ( !pModel->brush.nummodelsurfaces )
  296. return NULL;
  297. AUTO_LOCK( m_Mutex );
  298. unsigned short index = pModel->brush.renderHandle - 1;
  299. if ( m_renderList.IsValidIndex( index ) )
  300. return m_renderList.Element(index);
  301. brushrender_t *pRender = new brushrender_t;
  302. index = m_renderList.AddToTail( pRender );
  303. pModel->brush.renderHandle = index + 1;
  304. brushrender_t &render = *pRender;
  305. render.pPlanes = NULL;
  306. render.pMeshes = NULL;
  307. render.planeCount = 0;
  308. render.meshCount = 0;
  309. render.totalIndexCount = 0;
  310. render.totalVertexCount = 0;
  311. CUtlVector<cplane_t *> planeList;
  312. CUtlVector<surfacelist_t> surfaceList;
  313. int i;
  314. SurfaceHandle_t surfID = SurfaceHandleFromIndex( pModel->brush.firstmodelsurface, pModel->brush.pShared );
  315. for (i=0 ; i<pModel->brush.nummodelsurfaces; i++, surfID++)
  316. {
  317. // UNDONE: For now, just draw these in a separate pass
  318. if ( MSurf_Flags(surfID) & SURFDRAW_TRANS )
  319. continue;
  320. #ifndef _PS3
  321. cplane_t *plane = surfID->plane;
  322. #else
  323. cplane_t *plane = &surfID->m_plane;
  324. #endif
  325. int planeIndex = planeList.Find(plane);
  326. if ( planeIndex == -1 )
  327. {
  328. planeIndex = planeList.AddToTail( plane );
  329. }
  330. surfacelist_t tmp;
  331. tmp.surfID = surfID;
  332. tmp.surfaceIndex = i;
  333. tmp.planeIndex = planeIndex;
  334. surfaceList.AddToTail( tmp );
  335. }
  336. surfaceList.Sort( SurfaceCmp );
  337. render.pPlanes = new cplane_t *[planeList.Count()];
  338. render.planeCount = planeList.Count();
  339. memcpy( render.pPlanes, planeList.Base(), sizeof(cplane_t *)*planeList.Count() );
  340. render.pSurfaces = new brushrendersurface_t[surfaceList.Count()];
  341. render.surfaceCount = surfaceList.Count();
  342. int meshCount = 0;
  343. int batchCount = 0;
  344. int lastSortID = -1;
  345. IMesh *pLastMesh = NULL;
  346. brushrendermesh_t *pMesh = NULL;
  347. brushrendermesh_t tmpMesh[MAX_VERTEX_FORMAT_CHANGES];
  348. brushrenderbatch_t *pBatch = NULL;
  349. brushrenderbatch_t tmpBatch[128];
  350. for ( i = 0; i < surfaceList.Count(); i++ )
  351. {
  352. render.pSurfaces[i].surfaceIndex = surfaceList[i].surfaceIndex;
  353. render.pSurfaces[i].planeIndex = surfaceList[i].planeIndex;
  354. surfID = surfaceList[i].surfID;
  355. int sortID = MSurf_MaterialSortID( surfID );
  356. if ( g_WorldStaticMeshes[sortID] != pLastMesh )
  357. {
  358. pMesh = tmpMesh + meshCount;
  359. pMesh->firstBatch = batchCount;
  360. pMesh->batchCount = 0;
  361. lastSortID = -1; // force a new batch
  362. meshCount++;
  363. }
  364. if ( sortID != lastSortID )
  365. {
  366. pBatch = tmpBatch + batchCount;
  367. pBatch->firstSurface = i;
  368. pBatch->surfaceCount = 0;
  369. pBatch->sortID = sortID;
  370. pBatch->pMaterial = MSurf_TexInfo( surfID )->material;
  371. pBatch->indexCount = 0;
  372. pMesh->batchCount++;
  373. batchCount++;
  374. }
  375. pLastMesh = g_WorldStaticMeshes[sortID];
  376. lastSortID = sortID;
  377. pBatch->surfaceCount++;
  378. int vertCount = MSurf_VertCount( surfID );
  379. int indexCount = (vertCount - 2) * 3;
  380. pBatch->indexCount += indexCount;
  381. render.totalIndexCount += indexCount;
  382. render.totalVertexCount += vertCount;
  383. }
  384. render.pMeshes = new brushrendermesh_t[meshCount];
  385. memcpy( render.pMeshes, tmpMesh, sizeof(brushrendermesh_t) * meshCount );
  386. render.meshCount = meshCount;
  387. render.pBatches = new brushrenderbatch_t[batchCount];
  388. memcpy( render.pBatches, tmpBatch, sizeof(brushrenderbatch_t) * batchCount );
  389. render.batchCount = batchCount;
  390. return &render;
  391. }
  392. //-----------------------------------------------------------------------------
  393. // Draws an opaque (parts of a) brush model
  394. //-----------------------------------------------------------------------------
  395. void CBrushBatchRender::DrawOpaqueBrushModel( IMatRenderContext *pRenderContext, IClientEntity *baseentity, model_t *model, ERenderDepthMode_t DepthMode )
  396. {
  397. VPROF( "R_DrawOpaqueBrushModel" );
  398. SurfaceHandle_t firstSurfID = SurfaceHandleFromIndex( model->brush.firstmodelsurface, model->brush.pShared );
  399. brushrender_t *pRender = FindOrCreateRenderBatch( model );
  400. int i;
  401. if ( !pRender )
  402. return;
  403. bool skipLight = false;
  404. PIXEVENT( pRenderContext, "DrawOpaqueBrushModel()" );
  405. if ( (g_pMaterialSystemConfig->nFullbright == 1) || ( DepthMode == DEPTH_MODE_SHADOW || DepthMode == DEPTH_MODE_SSA0 ) )
  406. {
  407. pRenderContext->BindLightmapPage( MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP );
  408. skipLight = true;
  409. }
  410. void *pProxyData = baseentity ? baseentity->GetClientRenderable() : NULL;
  411. int backface[1024];
  412. Assert( pRender->planeCount < 1024 );
  413. // NOTE: Backface culling is almost no perf gain. Can be removed from brush model rendering.
  414. // Check the shared planes once
  415. if ( DepthMode == DEPTH_MODE_SHADOW || DepthMode == DEPTH_MODE_SSA0 )
  416. {
  417. for ( i = 0; i < pRender->planeCount; i++ )
  418. {
  419. backface[i] = 0;
  420. }
  421. }
  422. else
  423. {
  424. for ( i = 0; i < pRender->planeCount; i++ )
  425. {
  426. float dot = DotProduct( modelorg, pRender->pPlanes[i]->normal) - pRender->pPlanes[i]->dist;
  427. backface[i] = ( dot < BACKFACE_EPSILON ) ? true : false; // don't backface cull when rendering to shadow map
  428. }
  429. }
  430. float pOldColor[4];
  431. // PORTAL 2 PAINT RENDERING
  432. CUtlVectorFixedGrowable< SurfaceHandle_t, 64 > paintableSurfaces;
  433. CUtlVectorFixedGrowable< int, 16 > batchPaintableSurfaceCount;
  434. CUtlVectorFixedGrowable< int, 16 > batchPaintableSurfaceIndexCount;
  435. for ( i = 0; i < pRender->meshCount; i++ )
  436. {
  437. brushrendermesh_t &mesh = pRender->pMeshes[i];
  438. for ( int j = 0; j < mesh.batchCount; j++ )
  439. {
  440. int nBatchIndex = batchPaintableSurfaceCount.Count();
  441. batchPaintableSurfaceCount.AddToTail( 0 );
  442. batchPaintableSurfaceIndexCount.AddToTail( 0 );
  443. brushrenderbatch_t &batch = pRender->pBatches[mesh.firstBatch + j];
  444. int k;
  445. for ( k = 0; k < batch.surfaceCount; k++ )
  446. {
  447. brushrendersurface_t &surface = pRender->pSurfaces[batch.firstSurface + k];
  448. if ( !backface[surface.planeIndex] )
  449. break;
  450. }
  451. if ( k == batch.surfaceCount )
  452. continue;
  453. CMeshBuilder meshBuilder;
  454. IMaterial *pMaterial = NULL;
  455. if ( DepthMode != DEPTH_MODE_NORMAL )
  456. {
  457. // Select proper override material
  458. int nAlphaTest = (int) batch.pMaterial->IsAlphaTested();
  459. int nNoCull = (int) batch.pMaterial->IsTwoSided();
  460. IMaterial *pDepthWriteMaterial;
  461. if ( DepthMode == DEPTH_MODE_SHADOW )
  462. {
  463. pDepthWriteMaterial = g_pMaterialDepthWrite[ nAlphaTest ][ nNoCull ];
  464. }
  465. else
  466. {
  467. pDepthWriteMaterial = g_pMaterialSSAODepthWrite[ nAlphaTest ][ nNoCull ];
  468. }
  469. if ( nAlphaTest == 1 )
  470. {
  471. static unsigned int originalTextureVarCache = 0;
  472. IMaterialVar *pOriginalTextureVar = batch.pMaterial->FindVarFast( "$basetexture", &originalTextureVarCache );
  473. static unsigned int originalTextureFrameVarCache = 0;
  474. IMaterialVar *pOriginalTextureFrameVar = batch.pMaterial->FindVarFast( "$frame", &originalTextureFrameVarCache );
  475. static unsigned int originalAlphaRefCache = 0;
  476. IMaterialVar *pOriginalAlphaRefVar = batch.pMaterial->FindVarFast( "$AlphaTestReference", &originalAlphaRefCache );
  477. static unsigned int textureVarCache = 0;
  478. IMaterialVar *pTextureVar = pDepthWriteMaterial->FindVarFast( "$basetexture", &textureVarCache );
  479. static unsigned int textureFrameVarCache = 0;
  480. IMaterialVar *pTextureFrameVar = pDepthWriteMaterial->FindVarFast( "$frame", &textureFrameVarCache );
  481. static unsigned int alphaRefCache = 0;
  482. IMaterialVar *pAlphaRefVar = pDepthWriteMaterial->FindVarFast( "$AlphaTestReference", &alphaRefCache );
  483. if( pTextureVar && pOriginalTextureVar )
  484. {
  485. pTextureVar->SetTextureValue( pOriginalTextureVar->GetTextureValue() );
  486. }
  487. if( pTextureFrameVar && pOriginalTextureFrameVar )
  488. {
  489. pTextureFrameVar->SetIntValue( pOriginalTextureFrameVar->GetIntValue() );
  490. }
  491. if( pAlphaRefVar && pOriginalAlphaRefVar )
  492. {
  493. pAlphaRefVar->SetFloatValue( pOriginalAlphaRefVar->GetFloatValue() );
  494. }
  495. }
  496. pMaterial = pDepthWriteMaterial;
  497. }
  498. else
  499. {
  500. pMaterial = batch.pMaterial;
  501. // Store off the old color + alpha
  502. ModulateMaterial( pMaterial, pOldColor );
  503. if ( !skipLight )
  504. {
  505. pRenderContext->BindLightmapPage( materialSortInfoArray[batch.sortID].lightmapPageID );
  506. }
  507. }
  508. pRenderContext->Bind( pMaterial, pProxyData );
  509. IMesh *pBuildMesh = pRenderContext->GetDynamicMesh( false, g_WorldStaticMeshes[batch.sortID], NULL, NULL );
  510. meshBuilder.Begin( pBuildMesh, MATERIAL_TRIANGLES, 0, batch.indexCount );
  511. for ( ; k < batch.surfaceCount; k++ )
  512. {
  513. brushrendersurface_t &surface = pRender->pSurfaces[batch.firstSurface + k];
  514. if ( backface[surface.planeIndex] )
  515. continue;
  516. SurfaceHandle_t surfID = firstSurfID + surface.surfaceIndex;
  517. Assert( !(MSurf_Flags( surfID ) & SURFDRAW_NODRAW) );
  518. // PORTAL 2 PAINT RENDERING
  519. if ( (DepthMode == DEPTH_MODE_NORMAL) && ( MSurf_Flags( surfID ) & SURFDRAW_PAINTED ) )
  520. {
  521. paintableSurfaces.AddToTail( surfID );
  522. ++ batchPaintableSurfaceCount[ nBatchIndex ];
  523. int nVertCount, nIndexCount;
  524. Shader_GetSurfVertexAndIndexCount( surfID, &nVertCount, &nIndexCount );
  525. batchPaintableSurfaceIndexCount[ nBatchIndex ] += nIndexCount;
  526. }
  527. BuildIndicesForSurface( meshBuilder, surfID );
  528. if( SurfaceHasDecals( surfID ) && (DepthMode == DEPTH_MODE_NORMAL))
  529. {
  530. DecalSurfaceAdd( surfID, BRUSHMODEL_DECAL_SORT_GROUP );
  531. }
  532. // Add overlay fragments to list.
  533. // FIXME: A little code support is necessary to get overlays working on brush models
  534. // OverlayMgr()->AddFragmentListToRenderList( MSurf_OverlayFragmentList( surfID ), false );
  535. if ( DepthMode == DEPTH_MODE_NORMAL )
  536. {
  537. // Add render-to-texture shadows too....
  538. ShadowDecalHandle_t decalHandle = MSurf_ShadowDecals( surfID );
  539. if (decalHandle != SHADOW_DECAL_HANDLE_INVALID)
  540. {
  541. g_pShadowMgr->AddShadowsOnSurfaceToRenderList( decalHandle );
  542. }
  543. }
  544. }
  545. meshBuilder.End( false, true );
  546. if ( DepthMode == DEPTH_MODE_NORMAL )
  547. {
  548. // Don't leave the material in a bogus state
  549. UnModulateMaterial( pMaterial, pOldColor );
  550. }
  551. }
  552. }
  553. if ( DepthMode != DEPTH_MODE_NORMAL )
  554. return;
  555. // PORTAL 2 PAINT RENDERING
  556. if ( paintableSurfaces.Count() )
  557. {
  558. pRenderContext->SetRenderingPaint( true );
  559. PIXEVENT( pRenderContext, "Paint" );
  560. int nBatchIndex = 0;
  561. int nSurfaceIndex = 0;
  562. for ( i = 0; i < pRender->meshCount; i++ )
  563. {
  564. brushrendermesh_t &mesh = pRender->pMeshes[i];
  565. for ( int j = 0; j < mesh.batchCount; j++ )
  566. {
  567. int nSurfaceCount = batchPaintableSurfaceCount[ nBatchIndex ];
  568. if ( nSurfaceCount > 0 )
  569. {
  570. brushrenderbatch_t &batch = pRender->pBatches[mesh.firstBatch + j];
  571. IMaterial *pMaterial = batch.pMaterial;
  572. if ( !skipLight )
  573. {
  574. pRenderContext->BindLightmapPage( materialSortInfoArray[batch.sortID].lightmapPageID );
  575. }
  576. pRenderContext->Bind( pMaterial, pProxyData );
  577. CMeshBuilder meshBuilder;
  578. IMesh *pBuildMesh = pRenderContext->GetDynamicMesh( false, g_WorldStaticMeshes[batch.sortID], NULL, NULL );
  579. meshBuilder.Begin( pBuildMesh, MATERIAL_TRIANGLES, 0, batchPaintableSurfaceIndexCount[ nBatchIndex ] );
  580. for ( int i = 0; i < nSurfaceCount; ++ i, ++ nSurfaceIndex )
  581. {
  582. BuildIndicesForSurface( meshBuilder, paintableSurfaces[ nSurfaceIndex ] );
  583. }
  584. meshBuilder.End( false, true );
  585. }
  586. ++ nBatchIndex;
  587. }
  588. }
  589. pRenderContext->SetRenderingPaint( false );
  590. }
  591. if ( g_ShaderDebug.anydebug )
  592. {
  593. for ( i = 0; i < pRender->meshCount; i++ )
  594. {
  595. brushrendermesh_t &mesh = pRender->pMeshes[i];
  596. CUtlVector<msurface2_t *> brushList;
  597. for ( int j = 0; j < mesh.batchCount; j++ )
  598. {
  599. brushrenderbatch_t &batch = pRender->pBatches[mesh.firstBatch + j];
  600. for ( int k = 0; k < batch.surfaceCount; k++ )
  601. {
  602. brushrendersurface_t &surface = pRender->pSurfaces[batch.firstSurface + k];
  603. if ( backface[surface.planeIndex] )
  604. continue;
  605. SurfaceHandle_t surfID = firstSurfID + surface.surfaceIndex;
  606. brushList.AddToTail(surfID);
  607. }
  608. }
  609. // now draw debug for each drawn surface
  610. DrawDebugInformation( pRenderContext, brushList.Base(), brushList.Count() );
  611. }
  612. }
  613. }
  614. //-----------------------------------------------------------------------------
  615. // Draws an translucent (sorted) brush model
  616. //-----------------------------------------------------------------------------
  617. void CBrushBatchRender::DrawTranslucentBrushModel( IMatRenderContext *pRenderContext, IClientEntity *baseentity, model_t *model, ERenderDepthMode_t DepthMode, bool bDrawOpaque, bool bDrawTranslucent )
  618. {
  619. if ( bDrawOpaque )
  620. {
  621. DrawOpaqueBrushModel( pRenderContext, baseentity, model, DepthMode );
  622. }
  623. if ( ( DepthMode == DEPTH_MODE_NORMAL ) && bDrawTranslucent )
  624. {
  625. DrawTranslucentBrushModel( pRenderContext, model, baseentity );
  626. }
  627. }
  628. //-----------------------------------------------------------------------------
  629. // Purpose: Draws a brush model shadow for render-to-texture shadows
  630. //-----------------------------------------------------------------------------
  631. // UNDONE: This is reasonable, but it could be much faster as follows:
  632. // Build a vertex buffer cache. A block-allocated static mesh with 1024 verts
  633. // per block or something.
  634. // When a new brush is encountered, fill it in to the current block or the
  635. // next one (first fit allocator). Then this routine could simply draw
  636. // a static mesh with a single index buffer build, draw call (no dynamic vb).
  637. void CBrushBatchRender::DrawBrushModelShadow( IMatRenderContext *pRenderContext, model_t *model, IClientRenderable *pRenderable )
  638. {
  639. brushrender_t *pRender = FindOrCreateRenderBatch( (model_t *)model );
  640. if ( !pRender )
  641. return;
  642. pRenderContext->Bind( g_pMaterialShadowBuild, pRenderable );
  643. // Draws all surfaces in the brush model in arbitrary order
  644. SurfaceHandle_t surfID = SurfaceHandleFromIndex( model->brush.firstmodelsurface, model->brush.pShared );
  645. IMesh *pMesh = pRenderContext->GetDynamicMesh();
  646. CMeshBuilder meshBuilder;
  647. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, pRender->totalVertexCount, pRender->totalIndexCount );
  648. for ( int i=0 ; i<model->brush.nummodelsurfaces ; i++, surfID++)
  649. {
  650. Assert( !(MSurf_Flags( surfID ) & SURFDRAW_NODRAW) );
  651. if ( MSurf_Flags(surfID) & SURFDRAW_TRANS )
  652. continue;
  653. int startVert = MSurf_FirstVertIndex( surfID );
  654. int vertCount = MSurf_VertCount( surfID );
  655. int startIndex = meshBuilder.GetCurrentVertex();
  656. int j;
  657. for ( j = 0; j < vertCount; j++ )
  658. {
  659. int vertIndex = model->brush.pShared->vertindices[startVert + j];
  660. // world-space vertex
  661. meshBuilder.Position3fv( model->brush.pShared->vertexes[vertIndex].position.Base() );
  662. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  663. meshBuilder.AdvanceVertex();
  664. }
  665. for ( j = 0; j < vertCount-2; j++ )
  666. {
  667. meshBuilder.FastIndex( startIndex );
  668. meshBuilder.FastIndex( startIndex + j + 1 );
  669. meshBuilder.FastIndex( startIndex + j + 2 );
  670. }
  671. }
  672. meshBuilder.End();
  673. pMesh->Draw();
  674. }
  675. inline bool __cdecl CBrushBatchRender::BatchSortLessFunc( const BrushBatchRenderData_t &left, const BrushBatchRenderData_t &right )
  676. {
  677. brushrenderbatch_t &leftBatch = left.m_pBrushRender->pBatches[ left.m_nBatchIndex ];
  678. brushrenderbatch_t &rightBatch = right.m_pBrushRender->pBatches[ right.m_nBatchIndex ];
  679. if ( left.m_pMaterial != right.m_pMaterial )
  680. return left.m_pMaterial < right.m_pMaterial;
  681. if ( leftBatch.sortID != rightBatch.sortID )
  682. return leftBatch.sortID < rightBatch.sortID;
  683. if ( left.m_pInstanceData->m_pStencilState != right.m_pInstanceData->m_pStencilState )
  684. return left.m_pInstanceData->m_pStencilState < right.m_pInstanceData->m_pStencilState;
  685. if ( left.m_pInstanceData->m_pBrushToWorld != right.m_pInstanceData->m_pBrushToWorld )
  686. return left.m_pInstanceData->m_pBrushToWorld < right.m_pInstanceData->m_pBrushToWorld;
  687. return false;
  688. }
  689. //-----------------------------------------------------------------------------
  690. // Builds the lists of stuff to draw
  691. //-----------------------------------------------------------------------------
  692. void CBrushBatchRender::BuildBatchListToDraw( int nCount, const BrushArrayInstanceData_t *pInstanceData,
  693. CUtlVectorFixedGrowable< BrushBatchRenderData_t, 1024 > &batchesToRender, brushrender_t **ppBrushRender )
  694. {
  695. for ( int i = 0; i < nCount; ++i )
  696. {
  697. const BrushArrayInstanceData_t &instance = pInstanceData[i];
  698. brushrender_t *pRender = g_BrushBatchRenderer.FindOrCreateRenderBatch( const_cast< model_t* >( instance.m_pBrushModel ) );
  699. ppBrushRender[i] = pRender;
  700. if ( !pRender )
  701. continue;
  702. for ( int m = 0; m < pRender->meshCount; ++m )
  703. {
  704. brushrendermesh_t &mesh = pRender->pMeshes[m];
  705. int nBatchIndex = mesh.firstBatch;
  706. for ( int j = 0; j < mesh.batchCount; ++j, ++nBatchIndex )
  707. {
  708. int nIndex = batchesToRender.AddToTail();
  709. BrushBatchRenderData_t &batch = batchesToRender[nIndex];
  710. batch.m_pMaterial = pRender->pBatches[nBatchIndex].pMaterial;
  711. batch.m_pInstanceData = &instance;
  712. batch.m_pBrushRender = pRender;
  713. batch.m_nBatchIndex = nBatchIndex;
  714. Assert( nBatchIndex < ( 1 << 15 ) );
  715. }
  716. }
  717. }
  718. }
  719. //-----------------------------------------------------------------------------
  720. // Computes lightmap pages
  721. //-----------------------------------------------------------------------------
  722. void CBrushBatchRender::ComputeLightmapPages( int nCount, BrushBatchRenderData_t *pRenderData )
  723. {
  724. if ( g_pMaterialSystemConfig->nFullbright != 1 )
  725. {
  726. for ( int i = 0; i < nCount; ++i )
  727. {
  728. brushrenderbatch_t &batch = pRenderData[i].m_pBrushRender->pBatches[ pRenderData[i].m_nBatchIndex ];
  729. int nSortID = batch.sortID;
  730. Assert( nSortID >= 0 && nSortID < g_WorldStaticMeshes.Count() );
  731. pRenderData[i].m_nLightmapPage = materialSortInfoArray[ nSortID ].lightmapPageID;
  732. }
  733. return;
  734. }
  735. // Fullbright case. Bump works for unbumped surfaces too
  736. for ( int i = 0; i < nCount; ++i )
  737. {
  738. pRenderData[i].m_nLightmapPage = MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP;
  739. }
  740. }
  741. //-----------------------------------------------------------------------------
  742. // Computes the # of indices in an instance group
  743. //-----------------------------------------------------------------------------
  744. int CBrushBatchRender::ComputeInstanceGroups( IMatRenderContext *pRenderContext, int nCount, BrushBatchRenderData_t *pRenderData, CUtlVectorFixedGrowable< BrushInstanceGroup_t, 512 > &instanceGroups )
  745. {
  746. int nMaxIndices = pRenderContext->GetMaxIndicesToRender();
  747. int nMaxInstanceCount = 0;
  748. IMaterial *pLastMaterial = NULL;
  749. IMaterial *pLastActualMaterial = NULL;
  750. BrushBatchRenderData_t *pFirstInstance = NULL;
  751. int nInstanceCount = 0;
  752. int nIndexCount = 0;
  753. for ( int i = 0; i < nCount; i++ )
  754. {
  755. BrushBatchRenderData_t &renderData = pRenderData[i];
  756. brushrenderbatch_t &batch = renderData.m_pBrushRender->pBatches[ renderData.m_nBatchIndex ];
  757. int nNextIndexCount = nIndexCount + batch.indexCount;
  758. // Fire it away if the material changes or we overflow index count
  759. if ( ( pLastMaterial != batch.pMaterial ) || ( pLastMaterial != pLastActualMaterial ) || ( nNextIndexCount > nMaxIndices ) )
  760. {
  761. if ( nInstanceCount > 0 )
  762. {
  763. int nIndex = instanceGroups.AddToTail();
  764. instanceGroups[nIndex].m_pRenderData = pFirstInstance;
  765. instanceGroups[nIndex].m_nCount = nInstanceCount;
  766. instanceGroups[nIndex].m_nIndexCount = nIndexCount;
  767. instanceGroups[nIndex].m_pMaterial = pLastMaterial;
  768. instanceGroups[nIndex].m_pActualMaterial = pLastActualMaterial;
  769. if ( nInstanceCount > nMaxInstanceCount )
  770. {
  771. nMaxInstanceCount = nInstanceCount;
  772. }
  773. }
  774. nInstanceCount = 0;
  775. pFirstInstance = &renderData;
  776. nIndexCount = batch.indexCount;
  777. pLastMaterial = renderData.m_pMaterial;
  778. // This is necessary for shadow depth rendering. We need to re-bind
  779. // for every alpha tested material
  780. pLastActualMaterial = renderData.m_nIsAlphaTested ? batch.pMaterial : pLastMaterial;
  781. }
  782. else
  783. {
  784. nIndexCount = nNextIndexCount;
  785. }
  786. ++nInstanceCount;
  787. }
  788. if ( nInstanceCount > 0 )
  789. {
  790. int nIndex = instanceGroups.AddToTail();
  791. instanceGroups[nIndex].m_pRenderData = pFirstInstance;
  792. instanceGroups[nIndex].m_nCount = nInstanceCount;
  793. instanceGroups[nIndex].m_nIndexCount = nIndexCount;
  794. instanceGroups[nIndex].m_pMaterial = pLastMaterial;
  795. instanceGroups[nIndex].m_pActualMaterial = pLastActualMaterial;
  796. if ( nInstanceCount > nMaxInstanceCount )
  797. {
  798. nMaxInstanceCount = nInstanceCount;
  799. }
  800. }
  801. return nMaxInstanceCount;
  802. }
  803. //-----------------------------------------------------------------------------
  804. // Draws an opaque (parts of a) brush model
  805. //-----------------------------------------------------------------------------
  806. bool CBrushBatchRender::DrawSortedBatchList( IMatRenderContext* pRenderContext, int nCount, BrushInstanceGroup_t *pInstanceGroup, int nMaxInstanceCount )
  807. {
  808. VPROF( "DrawSortedBatchList" );
  809. PIXEVENT( pRenderContext, "DrawSortedBatchList()" );
  810. // Needed to allow the system to detect which samplers are bound to lightmap textures
  811. pRenderContext->BindLightmapPage( 0 );
  812. MeshInstanceData_t *pInstance = (MeshInstanceData_t*)stackalloc( nMaxInstanceCount * sizeof(MeshInstanceData_t) );
  813. bool bHasPaintedSurfaces = false;
  814. for ( int i = 0; i < nCount; i++ )
  815. {
  816. BrushInstanceGroup_t &group = pInstanceGroup[i];
  817. pRenderContext->Bind( group.m_pMaterial, NULL );
  818. // Only writing indices
  819. // FIXME: Can we make this a static index buffer?
  820. IIndexBuffer *pBuildIndexBuffer = pRenderContext->GetDynamicIndexBuffer();
  821. CIndexBuilder indexBuilder( pBuildIndexBuffer, MATERIAL_INDEX_FORMAT_16BIT );
  822. indexBuilder.Lock( group.m_nIndexCount, 0 );
  823. int nIndexOffset = indexBuilder.Offset() / sizeof(uint16);
  824. group.m_nHasPaintedSurfaces = false;
  825. for ( int j = 0; j < group.m_nCount; ++j )
  826. {
  827. BrushBatchRenderData_t &renderData = group.m_pRenderData[j];
  828. const brushrenderbatch_t &batch = renderData.m_pBrushRender->pBatches[ renderData.m_nBatchIndex ];
  829. renderData.m_nHasPaintedSurfaces = false;
  830. const model_t *pModel = renderData.m_pInstanceData->m_pBrushModel;
  831. SurfaceHandle_t firstSurfID = SurfaceHandleFromIndex( pModel->brush.firstmodelsurface, pModel->brush.pShared );
  832. for ( int k = 0; k < batch.surfaceCount; k++ )
  833. {
  834. const brushrendersurface_t &surface = renderData.m_pBrushRender->pSurfaces[batch.firstSurface + k];
  835. SurfaceHandle_t surfID = firstSurfID + surface.surfaceIndex;
  836. Assert( !(MSurf_Flags( surfID ) & SURFDRAW_NODRAW) );
  837. BuildIndicesForSurface( indexBuilder, surfID );
  838. if ( MSurf_Flags( surfID ) & SURFDRAW_PAINTED )
  839. {
  840. group.m_nHasPaintedSurfaces = true;
  841. renderData.m_nHasPaintedSurfaces = true;
  842. bHasPaintedSurfaces = true;
  843. }
  844. }
  845. MeshInstanceData_t &instance = pInstance[ j ];
  846. instance.m_pEnvCubemap = NULL;
  847. instance.m_pPoseToWorld = renderData.m_pInstanceData->m_pBrushToWorld;
  848. instance.m_pLightingState = NULL;
  849. instance.m_nBoneCount = 1;
  850. instance.m_pBoneRemap = NULL;
  851. instance.m_nIndexOffset = nIndexOffset;
  852. instance.m_nIndexCount = batch.indexCount;
  853. instance.m_nPrimType = MATERIAL_TRIANGLES;
  854. instance.m_pColorBuffer = NULL;
  855. instance.m_nColorVertexOffsetInBytes = 0;
  856. instance.m_pStencilState = renderData.m_pInstanceData->m_pStencilState;
  857. instance.m_pVertexBuffer = g_WorldStaticMeshes[ batch.sortID ];
  858. instance.m_pIndexBuffer = pBuildIndexBuffer;
  859. instance.m_nVertexOffsetInBytes = 0;
  860. instance.m_DiffuseModulation.Init( 1.0f, 1.0f, 1.0f, 1.0f );
  861. instance.m_nLightmapPageId = renderData.m_nLightmapPage;
  862. instance.m_bColorBufferHasIndirectLightingOnly = false;
  863. nIndexOffset += batch.indexCount;
  864. }
  865. indexBuilder.End( );
  866. pRenderContext->DrawInstances( group.m_nCount, pInstance );
  867. }
  868. return bHasPaintedSurfaces;
  869. }
  870. void CBrushBatchRender::DrawPaintForBatches( IMatRenderContext* pRenderContext, int nCount, const BrushInstanceGroup_t *pInstanceGroup, int nMaxInstanceCount )
  871. {
  872. MeshInstanceData_t *pInstance = (MeshInstanceData_t*)stackalloc( nMaxInstanceCount * sizeof(MeshInstanceData_t) );
  873. pRenderContext->SetRenderingPaint( true );
  874. PIXEVENT( pRenderContext, "Paint" );
  875. for ( int i = 0; i < nCount; i++ )
  876. {
  877. const BrushInstanceGroup_t &group = pInstanceGroup[i];
  878. if ( !group.m_nHasPaintedSurfaces )
  879. continue;
  880. pRenderContext->Bind( group.m_pMaterial, NULL );
  881. // Only writing indices, we're potentially allocating too many, but that's ok.
  882. // Unused ones will be freed up
  883. // FIXME: Can we make this a static index buffer?
  884. IIndexBuffer *pBuildIndexBuffer = pRenderContext->GetDynamicIndexBuffer();
  885. CIndexBuilder indexBuilder( pBuildIndexBuffer, MATERIAL_INDEX_FORMAT_16BIT );
  886. indexBuilder.Lock( group.m_nIndexCount, 0 );
  887. int nIndexOffset = indexBuilder.Offset() / sizeof(uint16);
  888. int nGroupCount = 0;
  889. for ( int j = 0; j < group.m_nCount; ++j )
  890. {
  891. const BrushBatchRenderData_t &renderData = group.m_pRenderData[j];
  892. if ( !renderData.m_nHasPaintedSurfaces )
  893. continue;
  894. const brushrenderbatch_t &batch = renderData.m_pBrushRender->pBatches[ renderData.m_nBatchIndex ];
  895. const model_t *pModel = renderData.m_pInstanceData->m_pBrushModel;
  896. SurfaceHandle_t firstSurfID = SurfaceHandleFromIndex( pModel->brush.firstmodelsurface, pModel->brush.pShared );
  897. int nBatchIndexCount = 0;
  898. for ( int k = 0; k < batch.surfaceCount; k++ )
  899. {
  900. const brushrendersurface_t &surface = renderData.m_pBrushRender->pSurfaces[batch.firstSurface + k];
  901. SurfaceHandle_t surfID = firstSurfID + surface.surfaceIndex;
  902. if ( ( MSurf_Flags( surfID ) & SURFDRAW_PAINTED ) == 0 )
  903. continue;
  904. int nTriCount = BuildIndicesForSurface( indexBuilder, surfID );
  905. nBatchIndexCount += nTriCount * 3;
  906. }
  907. MeshInstanceData_t &instance = pInstance[ nGroupCount ];
  908. instance.m_pEnvCubemap = NULL;
  909. instance.m_pPoseToWorld = renderData.m_pInstanceData->m_pBrushToWorld;
  910. instance.m_pLightingState = NULL;
  911. instance.m_nBoneCount = 1;
  912. instance.m_pBoneRemap = NULL;
  913. instance.m_nIndexOffset = nIndexOffset;
  914. instance.m_nIndexCount = nBatchIndexCount;
  915. instance.m_nPrimType = MATERIAL_TRIANGLES;
  916. instance.m_pColorBuffer = NULL;
  917. instance.m_nColorVertexOffsetInBytes = 0;
  918. instance.m_pStencilState = renderData.m_pInstanceData->m_pStencilState;
  919. instance.m_pVertexBuffer = g_WorldStaticMeshes[ batch.sortID ];
  920. instance.m_pIndexBuffer = pBuildIndexBuffer;
  921. instance.m_nVertexOffsetInBytes = 0;
  922. instance.m_DiffuseModulation.Init( 1.0f, 1.0f, 1.0f, 1.0f );
  923. instance.m_nLightmapPageId = renderData.m_nLightmapPage;
  924. instance.m_bColorBufferHasIndirectLightingOnly = false;
  925. nIndexOffset += nBatchIndexCount;
  926. ++nGroupCount;
  927. }
  928. indexBuilder.End( );
  929. pRenderContext->DrawInstances( nGroupCount, pInstance );
  930. }
  931. pRenderContext->SetRenderingPaint( false );
  932. }
  933. // Draw decals
  934. void CBrushBatchRender::DrawDecalsForBatches( IMatRenderContext *pRenderContext,
  935. int nCount, const BrushArrayInstanceData_t *pInstanceData, brushrender_t **ppBrushRender )
  936. {
  937. // FIXME: This could be better optimized by rendering across instances
  938. // but that's a deeper change: we'd need to have per-instance transforms
  939. // for each decal + shadow
  940. for ( int i = 0; i < nCount; ++i )
  941. {
  942. // Clear out the render list of decals
  943. DecalSurfacesInit( true );
  944. // Clear out the render lists of shadows
  945. g_pShadowMgr->ClearShadowRenderList( );
  946. const BrushArrayInstanceData_t &instance = pInstanceData[i];
  947. const brushrender_t *pRender = ppBrushRender[i];
  948. if ( !pRender )
  949. continue;
  950. SurfaceHandle_t firstSurfID = SurfaceHandleFromIndex( instance.m_pBrushModel->brush.firstmodelsurface, instance.m_pBrushModel->brush.pShared );
  951. bool bEncounteredDecals = false;
  952. for ( int s = 0; s < pRender->surfaceCount; ++s )
  953. {
  954. const brushrendersurface_t &surface = pRender->pSurfaces[s];
  955. SurfaceHandle_t surfID = firstSurfID + surface.surfaceIndex;
  956. if ( SurfaceHasDecals( surfID ) )
  957. {
  958. bEncounteredDecals = true;
  959. DecalSurfaceAdd( surfID, BRUSHMODEL_DECAL_SORT_GROUP );
  960. }
  961. // Add overlay fragments to list.
  962. // FIXME: A little code support is necessary to get overlays working on brush models
  963. // OverlayMgr()->AddFragmentListToRenderList( MSurf_OverlayFragmentList( surfID ), false );
  964. // Add render-to-texture shadows too....
  965. ShadowDecalHandle_t decalHandle = MSurf_ShadowDecals( surfID );
  966. if ( decalHandle != SHADOW_DECAL_HANDLE_INVALID )
  967. {
  968. bEncounteredDecals = true;
  969. g_pShadowMgr->AddShadowsOnSurfaceToRenderList( decalHandle );
  970. }
  971. }
  972. if ( bEncounteredDecals )
  973. {
  974. CBrushModelTransform pushTransform( *instance.m_pBrushToWorld, pRenderContext );
  975. // Draw all shadows on the brush
  976. g_pShadowMgr->RenderProjectedTextures( pRenderContext );
  977. DecalSurfaceDraw( pRenderContext, BRUSHMODEL_DECAL_SORT_GROUP, instance.m_DiffuseModulation.w );
  978. // draw the flashlight lighting for the decals on the brush.
  979. g_pShadowMgr->DrawFlashlightDecals( pRenderContext, BRUSHMODEL_DECAL_SORT_GROUP, false, instance.m_DiffuseModulation.w );
  980. // Retire decals on opaque brushmodel surfaces
  981. R_DecalFlushDestroyList();
  982. }
  983. }
  984. }
  985. void CBrushBatchRender::DrawArrayDebugInformation( IMatRenderContext *pRenderContext, int nCount, const BrushBatchRenderData_t *pRenderData )
  986. {
  987. if ( !g_ShaderDebug.anydebug )
  988. return;
  989. const Vector &vecViewOrigin = g_EngineRenderer->ViewOrigin();
  990. for ( int r = 0; r < nCount; ++r )
  991. {
  992. const BrushBatchRenderData_t &renderData = pRenderData[r];
  993. const brushrenderbatch_t &batch = renderData.m_pBrushRender->pBatches[ renderData.m_nBatchIndex ];
  994. const model_t *pModel = renderData.m_pInstanceData->m_pBrushModel;
  995. SurfaceHandle_t firstSurfID = SurfaceHandleFromIndex( pModel->brush.firstmodelsurface, pModel->brush.pShared );
  996. Vector vecModelSpaceViewOrigin;
  997. VectorITransform( vecViewOrigin, *renderData.m_pInstanceData->m_pBrushToWorld, vecModelSpaceViewOrigin );
  998. CUtlVectorFixedGrowable< msurface2_t *, 512 > surfaceList;
  999. for ( int k = 0; k < batch.surfaceCount; k++ )
  1000. {
  1001. brushrendersurface_t &surface = renderData.m_pBrushRender->pSurfaces[batch.firstSurface + k];
  1002. SurfaceHandle_t surfID = firstSurfID + surface.surfaceIndex;
  1003. if ( MSurf_Flags(surfID) & SURFDRAW_TRANS )
  1004. continue;
  1005. if ( ( MSurf_Flags( surfID ) & SURFDRAW_NOCULL) == 0 )
  1006. {
  1007. // Do a full backface cull here; we're not culling elsewhere in the pipeline
  1008. // Yes, it's expensive, but this is a debug mode, so who cares?
  1009. cplane_t *pSurfacePlane = renderData.m_pBrushRender->pPlanes[surface.planeIndex];
  1010. float flDot = DotProduct( vecModelSpaceViewOrigin, pSurfacePlane->normal ) - pSurfacePlane->dist;
  1011. bool bIsBackfacing = ( flDot < BACKFACE_EPSILON ) ? true : false;
  1012. if ( bIsBackfacing != false )
  1013. continue;
  1014. }
  1015. surfaceList.AddToTail( surfID );
  1016. }
  1017. // now draw debug for each drawn surface
  1018. DrawDebugInformation( pRenderContext, *renderData.m_pInstanceData->m_pBrushToWorld, surfaceList.Base(), surfaceList.Count() );
  1019. }
  1020. }
  1021. //-----------------------------------------------------------------------------
  1022. // Main entry point for rendering an array of brush models
  1023. //-----------------------------------------------------------------------------
  1024. void CBrushBatchRender::DrawBrushModelArray( IMatRenderContext* pRenderContext, int nCount,
  1025. const BrushArrayInstanceData_t *pInstanceData )
  1026. {
  1027. brushrender_t **ppBrushRender = (brushrender_t**)stackalloc( nCount * sizeof(brushrender_t*) );
  1028. CUtlVectorFixedGrowable< BrushBatchRenderData_t, 1024 > batchesToRender;
  1029. BuildBatchListToDraw( nCount, pInstanceData, batchesToRender, ppBrushRender );
  1030. int nBatchCount = batchesToRender.Count();
  1031. BrushBatchRenderData_t *pBatchData = batchesToRender.Base();
  1032. ComputeLightmapPages( nBatchCount, pBatchData );
  1033. std::make_heap( pBatchData, pBatchData + nBatchCount, BatchSortLessFunc );
  1034. std::sort_heap( pBatchData, pBatchData + nBatchCount, BatchSortLessFunc );
  1035. CUtlVectorFixedGrowable< BrushInstanceGroup_t, 512 > instanceGroups;
  1036. int nMaxInstanceCount = ComputeInstanceGroups( pRenderContext, nBatchCount, pBatchData, instanceGroups );
  1037. bool bHasPaintedSurfaces = DrawSortedBatchList( pRenderContext, instanceGroups.Count(), instanceGroups.Base(), nMaxInstanceCount );
  1038. if ( bHasPaintedSurfaces )
  1039. {
  1040. DrawPaintForBatches( pRenderContext, instanceGroups.Count(), instanceGroups.Base(), nMaxInstanceCount );
  1041. }
  1042. DrawDecalsForBatches( pRenderContext, nCount, pInstanceData, ppBrushRender );
  1043. DrawArrayDebugInformation( pRenderContext, nBatchCount, pBatchData );
  1044. }
  1045. //-----------------------------------------------------------------------------
  1046. // Builds the lists of shadow batches to draw
  1047. //-----------------------------------------------------------------------------
  1048. void CBrushBatchRender::BuildShadowBatchListToDraw( int nCount, const BrushArrayInstanceData_t *pInstanceData,
  1049. CUtlVectorFixedGrowable< BrushBatchRenderData_t, 1024 > &batchesToRender, int nModelTypeFlags )
  1050. {
  1051. for ( int i = 0; i < nCount; ++i )
  1052. {
  1053. const BrushArrayInstanceData_t &instance = pInstanceData[i];
  1054. brushrender_t *pRender = g_BrushBatchRenderer.FindOrCreateRenderBatch( const_cast< model_t* >( instance.m_pBrushModel ) );
  1055. if ( !pRender )
  1056. continue;
  1057. for ( int m = 0; m < pRender->meshCount; ++m )
  1058. {
  1059. brushrendermesh_t &mesh = pRender->pMeshes[m];
  1060. int nBatchIndex = mesh.firstBatch;
  1061. for ( int j = 0; j < mesh.batchCount; ++j, ++nBatchIndex )
  1062. {
  1063. // Select proper override material
  1064. const brushrenderbatch_t &renderBatch = pRender->pBatches[ nBatchIndex ];
  1065. int nAlphaTest = (int)renderBatch.pMaterial->IsAlphaTested();
  1066. int nNoCull = (int)renderBatch.pMaterial->IsTwoSided();
  1067. IMaterial *pDepthWriteMaterial;
  1068. if ( nModelTypeFlags & STUDIO_SSAODEPTHTEXTURE )
  1069. {
  1070. pDepthWriteMaterial = g_pMaterialSSAODepthWrite[ nAlphaTest ][ nNoCull ];
  1071. }
  1072. else
  1073. {
  1074. pDepthWriteMaterial = g_pMaterialDepthWrite[ nAlphaTest ][ nNoCull ];
  1075. }
  1076. int nIndex = batchesToRender.AddToTail();
  1077. BrushBatchRenderData_t &batch = batchesToRender[nIndex];
  1078. batch.m_pInstanceData = &instance;
  1079. batch.m_pBrushRender = pRender;
  1080. batch.m_nBatchIndex = nBatchIndex;
  1081. batch.m_nIsAlphaTested = nAlphaTest;
  1082. batch.m_pMaterial = pDepthWriteMaterial;
  1083. }
  1084. }
  1085. }
  1086. }
  1087. //-----------------------------------------------------------------------------
  1088. // Sorts shadows
  1089. //-----------------------------------------------------------------------------
  1090. inline bool __cdecl CBrushBatchRender::ShadowSortLessFunc( const BrushBatchRenderData_t &left, const BrushBatchRenderData_t &right )
  1091. {
  1092. if ( left.m_pMaterial != right.m_pMaterial )
  1093. return left.m_pMaterial < right.m_pMaterial;
  1094. if ( left.m_pInstanceData->m_pBrushToWorld != right.m_pInstanceData->m_pBrushToWorld )
  1095. return left.m_pInstanceData->m_pBrushToWorld < right.m_pInstanceData->m_pBrushToWorld;
  1096. return false;
  1097. }
  1098. //-----------------------------------------------------------------------------
  1099. // Draws an opaque (parts of a) brush model
  1100. //-----------------------------------------------------------------------------
  1101. void CBrushBatchRender::DrawShadowBatchList( IMatRenderContext* pRenderContext, int nCount, BrushInstanceGroup_t *pInstanceGroup, int nMaxInstanceCount )
  1102. {
  1103. VPROF( "DrawShadowBatchList" );
  1104. PIXEVENT( pRenderContext, "DrawShadowBatchList()" );
  1105. pRenderContext->BindLightmapPage( MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP );
  1106. MeshInstanceData_t *pInstance = (MeshInstanceData_t*)stackalloc( nMaxInstanceCount * sizeof(MeshInstanceData_t) );
  1107. for ( int i = 0; i < nCount; i++ )
  1108. {
  1109. BrushInstanceGroup_t &group = pInstanceGroup[i];
  1110. if ( group.m_pRenderData->m_nIsAlphaTested )
  1111. {
  1112. static unsigned int originalTextureVarCache = 0;
  1113. IMaterialVar *pOriginalTextureVar = group.m_pActualMaterial->FindVarFast( "$basetexture", &originalTextureVarCache );
  1114. static unsigned int originalTextureFrameVarCache = 0;
  1115. IMaterialVar *pOriginalTextureFrameVar = group.m_pActualMaterial->FindVarFast( "$frame", &originalTextureFrameVarCache );
  1116. static unsigned int originalAlphaRefCache = 0;
  1117. IMaterialVar *pOriginalAlphaRefVar = group.m_pActualMaterial->FindVarFast( "$AlphaTestReference", &originalAlphaRefCache );
  1118. static unsigned int textureVarCache = 0;
  1119. IMaterialVar *pTextureVar = group.m_pMaterial->FindVarFast( "$basetexture", &textureVarCache );
  1120. static unsigned int textureFrameVarCache = 0;
  1121. IMaterialVar *pTextureFrameVar = group.m_pMaterial->FindVarFast( "$frame", &textureFrameVarCache );
  1122. static unsigned int alphaRefCache = 0;
  1123. IMaterialVar *pAlphaRefVar = group.m_pMaterial->FindVarFast( "$AlphaTestReference", &alphaRefCache );
  1124. if( pTextureVar && pOriginalTextureVar )
  1125. {
  1126. pTextureVar->SetTextureValue( pOriginalTextureVar->GetTextureValue() );
  1127. }
  1128. if( pTextureFrameVar && pOriginalTextureFrameVar )
  1129. {
  1130. pTextureFrameVar->SetIntValue( pOriginalTextureFrameVar->GetIntValue() );
  1131. }
  1132. if( pAlphaRefVar && pOriginalAlphaRefVar )
  1133. {
  1134. pAlphaRefVar->SetFloatValue( pOriginalAlphaRefVar->GetFloatValue() );
  1135. }
  1136. }
  1137. pRenderContext->Bind( group.m_pMaterial, NULL );
  1138. // Only writing indices
  1139. // FIXME: Can we make this a static index buffer?
  1140. IIndexBuffer *pBuildIndexBuffer = pRenderContext->GetDynamicIndexBuffer();
  1141. CIndexBuilder indexBuilder( pBuildIndexBuffer, MATERIAL_INDEX_FORMAT_16BIT );
  1142. indexBuilder.Lock( group.m_nIndexCount, 0 );
  1143. int nIndexOffset = indexBuilder.Offset() / sizeof(uint16);
  1144. for ( int j = 0; j < group.m_nCount; ++j )
  1145. {
  1146. BrushBatchRenderData_t &renderData = group.m_pRenderData[j];
  1147. const brushrenderbatch_t &batch = renderData.m_pBrushRender->pBatches[ renderData.m_nBatchIndex ];
  1148. const model_t *pModel = renderData.m_pInstanceData->m_pBrushModel;
  1149. SurfaceHandle_t firstSurfID = SurfaceHandleFromIndex( pModel->brush.firstmodelsurface, pModel->brush.pShared );
  1150. for ( int k = 0; k < batch.surfaceCount; k++ )
  1151. {
  1152. const brushrendersurface_t &surface = renderData.m_pBrushRender->pSurfaces[batch.firstSurface + k];
  1153. SurfaceHandle_t surfID = firstSurfID + surface.surfaceIndex;
  1154. Assert( !(MSurf_Flags( surfID ) & SURFDRAW_NODRAW) );
  1155. BuildIndicesForSurface( indexBuilder, surfID );
  1156. }
  1157. MeshInstanceData_t &instance = pInstance[ j ];
  1158. instance.m_pEnvCubemap = NULL;
  1159. instance.m_pPoseToWorld = renderData.m_pInstanceData->m_pBrushToWorld;
  1160. instance.m_pLightingState = NULL;
  1161. instance.m_nBoneCount = 1;
  1162. instance.m_pBoneRemap = NULL;
  1163. instance.m_nIndexOffset = nIndexOffset;
  1164. instance.m_nIndexCount = batch.indexCount;
  1165. instance.m_nPrimType = MATERIAL_TRIANGLES;
  1166. instance.m_pColorBuffer = NULL;
  1167. instance.m_nColorVertexOffsetInBytes = 0;
  1168. instance.m_pStencilState = renderData.m_pInstanceData->m_pStencilState;
  1169. instance.m_pVertexBuffer = g_WorldStaticMeshes[ batch.sortID ];
  1170. instance.m_pIndexBuffer = pBuildIndexBuffer;
  1171. instance.m_nVertexOffsetInBytes = 0;
  1172. instance.m_DiffuseModulation.Init( 1.0f, 1.0f, 1.0f, 1.0f );
  1173. instance.m_nLightmapPageId = MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP;
  1174. instance.m_bColorBufferHasIndirectLightingOnly = false;
  1175. nIndexOffset += batch.indexCount;
  1176. }
  1177. indexBuilder.End( );
  1178. pRenderContext->DrawInstances( group.m_nCount, pInstance );
  1179. }
  1180. }
  1181. //-----------------------------------------------------------------------------
  1182. // Main entry point for rendering an array of brush model shadows
  1183. //-----------------------------------------------------------------------------
  1184. void CBrushBatchRender::DrawBrushModelShadowArray( IMatRenderContext* pRenderContext, int nCount,
  1185. const BrushArrayInstanceData_t *pInstanceData, int nModelTypeFlags )
  1186. {
  1187. CUtlVectorFixedGrowable< BrushBatchRenderData_t, 1024 > batchesToRender;
  1188. BuildShadowBatchListToDraw( nCount, pInstanceData, batchesToRender, nModelTypeFlags );
  1189. int nBatchCount = batchesToRender.Count();
  1190. BrushBatchRenderData_t *pBatchData = batchesToRender.Base();
  1191. std::make_heap( pBatchData, pBatchData + nBatchCount, ShadowSortLessFunc );
  1192. std::sort_heap( pBatchData, pBatchData + nBatchCount, ShadowSortLessFunc );
  1193. CUtlVectorFixedGrowable< BrushInstanceGroup_t, 512 > instanceGroups;
  1194. int nMaxInstanceCount = ComputeInstanceGroups( pRenderContext, nBatchCount, pBatchData, instanceGroups );
  1195. DrawShadowBatchList( pRenderContext, instanceGroups.Count(), instanceGroups.Base(), nMaxInstanceCount );
  1196. }