Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5378 lines
167 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #include "render_pch.h"
  9. #include "client.h"
  10. #include "gl_model_private.h"
  11. #include "gl_water.h"
  12. #include "gl_cvars.h"
  13. #include "zone.h"
  14. #include "decal.h"
  15. #include "decal_private.h"
  16. #include "gl_lightmap.h"
  17. #include "r_local.h"
  18. #include "gl_matsysiface.h"
  19. #include "gl_rsurf.h"
  20. #include "materialsystem/imesh.h"
  21. #include "materialsystem/ivballoctracker.h"
  22. #include "tier2/tier2.h"
  23. #include "collisionutils.h"
  24. #include "cdll_int.h"
  25. #include "utllinkedlist.h"
  26. #include "r_areaportal.h"
  27. #include "bsptreedata.h"
  28. #include "cmodel_private.h"
  29. #include "tier0/dbg.h"
  30. #include "crtmemdebug.h"
  31. #include "iclientrenderable.h"
  32. #include "icliententitylist.h"
  33. #include "icliententity.h"
  34. #include "gl_rmain.h"
  35. #include "tier0/vprof.h"
  36. #include "bitvec.h"
  37. #include "debugoverlay.h"
  38. #include "host.h"
  39. #include "materialsystem/imaterialsystemhardwareconfig.h"
  40. #include "cl_main.h"
  41. #include "cmodel_engine.h"
  42. #include "r_decal.h"
  43. #include "materialsystem/materialsystem_config.h"
  44. #include "materialsystem/imaterialproxy.h"
  45. #include "materialsystem/imaterialvar.h"
  46. #include "coordsize.h"
  47. #include "mempool.h"
  48. #ifndef SWDS
  49. #include "Overlay.h"
  50. #endif
  51. // memdbgon must be the last include file in a .cpp file!!!
  52. #include "tier0/memdbgon.h"
  53. #define BACKFACE_EPSILON -0.01f
  54. #define BRUSHMODEL_DECAL_SORT_GROUP MAX_MAT_SORT_GROUPS
  55. const int MAX_VERTEX_FORMAT_CHANGES = 128;
  56. int g_MaxLeavesVisible = 512;
  57. //-----------------------------------------------------------------------------
  58. // forward declarations
  59. //-----------------------------------------------------------------------------
  60. class IClientEntity;
  61. // interface to shader drawing
  62. void Shader_BrushBegin( model_t *model, IClientEntity *baseentity = NULL );
  63. void Shader_BrushSurface( SurfaceHandle_t surfID, model_t *model, IClientEntity *baseentity = NULL );
  64. void Shader_BrushEnd( IMatRenderContext *pRenderContext, VMatrix const* brushToWorld, model_t *model, bool bShadowDepth, IClientEntity *baseentity = NULL );
  65. #ifdef NEWMESH
  66. void BuildMSurfaceVertexArrays( worldbrushdata_t *pBrushData, SurfaceHandle_t surfID, float overbright, CVertexBufferBuilder &builder );
  67. #else
  68. void BuildMSurfaceVertexArrays( worldbrushdata_t *pBrushData, SurfaceHandle_t surfID, float overbright, CMeshBuilder &builder );
  69. #endif
  70. //-----------------------------------------------------------------------------
  71. // Information about the fog volumes for this pass of rendering
  72. //-----------------------------------------------------------------------------
  73. struct FogState_t
  74. {
  75. MaterialFogMode_t m_FogMode;
  76. float m_FogStart;
  77. float m_FogEnd;
  78. float m_FogColor[3];
  79. bool m_FogEnabled;
  80. };
  81. struct FogVolumeInfo_t : public FogState_t
  82. {
  83. bool m_InFogVolume;
  84. float m_FogSurfaceZ;
  85. float m_FogMinZ;
  86. int m_FogVolumeID;
  87. };
  88. //-----------------------------------------------------------------------------
  89. // Cached convars...
  90. //-----------------------------------------------------------------------------
  91. struct CachedConvars_t
  92. {
  93. bool m_bDrawWorld;
  94. int m_nDrawLeaf;
  95. bool m_bDrawFuncDetail;
  96. };
  97. static CachedConvars_t s_ShaderConvars;
  98. // AR - moved so SWDS can access these vars
  99. Frustum_t g_Frustum;
  100. //-----------------------------------------------------------------------------
  101. // Convars
  102. //-----------------------------------------------------------------------------
  103. static ConVar r_drawtranslucentworld( "r_drawtranslucentworld", "1", FCVAR_CHEAT );
  104. static ConVar mat_forcedynamic( "mat_forcedynamic", "0", FCVAR_CHEAT );
  105. static ConVar r_drawleaf( "r_drawleaf", "-1", FCVAR_CHEAT, "Draw the specified leaf." );
  106. static ConVar r_drawworld( "r_drawworld", "1", FCVAR_CHEAT, "Render the world." );
  107. static ConVar r_drawfuncdetail( "r_drawfuncdetail", "1", FCVAR_CHEAT, "Render func_detail" );
  108. static ConVar fog_enable_water_fog( "fog_enable_water_fog", "1", FCVAR_CHEAT );
  109. static ConVar r_fastzreject( "r_fastzreject", "0", FCVAR_ALLOWED_IN_COMPETITIVE, "Activate/deactivates a fast z-setting algorithm to take advantage of hardware with fast z reject. Use -1 to default to hardware settings" );
  110. static ConVar r_fastzrejectdisp( "r_fastzrejectdisp", "0", 0, "Activates/deactivates fast z rejection on displacements (360 only). Only active when r_fastzreject is on." );
  111. //-----------------------------------------------------------------------------
  112. // Installs a client-side renderer for brush models
  113. //-----------------------------------------------------------------------------
  114. static IBrushRenderer* s_pBrushRenderOverride = 0;
  115. //-----------------------------------------------------------------------------
  116. // Make sure we don't render the same surfaces twice
  117. //-----------------------------------------------------------------------------
  118. int r_surfacevisframe = 0;
  119. #define r_surfacevisframe dont_use_r_surfacevisframe_here
  120. //-----------------------------------------------------------------------------
  121. // Fast z reject displacements?
  122. //-----------------------------------------------------------------------------
  123. static bool s_bFastZRejectDisplacements = false;
  124. //-----------------------------------------------------------------------------
  125. // Top view bounds
  126. //-----------------------------------------------------------------------------
  127. static bool r_drawtopview = false;
  128. static Vector2D s_OrthographicCenter;
  129. static Vector2D s_OrthographicHalfDiagonal;
  130. //-----------------------------------------------------------------------------
  131. //
  132. //-----------------------------------------------------------------------------
  133. typedef CVarBitVec CVisitedSurfs;
  134. //-----------------------------------------------------------------------------
  135. // Returns planes in brush models
  136. //-----------------------------------------------------------------------------
  137. int R_GetBrushModelPlaneCount( const model_t *model )
  138. {
  139. return model->brush.nummodelsurfaces;
  140. }
  141. const cplane_t &R_GetBrushModelPlane( const model_t *model, int nIndex, Vector *pOrigin )
  142. {
  143. SurfaceHandle_t surfID = SurfaceHandleFromIndex( model->brush.firstmodelsurface, model->brush.pShared );
  144. surfID += nIndex;
  145. Assert( !(MSurf_Flags( surfID ) & SURFDRAW_NODRAW) );
  146. if ( pOrigin )
  147. {
  148. int vertCount = MSurf_VertCount( surfID );
  149. if ( vertCount > 0 )
  150. {
  151. int nFirstVertex = model->brush.pShared->vertindices[MSurf_FirstVertIndex( surfID )];
  152. *pOrigin = model->brush.pShared->vertexes[nFirstVertex].position;
  153. }
  154. else
  155. {
  156. const cplane_t &plane = MSurf_Plane( surfID );
  157. VectorMultiply( plane.normal, plane.dist, *pOrigin );
  158. }
  159. }
  160. return MSurf_Plane( surfID );
  161. }
  162. //-----------------------------------------------------------------------------
  163. // Computes the centroid of a surface
  164. //-----------------------------------------------------------------------------
  165. void Surf_ComputeCentroid( SurfaceHandle_t surfID, Vector *pVecCentroid )
  166. {
  167. int nCount = MSurf_VertCount( surfID );
  168. int nFirstVertIndex = MSurf_FirstVertIndex( surfID );
  169. float flTotalArea = 0.0f;
  170. Vector vecNormal;
  171. pVecCentroid->Init(0,0,0);
  172. int vertIndex = host_state.worldbrush->vertindices[nFirstVertIndex];
  173. Vector vecApex = host_state.worldbrush->vertexes[vertIndex].position;
  174. for (int v = 1; v < nCount - 1; ++v )
  175. {
  176. vertIndex = host_state.worldbrush->vertindices[nFirstVertIndex+v];
  177. Vector v1 = host_state.worldbrush->vertexes[vertIndex].position;
  178. vertIndex = host_state.worldbrush->vertindices[nFirstVertIndex+v+1];
  179. Vector v2 = host_state.worldbrush->vertexes[vertIndex].position;
  180. CrossProduct( v2 - v1, v1 - vecApex, vecNormal );
  181. float flArea = vecNormal.Length();
  182. flTotalArea += flArea;
  183. *pVecCentroid += (vecApex + v1 + v2) * flArea / 3.0f;
  184. }
  185. if (flTotalArea)
  186. {
  187. *pVecCentroid /= flTotalArea;
  188. }
  189. }
  190. //-----------------------------------------------------------------------------
  191. // Converts sort infos to lightmap pages
  192. //-----------------------------------------------------------------------------
  193. int SortInfoToLightmapPage( int sortID )
  194. {
  195. return materialSortInfoArray[sortID].lightmapPageID;
  196. }
  197. #ifndef SWDS
  198. class CWorldRenderList : public CRefCounted1<IWorldRenderList>
  199. {
  200. public:
  201. CWorldRenderList()
  202. {
  203. }
  204. ~CWorldRenderList()
  205. {
  206. Purge();
  207. }
  208. static CWorldRenderList *FindOrCreateList( int nSurfaces )
  209. {
  210. CWorldRenderList *p = g_Pool.GetObject();
  211. if ( p->m_VisitedSurfs.GetNumBits() == 0 )
  212. {
  213. p->Init( nSurfaces );
  214. }
  215. else
  216. {
  217. p->AddRef();
  218. }
  219. AssertMsg( p->m_VisitedSurfs.GetNumBits() == nSurfaces, "World render list pool not cleared between maps" );
  220. return p;
  221. }
  222. static void PurgeAll()
  223. {
  224. CWorldRenderList *p;
  225. while ( ( p = g_Pool.GetObject( false ) ) != NULL )
  226. {
  227. p->Purge();
  228. delete p;
  229. }
  230. }
  231. virtual bool OnFinalRelease()
  232. {
  233. Reset();
  234. g_Pool.PutObject( this );
  235. return false;
  236. }
  237. void Init( int nSurfaces )
  238. {
  239. m_SortList.Init(materials->GetNumSortIDs(), 512);
  240. m_AlphaSortList.Init( g_MaxLeavesVisible, 64 );
  241. m_DispSortList.Init(materials->GetNumSortIDs(), 32);
  242. m_DispAlphaSortList.Init( g_MaxLeavesVisible, 32 );
  243. m_VisitedSurfs.Resize( nSurfaces );
  244. m_bSkyVisible = false;
  245. }
  246. void Purge()
  247. {
  248. g_MaxLeavesVisible = max(g_MaxLeavesVisible,m_VisibleLeaves.Count());
  249. m_VisibleLeaves.Purge();
  250. m_VisibleLeafFogVolumes.Purge();
  251. for ( int i = 0; i < MAX_MAT_SORT_GROUPS; i++ )
  252. {
  253. m_ShadowHandles[i].Purge();
  254. m_DlightSurfaces[i].Purge();
  255. }
  256. m_SortList.Shutdown();
  257. m_AlphaSortList.Shutdown();
  258. m_DispSortList.Shutdown();
  259. m_DispAlphaSortList.Shutdown();
  260. }
  261. void Reset()
  262. {
  263. g_MaxLeavesVisible = max(g_MaxLeavesVisible,m_VisibleLeaves.Count());
  264. m_SortList.Reset();
  265. m_AlphaSortList.Reset();
  266. m_DispSortList.Reset();
  267. m_DispAlphaSortList.Reset();
  268. m_bSkyVisible = false;
  269. for (int j = 0; j < MAX_MAT_SORT_GROUPS; ++j)
  270. {
  271. //Assert(pRenderList->m_ShadowHandles[j].Count() == 0 );
  272. m_ShadowHandles[j].RemoveAll();
  273. m_DlightSurfaces[j].RemoveAll();
  274. }
  275. // We haven't found any visible leafs this frame
  276. m_VisibleLeaves.RemoveAll();
  277. m_VisibleLeafFogVolumes.RemoveAll();
  278. m_VisitedSurfs.ClearAll();
  279. }
  280. CMSurfaceSortList m_SortList;
  281. CMSurfaceSortList m_DispSortList;
  282. CMSurfaceSortList m_AlphaSortList;
  283. CMSurfaceSortList m_DispAlphaSortList;
  284. //-------------------------------------------------------------------------
  285. // List of decals to render this frame (need an extra one for brush models)
  286. //-------------------------------------------------------------------------
  287. CUtlVector<ShadowDecalHandle_t> m_ShadowHandles[MAX_MAT_SORT_GROUPS];
  288. // list of surfaces with dynamic lightmaps
  289. CUtlVector<SurfaceHandle_t> m_DlightSurfaces[MAX_MAT_SORT_GROUPS];
  290. //-------------------------------------------------------------------------
  291. // Used to generate a list of the leaves visited, and in back-to-front order
  292. // for this frame of rendering
  293. //-------------------------------------------------------------------------
  294. CUtlVector<LeafIndex_t> m_VisibleLeaves;
  295. CUtlVector<LeafFogVolume_t> m_VisibleLeafFogVolumes;
  296. CVisitedSurfs m_VisitedSurfs;
  297. bool m_bSkyVisible;
  298. static CObjectPool<CWorldRenderList> g_Pool;
  299. };
  300. CObjectPool<CWorldRenderList> CWorldRenderList::g_Pool;
  301. IWorldRenderList *AllocWorldRenderList()
  302. {
  303. return CWorldRenderList::FindOrCreateList( host_state.worldbrush->numsurfaces );
  304. }
  305. FORCEINLINE bool VisitSurface( CVisitedSurfs &visitedSurfs, SurfaceHandle_t surfID )
  306. {
  307. return !visitedSurfs.TestAndSet( MSurf_Index( surfID ) );
  308. }
  309. FORCEINLINE void MarkSurfaceVisited( CVisitedSurfs &visitedSurfs, SurfaceHandle_t surfID )
  310. {
  311. visitedSurfs.Set( MSurf_Index( surfID ) );
  312. }
  313. FORCEINLINE bool VisitedSurface( CVisitedSurfs &visitedSurfs, SurfaceHandle_t surfID )
  314. {
  315. return visitedSurfs.IsBitSet( MSurf_Index( surfID ) );
  316. }
  317. FORCEINLINE bool VisitedSurface( CVisitedSurfs &visitedSurfs, int index )
  318. {
  319. return visitedSurfs.IsBitSet( index );
  320. }
  321. //-----------------------------------------------------------------------------
  322. // Activates top view
  323. //-----------------------------------------------------------------------------
  324. void R_DrawTopView( bool enable )
  325. {
  326. r_drawtopview = enable;
  327. }
  328. void R_TopViewBounds( Vector2D const& mins, Vector2D const& maxs )
  329. {
  330. Vector2DAdd( maxs, mins, s_OrthographicCenter );
  331. s_OrthographicCenter *= 0.5f;
  332. Vector2DSubtract( maxs, s_OrthographicCenter, s_OrthographicHalfDiagonal );
  333. }
  334. #define MOVE_DLIGHTS_TO_NEW_TEXTURE 0
  335. #if MOVE_DLIGHTS_TO_NEW_TEXTURE
  336. bool DlightSurfaceSetQueuingFlag(SurfaceHandle_t surfID)
  337. {
  338. if ( MSurf_Flags( surfID ) & SURFDRAW_HASLIGHTSYTLES )
  339. {
  340. msurfacelighting_t *pLighting = SurfaceLighting(surfID);
  341. for( int maps = 1; maps < MAXLIGHTMAPS && pLighting->m_nStyles[maps] != 255; maps++ )
  342. {
  343. if( d_lightstylenumframes[pLighting->m_nStyles[maps]] != 1 )
  344. {
  345. MSurf_Flags( surfID ) |= SURFDRAW_DLIGHTPASS;
  346. return true;
  347. }
  348. }
  349. return false;
  350. }
  351. MSurf_Flags( surfID ) |= SURFDRAW_DLIGHTPASS;
  352. return true;
  353. }
  354. #else
  355. bool DlightSurfaceSetQueuingFlag(SurfaceHandle_t surfID) { return false; }
  356. #endif
  357. //-----------------------------------------------------------------------------
  358. // Adds surfaces to list of things to render
  359. //-----------------------------------------------------------------------------
  360. void Shader_TranslucentWorldSurface( CWorldRenderList *pRenderList, SurfaceHandle_t surfID )
  361. {
  362. Assert( !SurfaceHasDispInfo( surfID ) && (pRenderList->m_VisibleLeaves.Count() > 0) );
  363. // Hook into the chain of translucent objects for this leaf
  364. int sortGroup = MSurf_SortGroup( surfID );
  365. pRenderList->m_AlphaSortList.AddSurfaceToTail( surfID, sortGroup, pRenderList->m_VisibleLeaves.Count()-1 );
  366. if ( MSurf_Flags( surfID ) & (SURFDRAW_HASLIGHTSYTLES|SURFDRAW_HASDLIGHT) )
  367. {
  368. pRenderList->m_DlightSurfaces[sortGroup].AddToTail( surfID );
  369. DlightSurfaceSetQueuingFlag(surfID);
  370. }
  371. }
  372. inline void Shader_WorldSurface( CWorldRenderList *pRenderList, SurfaceHandle_t surfID )
  373. {
  374. // Hook it into the list of surfaces to render with this material
  375. // Do it in a way that generates a front-to-back ordering for fast z reject
  376. Assert( !SurfaceHasDispInfo( surfID ) );
  377. // Each surface is in exactly one group
  378. int nSortGroup = MSurf_SortGroup( surfID );
  379. // Add decals on non-displacement surfaces
  380. if( SurfaceHasDecals( surfID ) )
  381. {
  382. DecalSurfaceAdd( surfID, nSortGroup );
  383. }
  384. int nMaterialSortID = MSurf_MaterialSortID( surfID );
  385. if ( MSurf_Flags( surfID ) & (SURFDRAW_HASLIGHTSYTLES|SURFDRAW_HASDLIGHT) )
  386. {
  387. pRenderList->m_DlightSurfaces[nSortGroup].AddToTail( surfID );
  388. if ( !DlightSurfaceSetQueuingFlag(surfID) )
  389. {
  390. pRenderList->m_SortList.AddSurfaceToTail( surfID, nSortGroup, nMaterialSortID );
  391. }
  392. }
  393. else
  394. {
  395. pRenderList->m_SortList.AddSurfaceToTail( surfID, nSortGroup, nMaterialSortID );
  396. }
  397. }
  398. // The NoCull flavor of this function optimizes for shadow depth map rendering
  399. // No decal work, dlights or material sorting, for example
  400. inline void Shader_WorldSurfaceNoCull( CWorldRenderList *pRenderList, SurfaceHandle_t surfID )
  401. {
  402. // Hook it into the list of surfaces to render with this material
  403. // Do it in a way that generates a front-to-back ordering for fast z reject
  404. Assert( !SurfaceHasDispInfo( surfID ) );
  405. // Each surface is in exactly one group
  406. int nSortGroup = MSurf_SortGroup( surfID );
  407. int nMaterialSortID = MSurf_MaterialSortID( surfID );
  408. pRenderList->m_SortList.AddSurfaceToTail( surfID, nSortGroup, nMaterialSortID );
  409. }
  410. //-----------------------------------------------------------------------------
  411. // Adds displacement surfaces to list of things to render
  412. //-----------------------------------------------------------------------------
  413. void Shader_TranslucentDisplacementSurface( CWorldRenderList *pRenderList, SurfaceHandle_t surfID )
  414. {
  415. Assert( SurfaceHasDispInfo( surfID ) && (pRenderList->m_VisibleLeaves.Count() > 0));
  416. // For translucent displacement surfaces, they can exist in many
  417. // leaves. We want to choose the leaf that's closest to the camera
  418. // to render it in. Thankfully, we're iterating the tree in front-to-back
  419. // order, so this is very simple.
  420. // NOTE: You might expect some problems here when displacements cross fog volume
  421. // planes. However, these problems go away (I hope!) because the first planes
  422. // that split a scene are the fog volume planes. That means that if we're
  423. // in a fog volume, the closest leaf that the displacement will be in will
  424. // also be in the fog volume. If we're not in a fog volume, the closest
  425. // leaf that the displacement will be in will not be a fog volume. That should
  426. // hopefully hide any discontinuities between fog state that occur when
  427. // rendering displacements that straddle fog volume boundaries.
  428. // Each surface is in exactly one group
  429. int sortGroup = MSurf_SortGroup( surfID );
  430. if ( MSurf_Flags( surfID ) & (SURFDRAW_HASLIGHTSYTLES|SURFDRAW_HASDLIGHT) )
  431. {
  432. pRenderList->m_DlightSurfaces[sortGroup].AddToTail( surfID );
  433. if ( !DlightSurfaceSetQueuingFlag(surfID) )
  434. {
  435. pRenderList->m_DispAlphaSortList.AddSurfaceToTail(surfID, sortGroup, pRenderList->m_VisibleLeaves.Count()-1);
  436. }
  437. }
  438. else
  439. {
  440. pRenderList->m_DispAlphaSortList.AddSurfaceToTail(surfID, sortGroup, pRenderList->m_VisibleLeaves.Count()-1);
  441. }
  442. }
  443. void Shader_DisplacementSurface( CWorldRenderList *pRenderList, SurfaceHandle_t surfID )
  444. {
  445. Assert( SurfaceHasDispInfo( surfID ) );
  446. // For opaque displacement surfaces, we're going to build a temporary list of
  447. // displacement surfaces in each material bucket, and then add those to
  448. // the actual displacement lists in a separate pass.
  449. // We do this to sort the displacement surfaces by material
  450. // Each surface is in exactly one group
  451. int nSortGroup = MSurf_SortGroup( surfID );
  452. int nMaterialSortID = MSurf_MaterialSortID( surfID );
  453. if ( MSurf_Flags( surfID ) & (SURFDRAW_HASLIGHTSYTLES|SURFDRAW_HASDLIGHT) )
  454. {
  455. pRenderList->m_DlightSurfaces[nSortGroup].AddToTail( surfID );
  456. if ( !DlightSurfaceSetQueuingFlag(surfID) )
  457. {
  458. pRenderList->m_DispSortList.AddSurfaceToTail( surfID, nSortGroup, nMaterialSortID );
  459. }
  460. }
  461. else
  462. {
  463. pRenderList->m_DispSortList.AddSurfaceToTail( surfID, nSortGroup, nMaterialSortID );
  464. }
  465. }
  466. //-----------------------------------------------------------------------------
  467. // Purpose: This draws a single surface using the dynamic mesh
  468. //-----------------------------------------------------------------------------
  469. void Shader_DrawSurfaceDynamic( IMatRenderContext *pRenderContext, SurfaceHandle_t surfID, bool bShadowDepth )
  470. {
  471. tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s %d", __FUNCTION__, surfID );
  472. if( !SurfaceHasPrims( surfID ) )
  473. {
  474. IMesh *pMesh = pRenderContext->GetDynamicMesh( );
  475. CMeshBuilder meshBuilder;
  476. meshBuilder.Begin( pMesh, MATERIAL_POLYGON, MSurf_VertCount( surfID ) );
  477. BuildMSurfaceVertexArrays( host_state.worldbrush, surfID, OVERBRIGHT, meshBuilder );
  478. meshBuilder.End();
  479. pMesh->Draw();
  480. return;
  481. }
  482. mprimitive_t *pPrim = &host_state.worldbrush->primitives[MSurf_FirstPrimID( surfID )];
  483. if ( pPrim->vertCount )
  484. {
  485. #ifdef DBGFLAG_ASSERT
  486. int primType = pPrim->type;
  487. #endif
  488. IMesh *pMesh = pRenderContext->GetDynamicMesh( false );
  489. CMeshBuilder meshBuilder;
  490. for( int i = 0; i < MSurf_NumPrims( surfID ); i++, pPrim++ )
  491. {
  492. // Can't have heterogeneous primitive lists
  493. Assert( primType == pPrim->type );
  494. switch( pPrim->type )
  495. {
  496. case PRIM_TRILIST:
  497. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, pPrim->vertCount, pPrim->indexCount );
  498. break;
  499. case PRIM_TRISTRIP:
  500. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, pPrim->vertCount, pPrim->indexCount );
  501. break;
  502. default:
  503. Assert( 0 );
  504. return;
  505. }
  506. Assert( pPrim->indexCount );
  507. BuildMSurfacePrimVerts( host_state.worldbrush, pPrim, meshBuilder, surfID );
  508. BuildMSurfacePrimIndices( host_state.worldbrush, pPrim, meshBuilder );
  509. meshBuilder.End();
  510. pMesh->Draw();
  511. }
  512. }
  513. else
  514. {
  515. // prims are just a tessellation
  516. IMesh *pMesh = pRenderContext->GetDynamicMesh( );
  517. CMeshBuilder meshBuilder;
  518. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, MSurf_VertCount( surfID ), pPrim->indexCount );
  519. BuildMSurfaceVertexArrays( host_state.worldbrush, surfID, OVERBRIGHT, meshBuilder );
  520. for ( int primIndex = 0; primIndex < pPrim->indexCount; primIndex++ )
  521. {
  522. meshBuilder.FastIndex( host_state.worldbrush->primindices[pPrim->firstIndex + primIndex] );
  523. }
  524. meshBuilder.End();
  525. pMesh->Draw();
  526. }
  527. }
  528. //-----------------------------------------------------------------------------
  529. // Purpose: This draws a single surface using its static mesh
  530. //-----------------------------------------------------------------------------
  531. /*
  532. // NOTE: Since a static vb/dynamic ib IMesh doesn't buffer, we shouldn't use this
  533. // since it causes a lock and drawindexedprimitive per surface! (gary)
  534. void Shader_DrawSurfaceStatic( SurfaceHandle_t surfID )
  535. {
  536. VPROF( "Shader_DrawSurfaceStatic" );
  537. if (
  538. #ifdef USE_CONVARS
  539. mat_forcedynamic.GetInt() ||
  540. #endif
  541. (MSurf_Flags( surfID ) & SURFDRAW_WATERSURFACE) )
  542. {
  543. Shader_DrawSurfaceDynamic( pRenderContext, surfID );
  544. return;
  545. }
  546. IMesh *pMesh = pRenderContext->GetDynamicMesh( true,
  547. g_pWorldStatic[MSurf_MaterialSortID( surfID )].m_pMesh );
  548. CMeshBuilder meshBuilder;
  549. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 0, (MSurf_VertCount( surfID )-2)*3 );
  550. unsigned short startVert = MSurf_VertBufferIndex( surfID );
  551. Assert(startVert!=0xFFFF);
  552. for ( int v = 0; v < MSurf_VertCount( surfID )-2; v++ )
  553. {
  554. meshBuilder.Index( startVert );
  555. meshBuilder.AdvanceIndex();
  556. meshBuilder.Index( startVert + v + 1 );
  557. meshBuilder.AdvanceIndex();
  558. meshBuilder.Index( startVert + v + 2 );
  559. meshBuilder.AdvanceIndex();
  560. }
  561. meshBuilder.End();
  562. pMesh->Draw();
  563. }
  564. */
  565. //-----------------------------------------------------------------------------
  566. // Sets the lightmapping state
  567. //-----------------------------------------------------------------------------
  568. static inline void Shader_SetChainLightmapState( IMatRenderContext *pRenderContext, SurfaceHandle_t surfID )
  569. {
  570. if ( g_pMaterialSystemConfig->nFullbright == 1 )
  571. {
  572. if( MSurf_Flags( surfID ) & SURFDRAW_BUMPLIGHT )
  573. {
  574. pRenderContext->BindLightmapPage( MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP );
  575. }
  576. else
  577. {
  578. pRenderContext->BindLightmapPage( MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE );
  579. }
  580. }
  581. else
  582. {
  583. Assert( MSurf_MaterialSortID( surfID ) >= 0 && MSurf_MaterialSortID( surfID ) < g_WorldStaticMeshes.Count() );
  584. pRenderContext->BindLightmapPage( materialSortInfoArray[MSurf_MaterialSortID( surfID )].lightmapPageID );
  585. }
  586. }
  587. //-----------------------------------------------------------------------------
  588. // Sets the lightmap + texture to render with
  589. //-----------------------------------------------------------------------------
  590. void Shader_SetChainTextureState( IMatRenderContext *pRenderContext, SurfaceHandle_t surfID, IClientEntity* pBaseEntity, bool bShadowDepth )
  591. {
  592. tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s", __FUNCTION__ );
  593. if ( bShadowDepth )
  594. {
  595. IMaterial *pDrawMaterial = MSurf_TexInfo( surfID )->material;
  596. // Select proper override material
  597. int nAlphaTest = (int) pDrawMaterial->IsAlphaTested();
  598. int nNoCull = (int) pDrawMaterial->IsTwoSided();
  599. IMaterial *pDepthWriteMaterial = g_pMaterialDepthWrite[nAlphaTest][nNoCull];
  600. if ( nAlphaTest == 1 )
  601. {
  602. static unsigned int originalTextureVarCache = 0;
  603. IMaterialVar *pOriginalTextureVar = pDrawMaterial->FindVarFast( "$basetexture", &originalTextureVarCache );
  604. static unsigned int originalTextureFrameVarCache = 0;
  605. IMaterialVar *pOriginalTextureFrameVar = pDrawMaterial->FindVarFast( "$frame", &originalTextureFrameVarCache );
  606. static unsigned int originalAlphaRefCache = 0;
  607. IMaterialVar *pOriginalAlphaRefVar = pDrawMaterial->FindVarFast( "$AlphaTestReference", &originalAlphaRefCache );
  608. static unsigned int textureVarCache = 0;
  609. IMaterialVar *pTextureVar = pDepthWriteMaterial->FindVarFast( "$basetexture", &textureVarCache );
  610. static unsigned int textureFrameVarCache = 0;
  611. IMaterialVar *pTextureFrameVar = pDepthWriteMaterial->FindVarFast( "$frame", &textureFrameVarCache );
  612. static unsigned int alphaRefCache = 0;
  613. IMaterialVar *pAlphaRefVar = pDepthWriteMaterial->FindVarFast( "$AlphaTestReference", &alphaRefCache );
  614. if( pTextureVar && pOriginalTextureVar )
  615. {
  616. pTextureVar->SetTextureValue( pOriginalTextureVar->GetTextureValue() );
  617. }
  618. if( pTextureFrameVar && pOriginalTextureFrameVar )
  619. {
  620. pTextureFrameVar->SetIntValue( pOriginalTextureFrameVar->GetIntValue() );
  621. }
  622. if( pAlphaRefVar && pOriginalAlphaRefVar )
  623. {
  624. pAlphaRefVar->SetFloatValue( pOriginalAlphaRefVar->GetFloatValue() );
  625. }
  626. }
  627. pRenderContext->Bind( pDepthWriteMaterial );
  628. }
  629. else
  630. {
  631. pRenderContext->Bind( MSurf_TexInfo( surfID )->material, pBaseEntity ? pBaseEntity->GetClientRenderable() : NULL );
  632. Shader_SetChainLightmapState( pRenderContext, surfID );
  633. }
  634. }
  635. void Shader_DrawDynamicChain( const CMSurfaceSortList &sortList, const surfacesortgroup_t &group, bool bShadowDepth )
  636. {
  637. tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s", __FUNCTION__ );
  638. CMatRenderContextPtr pRenderContext( materials );
  639. SurfaceHandle_t hSurfID = sortList.GetSurfaceAtHead(group);
  640. if ( !IS_SURF_VALID( hSurfID ))
  641. return;
  642. Shader_SetChainTextureState( pRenderContext, hSurfID, 0, bShadowDepth );
  643. MSL_FOREACH_SURFACE_IN_GROUP_BEGIN(sortList, group, surfID)
  644. {
  645. Shader_DrawSurfaceDynamic( pRenderContext, surfID, bShadowDepth );
  646. }
  647. MSL_FOREACH_SURFACE_IN_GROUP_END()
  648. }
  649. void Shader_DrawChainsDynamic( const CMSurfaceSortList &sortList, int nSortGroup, bool bShadowDepth )
  650. {
  651. tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s", __FUNCTION__ );
  652. MSL_FOREACH_GROUP_BEGIN(sortList, nSortGroup, group )
  653. {
  654. Shader_DrawDynamicChain( sortList, group, bShadowDepth );
  655. }
  656. MSL_FOREACH_GROUP_END()
  657. }
  658. struct vertexformatlist_t
  659. {
  660. unsigned short numbatches;
  661. unsigned short firstbatch;
  662. #ifdef NEWMESH
  663. IVertexBuffer *pVertexBuffer;
  664. #else
  665. IMesh *pMesh;
  666. #endif
  667. };
  668. struct batchlist_t
  669. {
  670. SurfaceHandle_t surfID; // material and lightmap info
  671. unsigned short firstIndex;
  672. unsigned short numIndex;
  673. };
  674. void Shader_DrawChainsStatic( const CMSurfaceSortList &sortList, int nSortGroup, bool bShadowDepth )
  675. {
  676. tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s", __FUNCTION__ );
  677. //VPROF("DrawChainsStatic");
  678. CUtlVectorFixed<vertexformatlist_t, MAX_VERTEX_FORMAT_CHANGES> meshList;
  679. int meshMap[MAX_VERTEX_FORMAT_CHANGES];
  680. CUtlVectorFixedGrowable<batchlist_t, 512> batchList;
  681. CUtlVectorFixedGrowable<const surfacesortgroup_t *, 8> dynamicGroups;
  682. bool bWarn = true;
  683. #ifdef NEWMESH
  684. CIndexBufferBuilder indexBufferBuilder;
  685. #else
  686. CMeshBuilder meshBuilder;
  687. #endif
  688. bool skipBind = false;
  689. if ( g_pMaterialSystemConfig->nFullbright == 1 )
  690. {
  691. skipBind = true;
  692. }
  693. const CUtlVector<surfacesortgroup_t *> &groupList = sortList.GetSortList(nSortGroup);
  694. int count = groupList.Count();
  695. int i, listIndex = 0;
  696. CMatRenderContextPtr pRenderContext( materials );
  697. //PIXEVENT( pRenderContext, "Shader_DrawChainsStatic" );
  698. int nMaxIndices = pRenderContext->GetMaxIndicesToRender();
  699. while ( listIndex < count )
  700. {
  701. const surfacesortgroup_t &groupBase = *groupList[listIndex];
  702. SurfaceHandle_t surfIDBase = sortList.GetSurfaceAtHead( groupBase );
  703. int sortIDBase = MSurf_MaterialSortID( surfIDBase );
  704. #ifdef NEWMESH
  705. IIndexBuffer *pBuildIndexBuffer = pRenderContext->GetDynamicIndexBuffer( MATERIAL_INDEX_FORMAT_16BIT, false );
  706. indexBufferBuilder.Begin( pBuildIndexBuffer, nMaxIndices );
  707. IVertexBuffer *pLastVertexBuffer = NULL;
  708. #else
  709. IMesh *pBuildMesh = pRenderContext->GetDynamicMesh( false, g_WorldStaticMeshes[sortIDBase] );
  710. meshBuilder.Begin( pBuildMesh, MATERIAL_TRIANGLES, 0, nMaxIndices );
  711. IMesh *pLastMesh = NULL;
  712. #endif
  713. int indexCount = 0;
  714. int meshIndex = -1;
  715. for ( ; listIndex < count; listIndex++ )
  716. {
  717. const surfacesortgroup_t &group = *groupList[listIndex];
  718. SurfaceHandle_t surfID = sortList.GetSurfaceAtHead(group);
  719. Assert( IS_SURF_VALID( surfID ) );
  720. if ( MSurf_Flags(surfID) & SURFDRAW_DYNAMIC )
  721. {
  722. dynamicGroups.AddToTail( &group );
  723. continue;
  724. }
  725. Assert( group.triangleCount > 0 );
  726. int numIndex = group.triangleCount * 3;
  727. if ( indexCount + numIndex > nMaxIndices )
  728. {
  729. if ( numIndex > nMaxIndices )
  730. {
  731. DevMsg("Too many faces with the same material in scene!\n");
  732. break;
  733. }
  734. #ifdef NEWMESH
  735. pLastVertexBuffer = NULL;
  736. #else
  737. pLastMesh = NULL;
  738. #endif
  739. break;
  740. }
  741. int sortID = MSurf_MaterialSortID( surfID );
  742. #ifdef NEWMESH
  743. if ( g_WorldStaticMeshes[sortID] != pLastVertexBuffer )
  744. #else
  745. if ( g_WorldStaticMeshes[sortID] != pLastMesh )
  746. #endif
  747. {
  748. if( meshList.Count() < MAX_VERTEX_FORMAT_CHANGES - 1 )
  749. {
  750. meshIndex = meshList.AddToTail();
  751. meshList[meshIndex].numbatches = 0;
  752. meshList[meshIndex].firstbatch = batchList.Count();
  753. #ifdef NEWMESH
  754. pLastVertexBuffer = g_WorldStaticMeshes[sortID];
  755. Assert( pLastVertexBuffer );
  756. meshList[meshIndex].pVertexBuffer = pLastVertexBuffer;
  757. #else
  758. pLastMesh = g_WorldStaticMeshes[sortID];
  759. Assert( pLastMesh );
  760. meshList[meshIndex].pMesh = pLastMesh;
  761. #endif
  762. }
  763. else
  764. {
  765. if ( bWarn )
  766. {
  767. Warning( "Too many vertex format changes in frame, whole world not rendered\n" );
  768. bWarn = false;
  769. }
  770. continue;
  771. }
  772. }
  773. int batchIndex = batchList.AddToTail();
  774. batchlist_t &batch = batchList[batchIndex];
  775. batch.firstIndex = indexCount;
  776. batch.surfID = surfID;
  777. batch.numIndex = numIndex;
  778. Assert( indexCount + batch.numIndex < nMaxIndices );
  779. indexCount += batch.numIndex;
  780. meshList[meshIndex].numbatches++;
  781. MSL_FOREACH_SURFACE_IN_GROUP_BEGIN(sortList, group, surfIDList)
  782. {
  783. tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "BuildIndicesForWorldSurface" );
  784. #ifdef NEWMESH
  785. BuildIndicesForWorldSurface( indexBufferBuilder, surfIDList, host_state.worldbrush );
  786. #else
  787. Assert( meshBuilder.m_nFirstVertex == 0 );
  788. BuildIndicesForWorldSurface( meshBuilder, surfIDList, host_state.worldbrush );
  789. #endif
  790. }
  791. MSL_FOREACH_SURFACE_IN_GROUP_END()
  792. }
  793. // close out the index buffer
  794. #ifdef NEWMESH
  795. indexBufferBuilder.End( false ); // this one matches (world rendering)
  796. #else
  797. meshBuilder.End( false, false );
  798. #endif
  799. int meshTotal = meshList.Count();
  800. VPROF_INCREMENT_COUNTER( "vertex format changes", meshTotal );
  801. // HACKHACK: Crappy little bubble sort
  802. // UNDONE: Make the traversal happen so that they are already sorted when you get here.
  803. // NOTE: Profiled in a fairly complex map. This is not even costing 0.01ms / frame!
  804. for ( i = 0; i < meshTotal; i++ )
  805. {
  806. meshMap[i] = i;
  807. }
  808. bool swapped = true;
  809. while ( swapped )
  810. {
  811. swapped = false;
  812. for ( i = 1; i < meshTotal; i++ )
  813. {
  814. #ifdef NEWMESH
  815. if ( meshList[meshMap[i]].pVertexBuffer < meshList[meshMap[i-1]].pVertexBuffer )
  816. #else
  817. if ( meshList[meshMap[i]].pMesh < meshList[meshMap[i-1]].pMesh )
  818. #endif
  819. {
  820. int tmp = meshMap[i-1];
  821. meshMap[i-1] = meshMap[i];
  822. meshMap[i] = tmp;
  823. swapped = true;
  824. }
  825. }
  826. }
  827. #ifndef NEWMESH
  828. pRenderContext->BeginBatch( pBuildMesh );
  829. #endif
  830. for ( int m = 0; m < meshTotal; m++ )
  831. {
  832. vertexformatlist_t &mesh = meshList[meshMap[m]];
  833. IMaterial *pBindMaterial = materialSortInfoArray[MSurf_MaterialSortID( batchList[mesh.firstbatch].surfID )].material;
  834. #ifdef NEWMESH
  835. Assert( mesh.pVertexBuffer && pBuildIndexBuffer );
  836. #else
  837. Assert( mesh.pMesh && pBuildMesh );
  838. #endif
  839. #ifdef NEWMESH
  840. IIndexBuffer *pIndexBuffer = pRenderContext->GetDynamicIndexBuffer( MATERIAL_INDEX_FORMAT_16BIT, false );
  841. #else
  842. // IMesh *pMesh = pRenderContext->GetDynamicMesh( false, mesh.pMesh, pBuildMesh, pBindMaterial );
  843. pRenderContext->BindBatch( mesh.pMesh, pBindMaterial );
  844. #endif
  845. for ( int b = 0; b < mesh.numbatches; b++ )
  846. {
  847. batchlist_t &batch = batchList[b+mesh.firstbatch];
  848. IMaterial *pDrawMaterial = materialSortInfoArray[MSurf_MaterialSortID( batch.surfID )].material;
  849. if ( bShadowDepth )
  850. {
  851. // Select proper override material
  852. int nAlphaTest = (int) pDrawMaterial->IsAlphaTested();
  853. int nNoCull = (int) pDrawMaterial->IsTwoSided();
  854. IMaterial *pDepthWriteMaterial = g_pMaterialDepthWrite[nAlphaTest][nNoCull];
  855. if ( nAlphaTest == 1 )
  856. {
  857. static unsigned int originalTextureVarCache = 0;
  858. IMaterialVar *pOriginalTextureVar = pDrawMaterial->FindVarFast( "$basetexture", &originalTextureVarCache );
  859. static unsigned int originalTextureFrameVarCache = 0;
  860. IMaterialVar *pOriginalTextureFrameVar = pDrawMaterial->FindVarFast( "$frame", &originalTextureFrameVarCache );
  861. static unsigned int originalAlphaRefCache = 0;
  862. IMaterialVar *pOriginalAlphaRefVar = pDrawMaterial->FindVarFast( "$AlphaTestReference", &originalAlphaRefCache );
  863. static unsigned int textureVarCache = 0;
  864. IMaterialVar *pTextureVar = pDepthWriteMaterial->FindVarFast( "$basetexture", &textureVarCache );
  865. static unsigned int textureFrameVarCache = 0;
  866. IMaterialVar *pTextureFrameVar = pDepthWriteMaterial->FindVarFast( "$frame", &textureFrameVarCache );
  867. static unsigned int alphaRefCache = 0;
  868. IMaterialVar *pAlphaRefVar = pDepthWriteMaterial->FindVarFast( "$AlphaTestReference", &alphaRefCache );
  869. if( pTextureVar && pOriginalTextureVar )
  870. {
  871. pTextureVar->SetTextureValue( pOriginalTextureVar->GetTextureValue() );
  872. }
  873. if( pTextureFrameVar && pOriginalTextureFrameVar )
  874. {
  875. pTextureFrameVar->SetIntValue( pOriginalTextureFrameVar->GetIntValue() );
  876. }
  877. if( pAlphaRefVar && pOriginalAlphaRefVar )
  878. {
  879. pAlphaRefVar->SetFloatValue( pOriginalAlphaRefVar->GetFloatValue() );
  880. }
  881. }
  882. pRenderContext->Bind( pDepthWriteMaterial );
  883. }
  884. else
  885. {
  886. pRenderContext->Bind( pDrawMaterial, NULL );
  887. if ( skipBind )
  888. {
  889. if( MSurf_Flags( batch.surfID ) & SURFDRAW_BUMPLIGHT )
  890. {
  891. pRenderContext->BindLightmapPage( MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP );
  892. }
  893. else
  894. {
  895. pRenderContext->BindLightmapPage( MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE );
  896. }
  897. }
  898. else
  899. {
  900. pRenderContext->BindLightmapPage( materialSortInfoArray[MSurf_MaterialSortID( batch.surfID )].lightmapPageID );
  901. }
  902. }
  903. #ifdef NEWMESH
  904. // FIXME: IMaterial::GetVertexFormat() should do this stripping (add a separate 'SupportsCompression' accessor)
  905. VertexFormat_t vertexFormat = pBindMaterial->GetVertexFormat() & ~VERTEX_FORMAT_COMPRESSED;
  906. pRenderContext->BindVertexBuffer( 0, mesh.pVertexBuffer, 0, vertexFormat );
  907. pRenderContext->BindIndexBuffer( pIndexBuffer, 0 );
  908. Warning( "pRenderContext->Draw( MATERIAL_TRIANGLES, batch.firstIndex = %d, batch.numIndex = %d )\n",
  909. ( int )batch.firstIndex, ( int )batch.numIndex );
  910. pRenderContext->Draw( MATERIAL_TRIANGLES, batch.firstIndex, batch.numIndex );
  911. #else
  912. // pMesh->Draw( batch.firstIndex, batch.numIndex );
  913. pRenderContext->DrawBatch( batch.firstIndex, batch.numIndex );
  914. #endif
  915. }
  916. }
  917. #ifndef NEWMESH
  918. pRenderContext->EndBatch();
  919. #endif
  920. // if we get here and pLast mesh is NULL and we rendered somthing, we need to loop
  921. #ifdef NEWMESH
  922. if ( pLastVertexBuffer || !meshTotal )
  923. #else
  924. if ( pLastMesh || !meshTotal )
  925. #endif
  926. break;
  927. meshList.RemoveAll();
  928. batchList.RemoveAll();
  929. }
  930. for ( i = 0; i < dynamicGroups.Count(); i++ )
  931. {
  932. Shader_DrawDynamicChain( sortList, *dynamicGroups[i], bShadowDepth );
  933. }
  934. }
  935. //-----------------------------------------------------------------------------
  936. // The following methods will display debugging info in the middle of each surface
  937. //-----------------------------------------------------------------------------
  938. typedef void (*SurfaceDebugFunc_t)( SurfaceHandle_t surfID, const Vector &vecCentroid );
  939. void DrawSurfaceID( SurfaceHandle_t surfID, const Vector &vecCentroid )
  940. {
  941. char buf[32];
  942. Q_snprintf(buf, sizeof( buf ), "0x%p", surfID );
  943. CDebugOverlay::AddTextOverlay( vecCentroid, 0, buf );
  944. }
  945. void DrawSurfaceIDAsInt( SurfaceHandle_t surfID, const Vector &vecCentroid )
  946. {
  947. int nInt = (msurface2_t*)surfID - host_state.worldbrush->surfaces2;
  948. char buf[32];
  949. Q_snprintf( buf, sizeof( buf ), "%d", nInt );
  950. CDebugOverlay::AddTextOverlay( vecCentroid, 0, buf );
  951. }
  952. void DrawSurfaceMaterial( SurfaceHandle_t surfID, const Vector &vecCentroid )
  953. {
  954. mtexinfo_t * pTexInfo = MSurf_TexInfo(surfID);
  955. const char *pFullMaterialName = pTexInfo->material ? pTexInfo->material->GetName() : "no material";
  956. const char *pSlash = strrchr( pFullMaterialName, '/' );
  957. const char *pMaterialName = strrchr( pFullMaterialName, '\\' );
  958. if (pSlash > pMaterialName)
  959. pMaterialName = pSlash;
  960. if (pMaterialName)
  961. ++pMaterialName;
  962. else
  963. pMaterialName = pFullMaterialName;
  964. CDebugOverlay::AddTextOverlay( vecCentroid, 0, pMaterialName );
  965. }
  966. //-----------------------------------------------------------------------------
  967. // Displays the surface id # in the center of the surface.
  968. //-----------------------------------------------------------------------------
  969. void Shader_DrawSurfaceDebuggingInfo( const CUtlVector<msurface2_t *> &surfaceList, SurfaceDebugFunc_t func )
  970. {
  971. for ( int i = 0; i < surfaceList.Count(); i++ )
  972. {
  973. SurfaceHandle_t surfID = surfaceList[i];
  974. Assert( !SurfaceHasDispInfo( surfID ) );
  975. // Compute the centroid of the surface
  976. int nCount = MSurf_VertCount( surfID );
  977. if (nCount >= 3)
  978. {
  979. Vector vecCentroid;
  980. Surf_ComputeCentroid( surfID, &vecCentroid );
  981. func( surfID, vecCentroid );
  982. }
  983. }
  984. }
  985. //-----------------------------------------------------------------------------
  986. // Doesn't draw internal triangles
  987. //-----------------------------------------------------------------------------
  988. void Shader_DrawWireframePolygons( const CUtlVector<msurface2_t *> &surfaceList )
  989. {
  990. int nLineCount = 0;
  991. for ( int i = 0; i < surfaceList.Count(); i++ )
  992. {
  993. int nCount = MSurf_VertCount( surfaceList[i] );
  994. if (nCount >= 3)
  995. {
  996. nLineCount += nCount;
  997. }
  998. }
  999. if (nLineCount == 0)
  1000. return;
  1001. CMatRenderContextPtr pRenderContext( materials );
  1002. pRenderContext->Bind( g_materialWorldWireframe );
  1003. IMesh *pMesh = pRenderContext->GetDynamicMesh( false );
  1004. CMeshBuilder meshBuilder;
  1005. meshBuilder.Begin( pMesh, MATERIAL_LINES, nLineCount );
  1006. for ( int i = 0; i < surfaceList.Count(); i++ )
  1007. {
  1008. SurfaceHandle_t surfID = surfaceList[i];
  1009. Assert( !SurfaceHasDispInfo( surfID ) );
  1010. // Compute the centroid of the surface
  1011. int nCount = MSurf_VertCount( surfID );
  1012. if (nCount >= 3)
  1013. {
  1014. int nFirstVertIndex = MSurf_FirstVertIndex( surfID );
  1015. int nVertIndex = host_state.worldbrush->vertindices[nFirstVertIndex + nCount - 1];
  1016. Vector vecPrevPos = host_state.worldbrush->vertexes[nVertIndex].position;
  1017. for (int v = 0; v < nCount; ++v )
  1018. {
  1019. // world-space vertex
  1020. nVertIndex = host_state.worldbrush->vertindices[nFirstVertIndex + v];
  1021. Vector& vec = host_state.worldbrush->vertexes[nVertIndex].position;
  1022. // output to mesh
  1023. meshBuilder.Position3fv( vecPrevPos.Base() );
  1024. meshBuilder.AdvanceVertex();
  1025. meshBuilder.Position3fv( vec.Base() );
  1026. meshBuilder.AdvanceVertex();
  1027. vecPrevPos = vec;
  1028. }
  1029. }
  1030. }
  1031. meshBuilder.End();
  1032. pMesh->Draw();
  1033. }
  1034. //-----------------------------------------------------------------------------
  1035. // Debugging mode, renders the wireframe.
  1036. //-----------------------------------------------------------------------------
  1037. static void Shader_DrawChainsWireframe( const CUtlVector<msurface2_t *> &surfaceList )
  1038. {
  1039. int nWireFrameMode = WireFrameMode();
  1040. switch( nWireFrameMode )
  1041. {
  1042. case 3:
  1043. // Doesn't draw internal triangles
  1044. Shader_DrawWireframePolygons(surfaceList);
  1045. break;
  1046. default:
  1047. {
  1048. CMatRenderContextPtr pRenderContext( materials );
  1049. if( nWireFrameMode == 2 )
  1050. {
  1051. pRenderContext->Bind( g_materialWorldWireframeZBuffer );
  1052. }
  1053. else
  1054. {
  1055. pRenderContext->Bind( g_materialWorldWireframe );
  1056. }
  1057. for ( int i = 0; i < surfaceList.Count(); i++ )
  1058. {
  1059. SurfaceHandle_t surfID = surfaceList[i];
  1060. Assert( !SurfaceHasDispInfo( surfID ) );
  1061. Shader_DrawSurfaceDynamic( pRenderContext, surfID, false );
  1062. }
  1063. }
  1064. }
  1065. }
  1066. //-----------------------------------------------------------------------------
  1067. // Debugging mode, renders the normals
  1068. //-----------------------------------------------------------------------------
  1069. static void Shader_DrawChainNormals( const CUtlVector<msurface2_t *> &surfaceList )
  1070. {
  1071. Vector p, tVect, tangentS, tangentT;
  1072. CMatRenderContextPtr pRenderContext( materials );
  1073. worldbrushdata_t *pBrushData = host_state.worldbrush;
  1074. pRenderContext->Bind( g_pMaterialWireframeVertexColor );
  1075. for ( int i = 0; i < surfaceList.Count(); i++ )
  1076. {
  1077. SurfaceHandle_t surfID = surfaceList[i];
  1078. IMesh *pMesh = pRenderContext->GetDynamicMesh( );
  1079. CMeshBuilder meshBuilder;
  1080. meshBuilder.Begin( pMesh, MATERIAL_LINES, MSurf_VertCount( surfID ) * 3 );
  1081. bool negate = TangentSpaceSurfaceSetup( surfID, tVect );
  1082. int vertID;
  1083. for( vertID = 0; vertID < MSurf_VertCount( surfID ); ++vertID )
  1084. {
  1085. int vertIndex = pBrushData->vertindices[MSurf_FirstVertIndex( surfID )+vertID];
  1086. Vector& pos = pBrushData->vertexes[vertIndex].position;
  1087. Vector& norm = pBrushData->vertnormals[ pBrushData->vertnormalindices[MSurf_FirstVertNormal( surfID )+vertID] ];
  1088. TangentSpaceComputeBasis( tangentS, tangentT, norm, tVect, negate );
  1089. meshBuilder.Position3fv( pos.Base() );
  1090. meshBuilder.Color3ub( 0, 0, 255 );
  1091. meshBuilder.AdvanceVertex();
  1092. VectorMA( pos, 5.0f, norm, p );
  1093. meshBuilder.Position3fv( p.Base() );
  1094. meshBuilder.Color3ub( 0, 0, 255 );
  1095. meshBuilder.AdvanceVertex();
  1096. meshBuilder.Position3fv( pos.Base() );
  1097. meshBuilder.Color3ub( 0, 255, 0 );
  1098. meshBuilder.AdvanceVertex();
  1099. VectorMA( pos, 5.0f, tangentT, p );
  1100. meshBuilder.Position3fv( p.Base() );
  1101. meshBuilder.Color3ub( 0, 255, 0 );
  1102. meshBuilder.AdvanceVertex();
  1103. meshBuilder.Position3fv( pos.Base() );
  1104. meshBuilder.Color3ub( 255, 0, 0 );
  1105. meshBuilder.AdvanceVertex();
  1106. VectorMA( pos, 5.0f, tangentS, p );
  1107. meshBuilder.Position3fv( p.Base() );
  1108. meshBuilder.Color3ub( 255, 0, 0 );
  1109. meshBuilder.AdvanceVertex();
  1110. }
  1111. meshBuilder.End();
  1112. pMesh->Draw();
  1113. }
  1114. }
  1115. static void Shader_DrawChainBumpBasis( const CUtlVector<msurface2_t *> &surfaceList )
  1116. {
  1117. Vector p, tVect, tangentS, tangentT;
  1118. CMatRenderContextPtr pRenderContext( materials );
  1119. worldbrushdata_t *pBrushData = host_state.worldbrush;
  1120. pRenderContext->Bind( g_pMaterialWireframeVertexColor );
  1121. for ( int i = 0; i < surfaceList.Count(); i++ )
  1122. {
  1123. SurfaceHandle_t surfID = surfaceList[i];
  1124. IMesh *pMesh = pRenderContext->GetDynamicMesh( );
  1125. CMeshBuilder meshBuilder;
  1126. meshBuilder.Begin( pMesh, MATERIAL_LINES, MSurf_VertCount( surfID ) * 3 );
  1127. bool negate = TangentSpaceSurfaceSetup( surfID, tVect );
  1128. int vertID;
  1129. for( vertID = 0; vertID < MSurf_VertCount( surfID ); ++vertID )
  1130. {
  1131. int vertIndex = pBrushData->vertindices[MSurf_FirstVertIndex( surfID )+vertID];
  1132. Vector& pos = pBrushData->vertexes[vertIndex].position;
  1133. Vector& norm = pBrushData->vertnormals[ pBrushData->vertnormalindices[MSurf_FirstVertNormal( surfID )+vertID] ];
  1134. TangentSpaceComputeBasis( tangentS, tangentT, norm, tVect, negate );
  1135. Vector worldSpaceBumpBasis[3];
  1136. for( int j = 0; j < 3; j++ )
  1137. {
  1138. worldSpaceBumpBasis[j][0] =
  1139. g_localBumpBasis[j][0] * tangentS[0] +
  1140. g_localBumpBasis[j][1] * tangentS[1] +
  1141. g_localBumpBasis[j][2] * tangentS[2];
  1142. worldSpaceBumpBasis[j][1] =
  1143. g_localBumpBasis[j][0] * tangentT[0] +
  1144. g_localBumpBasis[j][1] * tangentT[1] +
  1145. g_localBumpBasis[j][2] * tangentT[2];
  1146. worldSpaceBumpBasis[j][2] =
  1147. g_localBumpBasis[j][0] * norm[0] +
  1148. g_localBumpBasis[j][1] * norm[1] +
  1149. g_localBumpBasis[j][2] * norm[2];
  1150. }
  1151. meshBuilder.Position3fv( pos.Base() );
  1152. meshBuilder.Color3ub( 255, 0, 0 );
  1153. meshBuilder.AdvanceVertex();
  1154. VectorMA( pos, 5.0f, worldSpaceBumpBasis[0], p );
  1155. meshBuilder.Position3fv( p.Base() );
  1156. meshBuilder.Color3ub( 255, 0, 0 );
  1157. meshBuilder.AdvanceVertex();
  1158. meshBuilder.Position3fv( pos.Base() );
  1159. meshBuilder.Color3ub( 0, 255, 0 );
  1160. meshBuilder.AdvanceVertex();
  1161. VectorMA( pos, 5.0f, worldSpaceBumpBasis[1], p );
  1162. meshBuilder.Position3fv( p.Base() );
  1163. meshBuilder.Color3ub( 0, 255, 0 );
  1164. meshBuilder.AdvanceVertex();
  1165. meshBuilder.Position3fv( pos.Base() );
  1166. meshBuilder.Color3ub( 0, 0, 255 );
  1167. meshBuilder.AdvanceVertex();
  1168. VectorMA( pos, 5.0f, worldSpaceBumpBasis[2], p );
  1169. meshBuilder.Position3fv( p.Base() );
  1170. meshBuilder.Color3ub( 0, 0, 255 );
  1171. meshBuilder.AdvanceVertex();
  1172. }
  1173. meshBuilder.End();
  1174. pMesh->Draw();
  1175. }
  1176. }
  1177. //-----------------------------------------------------------------------------
  1178. // Debugging mode, renders the luxel grid.
  1179. //-----------------------------------------------------------------------------
  1180. static void Shader_DrawLuxels( const CUtlVector<msurface2_t *> &surfaceList )
  1181. {
  1182. CMatRenderContextPtr pRenderContext( materials );
  1183. pRenderContext->Bind( g_materialDebugLuxels );
  1184. for ( int i = 0; i < surfaceList.Count(); i++ )
  1185. {
  1186. SurfaceHandle_t surfID = surfaceList[i];
  1187. Assert( !SurfaceHasDispInfo( surfID ) );
  1188. // Gotta bind the lightmap page so the rendering knows the lightmap scale
  1189. pRenderContext->BindLightmapPage( materialSortInfoArray[MSurf_MaterialSortID( surfID )].lightmapPageID );
  1190. Shader_DrawSurfaceDynamic( pRenderContext, surfID, false );
  1191. }
  1192. }
  1193. static struct CShaderDebug
  1194. {
  1195. bool wireframe;
  1196. bool normals;
  1197. bool luxels;
  1198. bool bumpBasis;
  1199. bool surfacematerials;
  1200. bool anydebug;
  1201. int surfaceid;
  1202. void TestAnyDebug()
  1203. {
  1204. anydebug = wireframe || normals || luxels || bumpBasis || ( surfaceid != 0 ) || surfacematerials;
  1205. }
  1206. } g_ShaderDebug;
  1207. ConVar mat_surfaceid("mat_surfaceid", "0", FCVAR_CHEAT);
  1208. ConVar mat_surfacemat("mat_surfacemat", "0", FCVAR_CHEAT);
  1209. //-----------------------------------------------------------------------------
  1210. // Purpose:
  1211. // Output : static void
  1212. //-----------------------------------------------------------------------------
  1213. static void ComputeDebugSettings( void )
  1214. {
  1215. g_ShaderDebug.wireframe = ShouldDrawInWireFrameMode() || (r_drawworld.GetInt() == 2);
  1216. g_ShaderDebug.normals = mat_normals.GetBool();
  1217. g_ShaderDebug.luxels = mat_luxels.GetBool();
  1218. g_ShaderDebug.bumpBasis = mat_bumpbasis.GetBool();
  1219. g_ShaderDebug.surfaceid = mat_surfaceid.GetInt();
  1220. g_ShaderDebug.surfacematerials = mat_surfacemat.GetBool();
  1221. g_ShaderDebug.TestAnyDebug();
  1222. }
  1223. //-----------------------------------------------------------------------------
  1224. // Draw debugging information
  1225. //-----------------------------------------------------------------------------
  1226. static void DrawDebugInformation( const CUtlVector<msurface2_t *> &surfaceList )
  1227. {
  1228. // Overlay with wireframe if we're in that mode
  1229. if( g_ShaderDebug.wireframe )
  1230. {
  1231. Shader_DrawChainsWireframe(surfaceList);
  1232. }
  1233. // Overlay with normals if we're in that mode
  1234. if( g_ShaderDebug.normals )
  1235. {
  1236. Shader_DrawChainNormals(surfaceList);
  1237. }
  1238. if( g_ShaderDebug.bumpBasis )
  1239. {
  1240. Shader_DrawChainBumpBasis(surfaceList);
  1241. }
  1242. // Overlay with luxel grid if we're in that mode
  1243. if( g_ShaderDebug.luxels )
  1244. {
  1245. Shader_DrawLuxels(surfaceList);
  1246. }
  1247. if ( g_ShaderDebug.surfaceid )
  1248. {
  1249. // Draw the surface id in the middle of the surfaces
  1250. Shader_DrawSurfaceDebuggingInfo( surfaceList, (g_ShaderDebug.surfaceid != 2 ) ? DrawSurfaceID : DrawSurfaceIDAsInt );
  1251. }
  1252. else if ( g_ShaderDebug.surfacematerials )
  1253. {
  1254. // Draw the material name in the middle of the surfaces
  1255. Shader_DrawSurfaceDebuggingInfo( surfaceList, DrawSurfaceMaterial );
  1256. }
  1257. }
  1258. void AddProjectedTextureDecalsToList( CWorldRenderList *pRenderList, int nSortGroup )
  1259. {
  1260. const CMSurfaceSortList &sortList = pRenderList->m_SortList;
  1261. MSL_FOREACH_GROUP_BEGIN( sortList, nSortGroup, group )
  1262. {
  1263. MSL_FOREACH_SURFACE_IN_GROUP_BEGIN(sortList, group, surfID)
  1264. {
  1265. Assert( !SurfaceHasDispInfo( surfID ) );
  1266. if ( SHADOW_DECAL_HANDLE_INVALID != MSurf_ShadowDecals( surfID ) )
  1267. {
  1268. // No shadows on water surfaces
  1269. if ((MSurf_Flags( surfID ) & SURFDRAW_NOSHADOWS) == 0)
  1270. {
  1271. MEM_ALLOC_CREDIT();
  1272. pRenderList->m_ShadowHandles[nSortGroup].AddToTail( MSurf_ShadowDecals( surfID ) );
  1273. }
  1274. }
  1275. // Add overlay fragments to list.
  1276. if ( OVERLAY_FRAGMENT_INVALID != MSurf_OverlayFragmentList( surfID ) )
  1277. {
  1278. OverlayMgr()->AddFragmentListToRenderList( nSortGroup, MSurf_OverlayFragmentList( surfID ), false );
  1279. }
  1280. }
  1281. MSL_FOREACH_SURFACE_IN_GROUP_END();
  1282. }
  1283. MSL_FOREACH_GROUP_END()
  1284. }
  1285. //-----------------------------------------------------------------------------
  1286. // Draws all of the opaque non-displacement surfaces queued up previously
  1287. //-----------------------------------------------------------------------------
  1288. void Shader_DrawChains( const CWorldRenderList *pRenderList, int nSortGroup, bool bShadowDepth )
  1289. {
  1290. tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s", __FUNCTION__ );
  1291. CMatRenderContextPtr pRenderContext(materials);
  1292. Assert( !g_EngineRenderer->InLightmapUpdate() );
  1293. VPROF("Shader_DrawChains");
  1294. // Draw chains...
  1295. #ifdef USE_CONVARS
  1296. if ( !mat_forcedynamic.GetInt() && !g_pMaterialSystemConfig->bDrawFlat )
  1297. #else
  1298. if( 1 )
  1299. #endif
  1300. {
  1301. if ( g_VBAllocTracker )
  1302. g_VBAllocTracker->TrackMeshAllocations( "Shader_DrawChainsStatic" );
  1303. Shader_DrawChainsStatic( pRenderList->m_SortList, nSortGroup, bShadowDepth );
  1304. }
  1305. else
  1306. {
  1307. if ( g_VBAllocTracker )
  1308. g_VBAllocTracker->TrackMeshAllocations( "Shader_DrawChainsDynamic" );
  1309. Shader_DrawChainsDynamic( pRenderList->m_SortList, nSortGroup, bShadowDepth );
  1310. }
  1311. if ( g_VBAllocTracker )
  1312. g_VBAllocTracker->TrackMeshAllocations( NULL );
  1313. #if MOVE_DLIGHTS_TO_NEW_TEXTURE
  1314. for ( int i = 0; i < pRenderList->m_DlightSurfaces[nSortGroup].Count(); i++ )
  1315. {
  1316. SurfaceHandle_t surfID = pRenderList->m_DlightSurfaces[nSortGroup][i];
  1317. if ( !SurfaceHasDispInfo( surfID ) && (MSurf_Flags(surfID) & SURFDRAW_DLIGHTPASS) )
  1318. {
  1319. pRenderContext->Bind( MSurf_TexInfo( surfID )->material, NULL );
  1320. Shader_SetChainLightmapState( pRenderContext, surfID );
  1321. Shader_DrawSurfaceDynamic( pRenderContext, surfID, bShadowDepth );
  1322. }
  1323. }
  1324. #endif
  1325. if ( bShadowDepth ) // Skip debug stuff in shadow depth map
  1326. return;
  1327. #ifdef USE_CONVARS
  1328. if ( g_ShaderDebug.anydebug )
  1329. {
  1330. const CMSurfaceSortList &sortList = pRenderList->m_SortList;
  1331. // Debugging information
  1332. MSL_FOREACH_GROUP_BEGIN(sortList, nSortGroup, group )
  1333. {
  1334. CUtlVector<msurface2_t *> surfList;
  1335. sortList.GetSurfaceListForGroup( surfList, group );
  1336. DrawDebugInformation( surfList );
  1337. }
  1338. MSL_FOREACH_GROUP_END()
  1339. }
  1340. #endif
  1341. }
  1342. //-----------------------------------------------------------------------------
  1343. // Draws all of the opaque displacement surfaces queued up previously
  1344. //-----------------------------------------------------------------------------
  1345. void Shader_DrawDispChain( int nSortGroup, const CMSurfaceSortList &list, unsigned long flags, ERenderDepthMode DepthMode )
  1346. {
  1347. VPROF_BUDGET( "Shader_DrawDispChain", VPROF_BUDGETGROUP_DISPLACEMENT_RENDERING );
  1348. tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s", __FUNCTION__ );
  1349. int count = 0;
  1350. msurface2_t **pList;
  1351. MSL_FOREACH_GROUP_BEGIN( list, nSortGroup, group )
  1352. {
  1353. count += group.surfaceCount;
  1354. }
  1355. MSL_FOREACH_GROUP_END()
  1356. if (count)
  1357. {
  1358. pList = (msurface2_t **)stackalloc( count * sizeof(msurface2_t *));
  1359. int i = 0;
  1360. MSL_FOREACH_GROUP_BEGIN( list, nSortGroup, group )
  1361. {
  1362. MSL_FOREACH_SURFACE_IN_GROUP_BEGIN(list,group,surfID)
  1363. {
  1364. pList[i] = surfID;
  1365. ++i;
  1366. }
  1367. MSL_FOREACH_SURFACE_IN_GROUP_END()
  1368. }
  1369. MSL_FOREACH_GROUP_END()
  1370. Assert(i==count);
  1371. // draw displacments, batch decals
  1372. DispInfo_RenderList( nSortGroup, pList, count, g_EngineRenderer->ViewGetCurrent().m_bOrtho, flags, DepthMode );
  1373. stackfree(pList);
  1374. }
  1375. }
  1376. static void Shader_BuildDynamicLightmaps( CWorldRenderList *pRenderList )
  1377. {
  1378. VPROF( "Shader_BuildDynamicLightmaps" );
  1379. R_DLightStartView();
  1380. // Build all lightmaps for opaque surfaces
  1381. for ( int nSortGroup = 0; nSortGroup < MAX_MAT_SORT_GROUPS; ++nSortGroup)
  1382. {
  1383. #if 0
  1384. int updateStart = g_LightmapUpdateList.Count();
  1385. #endif
  1386. for ( int i = pRenderList->m_DlightSurfaces[nSortGroup].Count()-1; i >= 0; --i )
  1387. {
  1388. LightmapUpdateInfo_t tmp;
  1389. tmp.m_SurfHandle = pRenderList->m_DlightSurfaces[nSortGroup].Element(i);
  1390. tmp.transformIndex = 0;
  1391. g_LightmapUpdateList.AddToTail( tmp );
  1392. }
  1393. // UNDONE: Redo this list? Make a new list with the texture coord info for the new lightmaps?
  1394. #if 0
  1395. pRenderList->m_DlightSurfaces[nSortGroup].RemoveAll();
  1396. for ( int i = updateStart; i < g_LightmapUpdateList.Count(); i++ )
  1397. {
  1398. if ( MSurf_Flags(g_LightmapUpdateList[i].m_SurfHandle) & SURFDRAW_DLIGHTPASS )
  1399. {
  1400. pRenderList->m_DlightSurfaces[nSortGroup].AddToTail(g_LightmapUpdateList[i].m_SurfHandle);
  1401. }
  1402. }
  1403. #endif
  1404. }
  1405. R_DLightEndView();
  1406. }
  1407. //-----------------------------------------------------------------------------
  1408. // Compute if we're in or out of a fog volume
  1409. //-----------------------------------------------------------------------------
  1410. static void ComputeFogVolumeInfo( FogVolumeInfo_t *pFogVolume )
  1411. {
  1412. pFogVolume->m_InFogVolume = false;
  1413. int leafID = CM_PointLeafnum( CurrentViewOrigin() );
  1414. if( leafID < 0 || leafID >= host_state.worldbrush->numleafs )
  1415. return;
  1416. mleaf_t* pLeaf = &host_state.worldbrush->leafs[leafID];
  1417. pFogVolume->m_FogVolumeID = pLeaf->leafWaterDataID;
  1418. if( pFogVolume->m_FogVolumeID == -1 )
  1419. return;
  1420. pFogVolume->m_InFogVolume = true;
  1421. mleafwaterdata_t* pLeafWaterData = &host_state.worldbrush->leafwaterdata[pLeaf->leafWaterDataID];
  1422. if( pLeafWaterData->surfaceTexInfoID == -1 )
  1423. {
  1424. // Should this ever happen?????
  1425. pFogVolume->m_FogEnabled = false;
  1426. return;
  1427. }
  1428. mtexinfo_t* pTexInfo = &host_state.worldbrush->texinfo[pLeafWaterData->surfaceTexInfoID];
  1429. IMaterial* pMaterial = pTexInfo->material;
  1430. if( pMaterial )
  1431. {
  1432. IMaterialVar* pFogColorVar = pMaterial->FindVar( "$fogcolor", NULL );
  1433. IMaterialVar* pFogEnableVar = pMaterial->FindVar( "$fogenable", NULL );
  1434. IMaterialVar* pFogStartVar = pMaterial->FindVar( "$fogstart", NULL );
  1435. IMaterialVar* pFogEndVar = pMaterial->FindVar( "$fogend", NULL );
  1436. pFogVolume->m_FogEnabled = pFogEnableVar->GetIntValue() ? true : false;
  1437. pFogColorVar->GetVecValue( pFogVolume->m_FogColor, 3 );
  1438. pFogVolume->m_FogStart = -pFogStartVar->GetFloatValue();
  1439. pFogVolume->m_FogEnd = -pFogEndVar->GetFloatValue();
  1440. pFogVolume->m_FogSurfaceZ = pLeafWaterData->surfaceZ;
  1441. pFogVolume->m_FogMinZ = pLeafWaterData->minZ;
  1442. pFogVolume->m_FogMode = MATERIAL_FOG_LINEAR;
  1443. }
  1444. else
  1445. {
  1446. static bool bComplained = false;
  1447. if( !bComplained )
  1448. {
  1449. Warning( "***Water vmt missing . . check console for missing materials!***\n" );
  1450. bComplained = true;
  1451. }
  1452. pFogVolume->m_FogEnabled = false;
  1453. }
  1454. }
  1455. //-----------------------------------------------------------------------------
  1456. // Resets a world render list
  1457. //-----------------------------------------------------------------------------
  1458. void ResetWorldRenderList( CWorldRenderList *pRenderList )
  1459. {
  1460. if ( pRenderList )
  1461. {
  1462. pRenderList->Reset();
  1463. }
  1464. }
  1465. //-----------------------------------------------------------------------------
  1466. // Call this before rendering; it clears out the lists of stuff to render
  1467. //-----------------------------------------------------------------------------
  1468. void Shader_WorldBegin( CWorldRenderList *pRenderList )
  1469. {
  1470. // Cache the convars so we don't keep accessing them...
  1471. s_ShaderConvars.m_bDrawWorld = r_drawworld.GetBool();
  1472. s_ShaderConvars.m_nDrawLeaf = r_drawleaf.GetInt();
  1473. s_ShaderConvars.m_bDrawFuncDetail = r_drawfuncdetail.GetBool();
  1474. ResetWorldRenderList( pRenderList );
  1475. // Clear out the decal list
  1476. DecalSurfacesInit( false );
  1477. // Clear out the render lists of overlays
  1478. OverlayMgr()->ClearRenderLists();
  1479. // Clear out the render lists of shadows
  1480. g_pShadowMgr->ClearShadowRenderList( );
  1481. }
  1482. //-----------------------------------------------------------------------------
  1483. // Performs the z-fill
  1484. //-----------------------------------------------------------------------------
  1485. static void Shader_WorldZFillSurfChain( const CMSurfaceSortList &sortList, const surfacesortgroup_t &group, CMeshBuilder &meshBuilder, int &nStartVertIn, unsigned int includeFlags )
  1486. {
  1487. int nStartVert = nStartVertIn;
  1488. mvertex_t *pWorldVerts = host_state.worldbrush->vertexes;
  1489. MSL_FOREACH_SURFACE_IN_GROUP_BEGIN(sortList, group, nSurfID)
  1490. {
  1491. if ( (MSurf_Flags( nSurfID ) & includeFlags) == 0 )
  1492. continue;
  1493. // Skip water surfaces since it may move up or down to fixup water transitions.
  1494. if ( MSurf_Flags( nSurfID ) & SURFDRAW_WATERSURFACE )
  1495. continue;
  1496. int nSurfTriangleCount = MSurf_VertCount( nSurfID ) - 2;
  1497. unsigned short *pVertIndex = &(host_state.worldbrush->vertindices[MSurf_FirstVertIndex( nSurfID )]);
  1498. // add surface to this batch
  1499. if ( SurfaceHasPrims(nSurfID) )
  1500. {
  1501. mprimitive_t *pPrim = &host_state.worldbrush->primitives[MSurf_FirstPrimID( nSurfID )];
  1502. if ( pPrim->vertCount == 0 )
  1503. {
  1504. int firstVert = MSurf_FirstVertIndex( nSurfID );
  1505. for ( int i = 0; i < MSurf_VertCount(nSurfID); i++ )
  1506. {
  1507. int vertIndex = host_state.worldbrush->vertindices[firstVert + i];
  1508. meshBuilder.Position3fv( pWorldVerts[vertIndex].position.Base() );
  1509. meshBuilder.AdvanceVertex();
  1510. }
  1511. for ( int primIndex = 0; primIndex < pPrim->indexCount; primIndex++ )
  1512. {
  1513. meshBuilder.FastIndex( host_state.worldbrush->primindices[pPrim->firstIndex + primIndex] + nStartVert );
  1514. }
  1515. }
  1516. }
  1517. else
  1518. {
  1519. switch (nSurfTriangleCount)
  1520. {
  1521. case 1:
  1522. meshBuilder.Position3fv( pWorldVerts[*pVertIndex++].position.Base() );
  1523. meshBuilder.AdvanceVertex();
  1524. meshBuilder.Position3fv( pWorldVerts[*pVertIndex++].position.Base() );
  1525. meshBuilder.AdvanceVertex();
  1526. meshBuilder.Position3fv( pWorldVerts[*pVertIndex++].position.Base() );
  1527. meshBuilder.AdvanceVertex();
  1528. meshBuilder.FastIndex( nStartVert );
  1529. meshBuilder.FastIndex( nStartVert + 1 );
  1530. meshBuilder.FastIndex( nStartVert + 2 );
  1531. break;
  1532. case 2:
  1533. meshBuilder.Position3fv( pWorldVerts[*pVertIndex++].position.Base() );
  1534. meshBuilder.AdvanceVertex();
  1535. meshBuilder.Position3fv( pWorldVerts[*pVertIndex++].position.Base() );
  1536. meshBuilder.AdvanceVertex();
  1537. meshBuilder.Position3fv( pWorldVerts[*pVertIndex++].position.Base() );
  1538. meshBuilder.AdvanceVertex();
  1539. meshBuilder.Position3fv( pWorldVerts[*pVertIndex++].position.Base() );
  1540. meshBuilder.AdvanceVertex();
  1541. meshBuilder.FastIndex( nStartVert );
  1542. meshBuilder.FastIndex( nStartVert + 1 );
  1543. meshBuilder.FastIndex( nStartVert + 2 );
  1544. meshBuilder.FastIndex( nStartVert );
  1545. meshBuilder.FastIndex( nStartVert + 2 );
  1546. meshBuilder.FastIndex( nStartVert + 3 );
  1547. break;
  1548. default:
  1549. {
  1550. for ( unsigned short v = 0; v < nSurfTriangleCount; ++v )
  1551. {
  1552. meshBuilder.Position3fv( pWorldVerts[*pVertIndex++].position.Base() );
  1553. meshBuilder.AdvanceVertex();
  1554. meshBuilder.FastIndex( nStartVert );
  1555. meshBuilder.FastIndex( nStartVert + v + 1 );
  1556. meshBuilder.FastIndex( nStartVert + v + 2 );
  1557. }
  1558. meshBuilder.Position3fv( pWorldVerts[*pVertIndex++].position.Base() );
  1559. meshBuilder.AdvanceVertex();
  1560. meshBuilder.Position3fv( pWorldVerts[*pVertIndex++].position.Base() );
  1561. meshBuilder.AdvanceVertex();
  1562. }
  1563. break;
  1564. }
  1565. }
  1566. nStartVert += nSurfTriangleCount + 2;
  1567. }
  1568. MSL_FOREACH_SURFACE_IN_GROUP_END()
  1569. nStartVertIn = nStartVert;
  1570. }
  1571. static const int s_DrawWorldListsToSortGroup[MAX_MAT_SORT_GROUPS] =
  1572. {
  1573. MAT_SORT_GROUP_STRICTLY_ABOVEWATER,
  1574. MAT_SORT_GROUP_STRICTLY_UNDERWATER,
  1575. MAT_SORT_GROUP_INTERSECTS_WATER_SURFACE,
  1576. MAT_SORT_GROUP_WATERSURFACE,
  1577. };
  1578. static ConVar r_flashlightrendermodels( "r_flashlightrendermodels", "1" );
  1579. //-----------------------------------------------------------------------------
  1580. // Performs the shadow depth texture fill
  1581. //-----------------------------------------------------------------------------
  1582. static void Shader_WorldShadowDepthFill( CWorldRenderList *pRenderList, unsigned long flags )
  1583. {
  1584. tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s", __FUNCTION__ );
  1585. // First, count the number of vertices + indices
  1586. int nVertexCount = 0;
  1587. int nIndexCount = 0;
  1588. ERenderDepthMode DepthMode = DEPTH_MODE_SHADOW;
  1589. if ( flags & DRAWWORLDLISTS_DRAW_SSAO )
  1590. {
  1591. DepthMode = DEPTH_MODE_SSA0;
  1592. }
  1593. int g;
  1594. CUtlVector<const surfacesortgroup_t *> alphatestedGroups;
  1595. const CMSurfaceSortList &sortList = pRenderList->m_SortList;
  1596. for ( g = 0; g < MAX_MAT_SORT_GROUPS; ++g )
  1597. {
  1598. if ( ( flags & ( 1 << g ) ) == 0 )
  1599. continue;
  1600. int nSortGroup = s_DrawWorldListsToSortGroup[g];
  1601. MSL_FOREACH_GROUP_BEGIN(sortList, nSortGroup, group )
  1602. {
  1603. SurfaceHandle_t surfID = sortList.GetSurfaceAtHead(group);
  1604. if ( MSurf_Flags( surfID ) & SURFDRAW_WATERSURFACE )
  1605. continue;
  1606. IMaterial *pMaterial = MSurf_TexInfo( surfID )->material;
  1607. if( pMaterial->IsTranslucent() )
  1608. continue;
  1609. if ( pMaterial->IsAlphaTested() )
  1610. {
  1611. alphatestedGroups.AddToTail( &group );
  1612. continue;
  1613. }
  1614. nVertexCount += group.vertexCount;
  1615. nIndexCount += group.triangleCount*3;
  1616. }
  1617. MSL_FOREACH_GROUP_END()
  1618. // Draws opaque displacement surfaces along with shadows, overlays, flashlights, etc.
  1619. Shader_DrawDispChain( nSortGroup, pRenderList->m_DispSortList, flags, DepthMode );
  1620. }
  1621. if ( nVertexCount == 0 )
  1622. return;
  1623. CMatRenderContextPtr pRenderContext( materials );
  1624. if ( DepthMode == DEPTH_MODE_SHADOW )
  1625. {
  1626. pRenderContext->Bind( g_pMaterialDepthWrite[0][1] );
  1627. }
  1628. else
  1629. {
  1630. pRenderContext->Bind( g_pMaterialSSAODepthWrite[0][1] );
  1631. }
  1632. IMesh *pMesh = pRenderContext->GetDynamicMesh( false );
  1633. int nMaxIndices = pRenderContext->GetMaxIndicesToRender();
  1634. int nMaxVertices = pRenderContext->GetMaxVerticesToRender( g_pMaterialDepthWrite[0][1] ); // opaque, nocull
  1635. // nBatchIndexCount and nBatchVertexCount are the number of indices and vertices we can fit in this batch
  1636. // Each batch must have fewer than nMaxIndices and nMaxVertices or the material system will fail
  1637. int nBatchIndexCount = min( nIndexCount, nMaxIndices );
  1638. int nBatchVertexCount = min( nVertexCount, nMaxVertices );
  1639. CMeshBuilder meshBuilder;
  1640. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nBatchVertexCount, nBatchIndexCount );
  1641. int nStartVert = 0;
  1642. for ( g = 0; g < MAX_MAT_SORT_GROUPS; ++g )
  1643. {
  1644. if ( ( flags & ( 1 << g ) ) == 0 )
  1645. continue;
  1646. int nSortGroup = s_DrawWorldListsToSortGroup[g];
  1647. MSL_FOREACH_GROUP_BEGIN(sortList, nSortGroup, group )
  1648. {
  1649. SurfaceHandle_t surfID = sortList.GetSurfaceAtHead(group);
  1650. // Check to see if we can add this list to the current batch...
  1651. int nCurrIndexCount = group.triangleCount*3;
  1652. int nCurrVertexCount = group.vertexCount;
  1653. if ( ( nCurrIndexCount == 0 ) || ( nCurrVertexCount == 0 ) )
  1654. continue;
  1655. // this group is too big to draw so push it into the alphatested groups
  1656. // this will run much slower but at least it won't crash
  1657. // alphatested groups will draw each surface one at a time.
  1658. if ( nCurrIndexCount > nMaxIndices || nCurrVertexCount > nMaxVertices )
  1659. {
  1660. alphatestedGroups.AddToTail( &group );
  1661. continue;
  1662. }
  1663. IMaterial *pMaterial = MSurf_TexInfo( surfID )->material;
  1664. // Opaque only on this loop
  1665. if( pMaterial->IsTranslucent() || pMaterial->IsAlphaTested() )
  1666. continue;
  1667. Assert( nCurrIndexCount <= nMaxIndices );
  1668. Assert( nCurrVertexCount <= nMaxVertices );
  1669. if ( ( nBatchIndexCount < nCurrIndexCount ) || ( nBatchVertexCount < nCurrVertexCount ) )
  1670. {
  1671. // Nope, fire off the current batch...
  1672. meshBuilder.End();
  1673. pMesh->Draw();
  1674. nBatchIndexCount = min( nIndexCount, nMaxIndices );
  1675. nBatchVertexCount = min( nVertexCount, nMaxVertices );
  1676. pMesh = pRenderContext->GetDynamicMesh( false );
  1677. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nBatchVertexCount, nBatchIndexCount );
  1678. nStartVert = 0;
  1679. }
  1680. nBatchIndexCount -= nCurrIndexCount;
  1681. nIndexCount -= nCurrIndexCount;
  1682. nBatchVertexCount -= nCurrVertexCount;
  1683. nVertexCount -= nCurrVertexCount;
  1684. // 0xFFFFFFFF means include all surfaces
  1685. Shader_WorldZFillSurfChain( sortList, group, meshBuilder, nStartVert, 0xFFFFFFFF );
  1686. }
  1687. MSL_FOREACH_GROUP_END()
  1688. }
  1689. meshBuilder.End();
  1690. pMesh->Draw();
  1691. // Now draw the alpha-tested groups we stored away earlier
  1692. for ( int i = 0; i < alphatestedGroups.Count(); i++ )
  1693. {
  1694. Shader_DrawDynamicChain( sortList, *alphatestedGroups[i], true );
  1695. }
  1696. }
  1697. //-----------------------------------------------------------------------------
  1698. // Performs the z-fill
  1699. //-----------------------------------------------------------------------------
  1700. static void Shader_WorldZFill( CWorldRenderList *pRenderList, unsigned long flags )
  1701. {
  1702. tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s", __FUNCTION__ );
  1703. // First, count the number of vertices + indices
  1704. int nVertexCount = 0;
  1705. int nIndexCount = 0;
  1706. int g;
  1707. const CMSurfaceSortList &sortList = pRenderList->m_SortList;
  1708. #ifdef _X360
  1709. bool bFastZRejectDisplacements = s_bFastZRejectDisplacements || ( r_fastzrejectdisp.GetInt() != 0 );
  1710. #endif
  1711. for ( g = 0; g < MAX_MAT_SORT_GROUPS; ++g )
  1712. {
  1713. if ( ( flags & ( 1 << g ) ) == 0 )
  1714. continue;
  1715. int nSortGroup = s_DrawWorldListsToSortGroup[g];
  1716. MSL_FOREACH_GROUP_BEGIN(sortList, nSortGroup, group )
  1717. {
  1718. SurfaceHandle_t surfID = sortList.GetSurfaceAtHead(group);
  1719. IMaterial *pMaterial = MSurf_TexInfo( surfID )->material;
  1720. if( pMaterial->IsAlphaTested() || pMaterial->IsTranslucent() )
  1721. {
  1722. continue;
  1723. }
  1724. nVertexCount += group.vertexCountNoDetail;
  1725. nIndexCount += group.indexCountNoDetail;
  1726. }
  1727. MSL_FOREACH_GROUP_END()
  1728. #ifdef _X360
  1729. // Draws opaque displacement surfaces along with shadows, overlays, flashlights, etc.
  1730. // NOTE: This only makes sense on the 360, since the extra batches aren't
  1731. // worth it on the PC (I think!)
  1732. if ( bFastZRejectDisplacements )
  1733. {
  1734. Shader_DrawDispChain( nSortGroup, pRenderList->m_DispSortList, flags, true );
  1735. }
  1736. #endif
  1737. }
  1738. if ( nVertexCount == 0 )
  1739. return;
  1740. CMatRenderContextPtr pRenderContext( materials );
  1741. pRenderContext->Bind( g_pMaterialWriteZ );
  1742. IMesh *pMesh = pRenderContext->GetDynamicMesh( false );
  1743. int nMaxIndices = pRenderContext->GetMaxIndicesToRender();
  1744. int nMaxVertices = pRenderContext->GetMaxVerticesToRender( g_pMaterialWriteZ );
  1745. // nBatchIndexCount and nBatchVertexCount are the number of indices and vertices we can fit in this batch
  1746. // Each batch must have fewe than nMaxIndices and nMaxVertices or the material system will fail
  1747. int nBatchIndexCount = min( nIndexCount, nMaxIndices );
  1748. int nBatchVertexCount = min( nVertexCount, nMaxVertices );
  1749. CMeshBuilder meshBuilder;
  1750. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nBatchVertexCount, nBatchIndexCount );
  1751. int nStartVert = 0;
  1752. for ( g = 0; g < MAX_MAT_SORT_GROUPS; ++g )
  1753. {
  1754. if ( ( flags & ( 1 << g ) ) == 0 )
  1755. continue;
  1756. int nSortGroup = s_DrawWorldListsToSortGroup[g];
  1757. MSL_FOREACH_GROUP_BEGIN(sortList, nSortGroup, group )
  1758. {
  1759. SurfaceHandle_t surfID = sortList.GetSurfaceAtHead(group);
  1760. // Check to see if we can add this list to the current batch...
  1761. int nCurrIndexCount = group.indexCountNoDetail;
  1762. int nCurrVertexCount = group.vertexCountNoDetail;
  1763. if ( ( nCurrIndexCount == 0 ) || ( nCurrVertexCount == 0 ) )
  1764. continue;
  1765. IMaterial *pMaterial = MSurf_TexInfo( surfID )->material;
  1766. if( pMaterial->IsAlphaTested() || pMaterial->IsTranslucent() )
  1767. continue;
  1768. Assert( nCurrIndexCount <= nMaxIndices );
  1769. Assert( nCurrVertexCount <= nMaxVertices );
  1770. if ( ( nBatchIndexCount < nCurrIndexCount ) || ( nBatchVertexCount < nCurrVertexCount ) )
  1771. {
  1772. // Nope, fire off the current batch...
  1773. meshBuilder.End();
  1774. pMesh->Draw();
  1775. nBatchIndexCount = min( nIndexCount, nMaxIndices );
  1776. nBatchVertexCount = min( nVertexCount, nMaxVertices );
  1777. pMesh = pRenderContext->GetDynamicMesh( false );
  1778. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nBatchVertexCount, nBatchIndexCount );
  1779. nStartVert = 0;
  1780. }
  1781. nBatchIndexCount -= nCurrIndexCount;
  1782. nIndexCount -= nCurrIndexCount;
  1783. nBatchVertexCount -= nCurrVertexCount;
  1784. nVertexCount -= nCurrVertexCount;
  1785. // only draw surfaces on nodes (i.e. no detail surfaces)
  1786. Shader_WorldZFillSurfChain( sortList, group, meshBuilder, nStartVert, SURFDRAW_NODE );
  1787. }
  1788. MSL_FOREACH_GROUP_END()
  1789. }
  1790. meshBuilder.End();
  1791. pMesh->Draw();
  1792. // FIXME: Do fast z reject on displacements!
  1793. }
  1794. //-----------------------------------------------------------------------------
  1795. // Call this after lists of stuff to render are made; it renders opaque surfaces
  1796. //-----------------------------------------------------------------------------
  1797. static void Shader_WorldEnd( CWorldRenderList *pRenderList, unsigned long flags, float waterZAdjust )
  1798. {
  1799. VPROF("Shader_WorldEnd");
  1800. CMatRenderContextPtr pRenderContext( materials );
  1801. if ( flags & ( DRAWWORLDLISTS_DRAW_SHADOWDEPTH | DRAWWORLDLISTS_DRAW_SSAO ) )
  1802. {
  1803. Shader_WorldShadowDepthFill( pRenderList, flags );
  1804. return;
  1805. }
  1806. // Draw the skybox
  1807. if ( flags & DRAWWORLDLISTS_DRAW_SKYBOX )
  1808. {
  1809. if ( pRenderList->m_bSkyVisible || Map_VisForceFullSky() )
  1810. {
  1811. if( flags & DRAWWORLDLISTS_DRAW_CLIPSKYBOX )
  1812. {
  1813. R_DrawSkyBox( g_EngineRenderer->GetZFar() );
  1814. }
  1815. else
  1816. {
  1817. // Don't clip the skybox with height clip in this path.
  1818. MaterialHeightClipMode_t nClipMode = pRenderContext->GetHeightClipMode();
  1819. pRenderContext->SetHeightClipMode( MATERIAL_HEIGHTCLIPMODE_DISABLE );
  1820. R_DrawSkyBox( g_EngineRenderer->GetZFar() );
  1821. pRenderContext->SetHeightClipMode( nClipMode );
  1822. }
  1823. }
  1824. }
  1825. // Perform the fast z-fill pass
  1826. bool bFastZReject = (r_fastzreject.GetInt() != 0);
  1827. if ( bFastZReject )
  1828. {
  1829. Shader_WorldZFill( pRenderList, flags );
  1830. }
  1831. // Gotta draw each sort group
  1832. // Draw the fog volume first, if there is one, because it turns out
  1833. // that we only draw fog volumes if we're in the fog volume, which
  1834. // means it's closer. We want to render closer things first to get
  1835. // fast z-reject.
  1836. int i;
  1837. for ( i = MAX_MAT_SORT_GROUPS; --i >= 0; )
  1838. {
  1839. if ( !( flags & ( 1 << i ) ) )
  1840. continue;
  1841. int nSortGroup = s_DrawWorldListsToSortGroup[i];
  1842. if ( nSortGroup == MAT_SORT_GROUP_WATERSURFACE )
  1843. {
  1844. if ( waterZAdjust != 0.0f )
  1845. {
  1846. pRenderContext->MatrixMode( MATERIAL_MODEL );
  1847. pRenderContext->PushMatrix();
  1848. pRenderContext->LoadIdentity();
  1849. pRenderContext->Translate( 0.0f, 0.0f, waterZAdjust );
  1850. }
  1851. }
  1852. // Draws opaque displacement surfaces along with shadows, overlays, flashlights, etc.
  1853. Shader_DrawDispChain( nSortGroup, pRenderList->m_DispSortList, flags, DEPTH_MODE_NORMAL );
  1854. // Draws opaque non-displacement surfaces
  1855. // This also add shadows to pRenderList->m_ShadowHandles.
  1856. Shader_DrawChains( pRenderList, nSortGroup, false );
  1857. AddProjectedTextureDecalsToList( pRenderList, nSortGroup );
  1858. // Adds shadows to render lists
  1859. for ( int j = pRenderList->m_ShadowHandles[nSortGroup].Count()-1; j >= 0; --j )
  1860. {
  1861. g_pShadowMgr->AddShadowsOnSurfaceToRenderList( pRenderList->m_ShadowHandles[nSortGroup].Element(j) );
  1862. }
  1863. pRenderList->m_ShadowHandles[nSortGroup].RemoveAll();
  1864. // Don't stencil or scissor the flashlight if we're rendering to an offscreen view
  1865. bool bFlashlightMask = !( (flags & DRAWWORLDLISTS_DRAW_REFRACTION ) || (flags & DRAWWORLDLISTS_DRAW_REFLECTION ));
  1866. // Set masking stencil bits for flashlights
  1867. g_pShadowMgr->SetFlashlightStencilMasks( bFlashlightMask );
  1868. // Draw shadows and flashlights on world surfaces
  1869. g_pShadowMgr->RenderFlashlights( bFlashlightMask );
  1870. // Render the fragments from the surfaces + displacements.
  1871. // FIXME: Actually, this call is irrelevant (for displacements) because it's done from
  1872. // within DrawDispChain currently, but that should change.
  1873. // We need to split out the disp decal rendering from DrawDispChain
  1874. // and do it after overlays are rendered....
  1875. OverlayMgr()->RenderOverlays( nSortGroup );
  1876. g_pShadowMgr->DrawFlashlightOverlays( nSortGroup, bFlashlightMask );
  1877. OverlayMgr()->ClearRenderLists( nSortGroup );
  1878. // Draws decals lying on opaque non-displacement surfaces
  1879. DecalSurfaceDraw( pRenderContext, nSortGroup );
  1880. // Draw the flashlight lighting for the decals.
  1881. g_pShadowMgr->DrawFlashlightDecals( nSortGroup, bFlashlightMask );
  1882. // Draw RTT shadows
  1883. g_pShadowMgr->RenderShadows( );
  1884. g_pShadowMgr->ClearShadowRenderList();
  1885. if ( nSortGroup == MAT_SORT_GROUP_WATERSURFACE && waterZAdjust != 0.0f )
  1886. {
  1887. pRenderContext->MatrixMode( MATERIAL_MODEL );
  1888. pRenderContext->PopMatrix();
  1889. }
  1890. }
  1891. }
  1892. //-----------------------------------------------------------------------------
  1893. // Renders translucent surfaces
  1894. //-----------------------------------------------------------------------------
  1895. bool Shader_LeafContainsTranslucentSurfaces( IWorldRenderList *pRenderListIn, int sortIndex, unsigned long flags )
  1896. {
  1897. CWorldRenderList *pRenderList = assert_cast<CWorldRenderList *>(pRenderListIn);
  1898. int i;
  1899. for ( i = 0; i < MAX_MAT_SORT_GROUPS; ++i )
  1900. {
  1901. if( !( flags & ( 1 << i ) ) )
  1902. continue;
  1903. int sortGroup = s_DrawWorldListsToSortGroup[i];
  1904. // Set the fog state here since it will be the same for all things
  1905. // in this list of translucent objects (except for displacements)
  1906. const surfacesortgroup_t &group = pRenderList->m_AlphaSortList.GetGroupForSortID( sortGroup, sortIndex );
  1907. if ( group.surfaceCount )
  1908. return true;
  1909. const surfacesortgroup_t &dispGroup = pRenderList->m_DispAlphaSortList.GetGroupForSortID( sortGroup, sortIndex );
  1910. if ( dispGroup.surfaceCount )
  1911. return true;
  1912. }
  1913. return false;
  1914. }
  1915. void Shader_DrawTranslucentSurfaces( IWorldRenderList *pRenderListIn, int sortIndex, unsigned long flags, bool bShadowDepth )
  1916. {
  1917. if ( !r_drawtranslucentworld.GetBool() )
  1918. return;
  1919. CWorldRenderList *pRenderList = assert_cast<CWorldRenderList *>(pRenderListIn);
  1920. CMatRenderContextPtr pRenderContext( materials );
  1921. bool skipLight = false;
  1922. if ( g_pMaterialSystemConfig->nFullbright == 1 )
  1923. {
  1924. pRenderContext->BindLightmapPage( MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP );
  1925. skipLight = true;
  1926. }
  1927. // Gotta draw each sort group
  1928. // Draw the fog volume first, if there is one, because it turns out
  1929. // that we only draw fog volumes if we're in the fog volume, which
  1930. // means it's closer. We want to render closer things first to get
  1931. // fast z-reject.
  1932. int i;
  1933. CUtlVector<msurface2_t *> surfaceList;
  1934. for ( i = 0; i < MAX_MAT_SORT_GROUPS; ++i )
  1935. {
  1936. if( !( flags & ( 1 << i ) ) )
  1937. {
  1938. continue;
  1939. }
  1940. int sortGroup = s_DrawWorldListsToSortGroup[i];
  1941. // Set the fog state here since it will be the same for all things
  1942. // in this list of translucent objects (except for displacements)
  1943. surfaceList.RemoveAll();
  1944. const surfacesortgroup_t &group = pRenderList->m_AlphaSortList.GetGroupForSortID( sortGroup, sortIndex );
  1945. const surfacesortgroup_t &dispGroup = pRenderList->m_DispAlphaSortList.GetGroupForSortID( sortGroup, sortIndex );
  1946. // Empty? skip...
  1947. if (!group.surfaceCount && !dispGroup.surfaceCount )
  1948. continue;
  1949. pRenderList->m_AlphaSortList.GetSurfaceListForGroup( surfaceList, group );
  1950. // Interate in back-to-front order
  1951. for ( int listIndex = surfaceList.Count(); --listIndex >= 0; )
  1952. {
  1953. SurfaceHandle_t surfID = surfaceList[listIndex];
  1954. pRenderContext->Bind( MSurf_TexInfo( surfID )->material );
  1955. Assert( MSurf_MaterialSortID( surfID ) >= 0 &&
  1956. MSurf_MaterialSortID( surfID ) < g_WorldStaticMeshes.Count() );
  1957. if ( !skipLight )
  1958. {
  1959. pRenderContext->BindLightmapPage( materialSortInfoArray[MSurf_MaterialSortID( surfID )].lightmapPageID );
  1960. }
  1961. // NOTE: Since a static vb/dynamic ib IMesh doesn't buffer, we shouldn't use this
  1962. // since it causes a lock and drawindexedprimitive per surface! (gary)
  1963. // Shader_DrawSurfaceStatic( surfID );
  1964. Shader_DrawSurfaceDynamic( pRenderContext, surfID, false );
  1965. // g_pShadowMgr->ClearShadowRenderList();
  1966. // Add shadows/flashlights to list.
  1967. ShadowDecalHandle_t decalHandle = MSurf_ShadowDecals( surfID );
  1968. if (decalHandle != SHADOW_DECAL_HANDLE_INVALID)
  1969. {
  1970. g_pShadowMgr->AddShadowsOnSurfaceToRenderList( decalHandle );
  1971. }
  1972. bool bFlashlightMask = !( (flags & DRAWWORLDLISTS_DRAW_REFRACTION ) || (flags & DRAWWORLDLISTS_DRAW_REFLECTION ));
  1973. // Draw flashlights
  1974. g_pShadowMgr->RenderFlashlights( bFlashlightMask );
  1975. // Draw overlays on the surface.
  1976. OverlayMgr()->AddFragmentListToRenderList( i, MSurf_OverlayFragmentList( surfID ), false );
  1977. OverlayMgr()->RenderOverlays( i );
  1978. // Draw flashlight overlays
  1979. g_pShadowMgr->DrawFlashlightOverlays( i, bFlashlightMask );
  1980. OverlayMgr()->ClearRenderLists( i );
  1981. // Draw decals on the surface
  1982. DrawDecalsOnSingleSurface( pRenderContext, surfID );
  1983. // Draw flashlight decals
  1984. g_pShadowMgr->DrawFlashlightDecalsOnSingleSurface( surfID, bFlashlightMask );
  1985. // draw shadows
  1986. g_pShadowMgr->RenderShadows();
  1987. g_pShadowMgr->ClearShadowRenderList();
  1988. }
  1989. // Draw wireframe, etc information
  1990. DrawDebugInformation( surfaceList );
  1991. // Now draw the translucent displacements; we need to do these *after* the
  1992. // non-displacement surfaces because most likely the displacement will always
  1993. // be in front (or at least not behind) the non-displacement translucent surfaces
  1994. // that exist in the same leaf.
  1995. // Draws translucent displacement surfaces
  1996. surfaceList.RemoveAll();
  1997. surfaceList.EnsureCapacity(dispGroup.surfaceCount);
  1998. MSL_FOREACH_SURFACE_IN_GROUP_BEGIN(pRenderList->m_DispAlphaSortList, dispGroup, surfID)
  1999. {
  2000. surfaceList.AddToTail(surfID);
  2001. }
  2002. MSL_FOREACH_SURFACE_IN_GROUP_END()
  2003. DispInfo_RenderList( i, surfaceList.Base(), surfaceList.Count(), g_EngineRenderer->ViewGetCurrent().m_bOrtho, flags, DEPTH_MODE_NORMAL );
  2004. }
  2005. }
  2006. //=============================================================
  2007. //
  2008. // WORLD MODEL
  2009. //
  2010. //=============================================================
  2011. void FASTCALL R_DrawSurface( CWorldRenderList *pRenderList, SurfaceHandle_t surfID )
  2012. {
  2013. ASSERT_SURF_VALID( surfID );
  2014. Assert( !SurfaceHasDispInfo( surfID ) );
  2015. if ( MSurf_Flags( surfID ) & SURFDRAW_SKY )
  2016. {
  2017. pRenderList->m_bSkyVisible = true;
  2018. }
  2019. // else if ( surf->texinfo->material->IsTranslucent() )
  2020. else if( MSurf_Flags( surfID ) & SURFDRAW_TRANS )
  2021. {
  2022. Shader_TranslucentWorldSurface( pRenderList, surfID );
  2023. }
  2024. else
  2025. {
  2026. Shader_WorldSurface( pRenderList, surfID );
  2027. }
  2028. }
  2029. // The NoCull flavor of this function calls functions which optimize for shadow depth map rendering
  2030. void FASTCALL R_DrawSurfaceNoCull( CWorldRenderList *pRenderList, SurfaceHandle_t surfID )
  2031. {
  2032. ASSERT_SURF_VALID( surfID );
  2033. if( !(MSurf_Flags( surfID ) & SURFDRAW_TRANS) && !(MSurf_Flags( surfID ) & SURFDRAW_SKY) )
  2034. {
  2035. Shader_WorldSurfaceNoCull( pRenderList, surfID );
  2036. }
  2037. }
  2038. //-----------------------------------------------------------------------------
  2039. // Draws displacements in a leaf
  2040. //-----------------------------------------------------------------------------
  2041. static inline void DrawDisplacementsInLeaf( CWorldRenderList *pRenderList, mleaf_t* pLeaf )
  2042. {
  2043. // add displacement surfaces
  2044. if (!pLeaf->dispCount)
  2045. return;
  2046. CVisitedSurfs &visitedSurfs = pRenderList->m_VisitedSurfs;
  2047. for ( int i = 0; i < pLeaf->dispCount; i++ )
  2048. {
  2049. IDispInfo *pDispInfo = MLeaf_Disaplcement( pLeaf, i );
  2050. // NOTE: We're not using the displacement's touched method here
  2051. // because we're just using the parent surface's visframe in the
  2052. // surface add methods below...
  2053. SurfaceHandle_t parentSurfID = pDispInfo->GetParent();
  2054. // already processed this frame? Then don't do it again!
  2055. if ( VisitSurface( visitedSurfs, parentSurfID ) )
  2056. {
  2057. if ( MSurf_Flags( parentSurfID ) & SURFDRAW_TRANS)
  2058. {
  2059. Shader_TranslucentDisplacementSurface( pRenderList, parentSurfID );
  2060. }
  2061. else
  2062. {
  2063. Shader_DisplacementSurface( pRenderList, parentSurfID );
  2064. }
  2065. }
  2066. }
  2067. }
  2068. int LeafToIndex( mleaf_t* pLeaf );
  2069. //-----------------------------------------------------------------------------
  2070. // Updates visibility + alpha lists
  2071. //-----------------------------------------------------------------------------
  2072. static inline void UpdateVisibleLeafLists( CWorldRenderList *pRenderList, mleaf_t* pLeaf )
  2073. {
  2074. // Consistency check...
  2075. MEM_ALLOC_CREDIT();
  2076. // Add this leaf to the list of visible leafs
  2077. int nLeafIndex = LeafToIndex( pLeaf );
  2078. pRenderList->m_VisibleLeaves.AddToTail( nLeafIndex );
  2079. int leafCount = pRenderList->m_VisibleLeaves.Count();
  2080. pRenderList->m_VisibleLeafFogVolumes.AddToTail( pLeaf->leafWaterDataID );
  2081. pRenderList->m_AlphaSortList.EnsureMaxSortIDs( leafCount );
  2082. pRenderList->m_DispAlphaSortList.EnsureMaxSortIDs( leafCount );
  2083. }
  2084. //-----------------------------------------------------------------------------
  2085. // Draws all displacements + surfaces in a leaf
  2086. //-----------------------------------------------------------------------------
  2087. static void FASTCALL R_DrawLeaf( CWorldRenderList *pRenderList, mleaf_t *pleaf )
  2088. {
  2089. // Add this leaf to the list of visible leaves
  2090. UpdateVisibleLeafLists( pRenderList, pleaf );
  2091. // Debugging to only draw at a particular leaf
  2092. #ifdef USE_CONVARS
  2093. if ( (s_ShaderConvars.m_nDrawLeaf >= 0) && (s_ShaderConvars.m_nDrawLeaf != LeafToIndex(pleaf)) )
  2094. return;
  2095. #endif
  2096. // add displacement surfaces
  2097. DrawDisplacementsInLeaf( pRenderList, pleaf );
  2098. #ifdef USE_CONVARS
  2099. if( !s_ShaderConvars.m_bDrawWorld )
  2100. return;
  2101. #endif
  2102. // Add non-displacement surfaces
  2103. int i;
  2104. int nSurfaceCount = pleaf->nummarknodesurfaces;
  2105. SurfaceHandle_t *pSurfID = &host_state.worldbrush->marksurfaces[pleaf->firstmarksurface];
  2106. CVisitedSurfs &visitedSurfs = pRenderList->m_VisitedSurfs;
  2107. for ( i = 0; i < nSurfaceCount; ++i )
  2108. {
  2109. // garymctoptimize - can we prefetch the next surfaces?
  2110. // We seem to be taking a huge hit here for referencing the surface for the first time.
  2111. SurfaceHandle_t surfID = pSurfID[i];
  2112. ASSERT_SURF_VALID( surfID );
  2113. // there are never any displacements or nodraws in the leaf list
  2114. Assert( !(MSurf_Flags( surfID ) & SURFDRAW_NODRAW) );
  2115. Assert( (MSurf_Flags( surfID ) & SURFDRAW_NODE) );
  2116. Assert( !SurfaceHasDispInfo(surfID) );
  2117. // mark this one to be drawn at the node
  2118. MarkSurfaceVisited( visitedSurfs, surfID );
  2119. }
  2120. #ifdef USE_CONVARS
  2121. if( !s_ShaderConvars.m_bDrawFuncDetail )
  2122. return;
  2123. #endif
  2124. for ( ; i < pleaf->nummarksurfaces; i++ )
  2125. {
  2126. SurfaceHandle_t surfID = pSurfID[i];
  2127. // Don't process the same surface twice
  2128. if ( !VisitSurface( visitedSurfs, surfID ) )
  2129. continue;
  2130. Assert( !(MSurf_Flags( surfID ) & SURFDRAW_NODE) );
  2131. // Back face cull; only func_detail are drawn here
  2132. if ( (MSurf_Flags( surfID ) & SURFDRAW_NOCULL) == 0 )
  2133. {
  2134. if ( (DotProduct(MSurf_Plane( surfID ).normal, modelorg) -
  2135. MSurf_Plane( surfID ).dist ) < BACKFACE_EPSILON )
  2136. continue;
  2137. }
  2138. R_DrawSurface( pRenderList, surfID );
  2139. }
  2140. }
  2141. static ConVar r_frustumcullworld( "r_frustumcullworld", "1" );
  2142. static void FASTCALL R_DrawLeafNoCull( CWorldRenderList *pRenderList, mleaf_t *pleaf )
  2143. {
  2144. // Add this leaf to the list of visible leaves
  2145. UpdateVisibleLeafLists( pRenderList, pleaf );
  2146. // add displacement surfaces
  2147. DrawDisplacementsInLeaf( pRenderList, pleaf );
  2148. int i;
  2149. SurfaceHandle_t *pSurfID = &host_state.worldbrush->marksurfaces[pleaf->firstmarksurface];
  2150. CVisitedSurfs &visitedSurfs = pRenderList->m_VisitedSurfs;
  2151. for ( i = 0; i < pleaf->nummarksurfaces; i++ )
  2152. {
  2153. SurfaceHandle_t surfID = pSurfID[i];
  2154. // Don't process the same surface twice
  2155. if ( !VisitSurface( visitedSurfs, surfID ) )
  2156. continue;
  2157. R_DrawSurfaceNoCull( pRenderList, surfID );
  2158. }
  2159. }
  2160. //-----------------------------------------------------------------------------
  2161. // Purpose: recurse on the BSP tree, calling the surface visitor
  2162. // Input : *node - BSP node
  2163. //-----------------------------------------------------------------------------
  2164. static void R_RecursiveWorldNodeNoCull( CWorldRenderList *pRenderList, mnode_t *node, int nCullMask )
  2165. {
  2166. int side;
  2167. cplane_t *plane;
  2168. float dot;
  2169. while (true)
  2170. {
  2171. // no polygons in solid nodes
  2172. if (node->contents == CONTENTS_SOLID)
  2173. return; // solid
  2174. // Check PVS signature
  2175. if (node->visframe != r_visframecount)
  2176. return;
  2177. // Cull against the screen frustum or the appropriate area's frustum.
  2178. if ( nCullMask != FRUSTUM_SUPPRESS_CLIPPING )
  2179. {
  2180. if (node->contents >= -1)
  2181. {
  2182. if ((nCullMask != 0) || ( node->area > 0 ))
  2183. {
  2184. if ( R_CullNode( &g_Frustum, node, nCullMask ) )
  2185. return;
  2186. }
  2187. }
  2188. else
  2189. {
  2190. // This prevents us from culling nodes that are too small to worry about
  2191. if (node->contents == -2)
  2192. {
  2193. nCullMask = FRUSTUM_SUPPRESS_CLIPPING;
  2194. }
  2195. }
  2196. }
  2197. // if a leaf node, draw stuff
  2198. if (node->contents >= 0)
  2199. {
  2200. R_DrawLeafNoCull( pRenderList, (mleaf_t *)node );
  2201. return;
  2202. }
  2203. // node is just a decision point, so go down the appropriate sides
  2204. // find which side of the node we are on
  2205. plane = node->plane;
  2206. if ( plane->type <= PLANE_Z )
  2207. {
  2208. dot = modelorg[plane->type] - plane->dist;
  2209. }
  2210. else
  2211. {
  2212. dot = DotProduct (modelorg, plane->normal) - plane->dist;
  2213. }
  2214. // recurse down the children, closer side first.
  2215. // We have to do this because we need to find if the surfaces at this node
  2216. // exist in any visible leaves closer to the camera than the node is. If so,
  2217. // their r_surfacevisframe is set to indicate that we need to render them
  2218. // at this node.
  2219. side = dot >= 0 ? 0 : 1;
  2220. // Recurse down the side closer to the camera
  2221. R_RecursiveWorldNodeNoCull (pRenderList, node->children[side], nCullMask );
  2222. // recurse down the side farther from the camera
  2223. // NOTE: With this while loop, this is identical to just calling
  2224. // R_RecursiveWorldNodeNoCull (node->children[!side], nCullMask );
  2225. node = node->children[!side];
  2226. }
  2227. }
  2228. //-----------------------------------------------------------------------------
  2229. // Purpose: recurse on the BSP tree, calling the surface visitor
  2230. // Input : *node - BSP node
  2231. //-----------------------------------------------------------------------------
  2232. static void R_RecursiveWorldNode( CWorldRenderList *pRenderList, mnode_t *node, int nCullMask )
  2233. {
  2234. int side;
  2235. cplane_t *plane;
  2236. float dot;
  2237. while (true)
  2238. {
  2239. // no polygons in solid nodes
  2240. if (node->contents == CONTENTS_SOLID)
  2241. return; // solid
  2242. // Check PVS signature
  2243. if (node->visframe != r_visframecount)
  2244. return;
  2245. // Cull against the screen frustum or the appropriate area's frustum.
  2246. if ( nCullMask != FRUSTUM_SUPPRESS_CLIPPING )
  2247. {
  2248. if (node->contents >= -1)
  2249. {
  2250. if ((nCullMask != 0) || ( node->area > 0 ))
  2251. {
  2252. if ( R_CullNode( &g_Frustum, node, nCullMask ) )
  2253. return;
  2254. }
  2255. }
  2256. else
  2257. {
  2258. // This prevents us from culling nodes that are too small to worry about
  2259. if (node->contents == -2)
  2260. {
  2261. nCullMask = FRUSTUM_SUPPRESS_CLIPPING;
  2262. }
  2263. }
  2264. }
  2265. // if a leaf node, draw stuff
  2266. if (node->contents >= 0)
  2267. {
  2268. R_DrawLeaf( pRenderList, (mleaf_t *)node );
  2269. return;
  2270. }
  2271. // node is just a decision point, so go down the appropriate sides
  2272. // find which side of the node we are on
  2273. plane = node->plane;
  2274. if ( plane->type <= PLANE_Z )
  2275. {
  2276. dot = modelorg[plane->type] - plane->dist;
  2277. }
  2278. else
  2279. {
  2280. dot = DotProduct (modelorg, plane->normal) - plane->dist;
  2281. }
  2282. // recurse down the children, closer side first.
  2283. // We have to do this because we need to find if the surfaces at this node
  2284. // exist in any visible leaves closer to the camera than the node is. If so,
  2285. // their r_surfacevisframe is set to indicate that we need to render them
  2286. // at this node.
  2287. side = dot >= 0 ? 0 : 1;
  2288. // Recurse down the side closer to the camera
  2289. R_RecursiveWorldNode (pRenderList, node->children[side], nCullMask );
  2290. // draw stuff on the node
  2291. SurfaceHandle_t surfID = SurfaceHandleFromIndex( node->firstsurface );
  2292. int i = MSurf_Index( surfID );
  2293. int nLastSurface = i + node->numsurfaces;
  2294. CVisitedSurfs &visitedSurfs = pRenderList->m_VisitedSurfs;
  2295. for ( ; i < nLastSurface; ++i, ++surfID )
  2296. {
  2297. // Only render things at this node that have previously been marked as visible
  2298. if ( !VisitedSurface( visitedSurfs, i ) )
  2299. continue;
  2300. // Don't add surfaces that have displacement
  2301. // UNDONE: Don't emit these at nodes in vbsp!
  2302. // UNDONE: Emit them at the end of the surface list
  2303. Assert( !SurfaceHasDispInfo( surfID ) );
  2304. // If a surface is marked to draw at a node, then it's not a func_detail.
  2305. // Only func_detail render at leaves. In the case of normal world surfaces,
  2306. // we only want to render them if they intersect a visible leaf.
  2307. int nFlags = MSurf_Flags( surfID );
  2308. Assert( nFlags & SURFDRAW_NODE );
  2309. Assert( !(nFlags & SURFDRAW_NODRAW) );
  2310. if ( !(nFlags & SURFDRAW_UNDERWATER) && ( side ^ !!(nFlags & SURFDRAW_PLANEBACK)) )
  2311. continue; // wrong side
  2312. R_DrawSurface( pRenderList, surfID );
  2313. }
  2314. // recurse down the side farther from the camera
  2315. // NOTE: With this while loop, this is identical to just calling
  2316. // R_RecursiveWorldNode (node->children[!side], nCullMask );
  2317. node = node->children[!side];
  2318. }
  2319. }
  2320. //-----------------------------------------------------------------------------
  2321. // Set up fog for a particular leaf
  2322. //-----------------------------------------------------------------------------
  2323. #define INVALID_WATER_HEIGHT 1000000.0f
  2324. inline float R_GetWaterHeight( int nFogVolume )
  2325. {
  2326. if( nFogVolume < 0 || nFogVolume > host_state.worldbrush->numleafwaterdata )
  2327. return INVALID_WATER_HEIGHT;
  2328. mleafwaterdata_t* pLeafWaterData = &host_state.worldbrush->leafwaterdata[nFogVolume];
  2329. return pLeafWaterData->surfaceZ;
  2330. }
  2331. IMaterial *R_GetFogVolumeMaterial( int nFogVolume, bool bEyeInFogVolume )
  2332. {
  2333. if( nFogVolume < 0 || nFogVolume > host_state.worldbrush->numleafwaterdata )
  2334. return NULL;
  2335. mleafwaterdata_t* pLeafWaterData = &host_state.worldbrush->leafwaterdata[nFogVolume];
  2336. mtexinfo_t* pTexInfo = &host_state.worldbrush->texinfo[pLeafWaterData->surfaceTexInfoID];
  2337. IMaterial* pMaterial = pTexInfo->material;
  2338. if( bEyeInFogVolume )
  2339. {
  2340. IMaterialVar *pVar = pMaterial->FindVar( "$bottommaterial", NULL );
  2341. if( pVar )
  2342. {
  2343. const char *pMaterialName = pVar->GetStringValue();
  2344. if( pMaterialName )
  2345. {
  2346. pMaterial = materials->FindMaterial( pMaterialName, TEXTURE_GROUP_OTHER );
  2347. }
  2348. }
  2349. }
  2350. return pMaterial;
  2351. }
  2352. void R_SetFogVolumeState( int fogVolume, bool useHeightFog )
  2353. {
  2354. // useHeightFog == eye out of water
  2355. // !useHeightFog == eye in water
  2356. IMaterial *pMaterial = R_GetFogVolumeMaterial( fogVolume, !useHeightFog );
  2357. mleafwaterdata_t* pLeafWaterData = &host_state.worldbrush->leafwaterdata[fogVolume];
  2358. IMaterialVar* pFogColorVar = pMaterial->FindVar( "$fogcolor", NULL );
  2359. IMaterialVar* pFogEnableVar = pMaterial->FindVar( "$fogenable", NULL );
  2360. IMaterialVar* pFogStartVar = pMaterial->FindVar( "$fogstart", NULL );
  2361. IMaterialVar* pFogEndVar = pMaterial->FindVar( "$fogend", NULL );
  2362. CMatRenderContextPtr pRenderContext( materials );
  2363. if( pMaterial && pFogEnableVar->GetIntValueFast() && fog_enable_water_fog.GetBool() )
  2364. {
  2365. pRenderContext->SetFogZ( pLeafWaterData->surfaceZ );
  2366. if( useHeightFog )
  2367. {
  2368. pRenderContext->FogMode( MATERIAL_FOG_LINEAR_BELOW_FOG_Z );
  2369. }
  2370. else
  2371. {
  2372. pRenderContext->FogMode( MATERIAL_FOG_LINEAR );
  2373. }
  2374. float fogColor[3];
  2375. pFogColorVar->GetVecValueFast( fogColor, 3 );
  2376. pRenderContext->FogColor3fv( fogColor );
  2377. pRenderContext->FogStart( pFogStartVar->GetFloatValueFast() );
  2378. pRenderContext->FogEnd( pFogEndVar->GetFloatValueFast() );
  2379. pRenderContext->FogMaxDensity( 1.0 );
  2380. }
  2381. else
  2382. {
  2383. pRenderContext->FogMode( MATERIAL_FOG_NONE );
  2384. }
  2385. }
  2386. static inline bool R_CullNodeTopView( mnode_t *pNode )
  2387. {
  2388. Vector2D delta, size;
  2389. Vector2DSubtract( pNode->m_vecCenter.AsVector2D(), s_OrthographicCenter, delta );
  2390. Vector2DAdd( pNode->m_vecHalfDiagonal.AsVector2D(), s_OrthographicHalfDiagonal, size );
  2391. return ( FloatMakePositive( delta.x ) > size.x ) ||
  2392. ( FloatMakePositive( delta.y ) > size.y );
  2393. }
  2394. //-----------------------------------------------------------------------------
  2395. // Draws all displacements + surfaces in a leaf
  2396. //-----------------------------------------------------------------------------
  2397. static void R_DrawTopViewLeaf( CWorldRenderList *pRenderList, mleaf_t *pleaf )
  2398. {
  2399. // Add this leaf to the list of visible leaves
  2400. UpdateVisibleLeafLists( pRenderList, pleaf );
  2401. // add displacement surfaces
  2402. DrawDisplacementsInLeaf( pRenderList, pleaf );
  2403. #ifdef USE_CONVARS
  2404. if( !s_ShaderConvars.m_bDrawWorld )
  2405. return;
  2406. #endif
  2407. // Add non-displacement surfaces
  2408. SurfaceHandle_t *pHandle = &host_state.worldbrush->marksurfaces[pleaf->firstmarksurface];
  2409. CVisitedSurfs &visitedSurfs = pRenderList->m_VisitedSurfs;
  2410. for ( int i = 0; i < pleaf->nummarksurfaces; i++ )
  2411. {
  2412. SurfaceHandle_t surfID = pHandle[i];
  2413. // Mark this surface as being in a visible leaf this frame. If this
  2414. // surface is meant to be drawn at a node (SURFDRAW_NODE),
  2415. // then it will be drawn in the recursive code down below.
  2416. if ( !VisitSurface( visitedSurfs, surfID ) )
  2417. continue;
  2418. // Don't add surfaces that have displacement; they are handled above
  2419. // In fact, don't even set the vis frame; we need it unset for translucent
  2420. // displacement code
  2421. if ( SurfaceHasDispInfo(surfID) )
  2422. continue;
  2423. if ( MSurf_Flags( surfID ) & SURFDRAW_NODE )
  2424. continue;
  2425. Assert( !(MSurf_Flags( surfID ) & SURFDRAW_NODRAW) );
  2426. // Back face cull; only func_detail are drawn here
  2427. if ( (MSurf_Flags( surfID ) & SURFDRAW_NOCULL) == 0 )
  2428. {
  2429. if (MSurf_Plane( surfID ).normal.z <= 0.0f)
  2430. continue;
  2431. }
  2432. // FIXME: For now, blow off translucent world polygons.
  2433. // Gotta solve the problem of how to render them all, unsorted,
  2434. // in a pass after the opaque world polygons, and before the
  2435. // translucent entities.
  2436. if ( !( MSurf_Flags( surfID ) & SURFDRAW_TRANS ))
  2437. // if ( !surf->texinfo->material->IsTranslucent() )
  2438. Shader_WorldSurface( pRenderList, surfID );
  2439. }
  2440. }
  2441. //-----------------------------------------------------------------------------
  2442. // Fast path for rendering top-views
  2443. //-----------------------------------------------------------------------------
  2444. void R_RenderWorldTopView( CWorldRenderList *pRenderList, mnode_t *node )
  2445. {
  2446. CVisitedSurfs &visitedSurfs = pRenderList->m_VisitedSurfs;
  2447. do
  2448. {
  2449. // no polygons in solid nodes
  2450. if (node->contents == CONTENTS_SOLID)
  2451. return; // solid
  2452. // Check PVS signature
  2453. if (node->visframe != r_visframecount)
  2454. return;
  2455. // Cull against the screen frustum or the appropriate area's frustum.
  2456. if( R_CullNodeTopView( node ) )
  2457. return;
  2458. // if a leaf node, draw stuff
  2459. if (node->contents >= 0)
  2460. {
  2461. R_DrawTopViewLeaf( pRenderList, (mleaf_t *)node );
  2462. return;
  2463. }
  2464. #ifdef USE_CONVARS
  2465. if (s_ShaderConvars.m_bDrawWorld)
  2466. #endif
  2467. {
  2468. // draw stuff on the node
  2469. SurfaceHandle_t surfID = SurfaceHandleFromIndex( node->firstsurface );
  2470. for ( int i = 0; i < node->numsurfaces; i++, surfID++ )
  2471. {
  2472. if ( !VisitSurface( visitedSurfs, surfID ) )
  2473. continue;
  2474. // Don't add surfaces that have displacement
  2475. if ( SurfaceHasDispInfo( surfID ) )
  2476. continue;
  2477. // If a surface is marked to draw at a node, then it's not a func_detail.
  2478. // Only func_detail render at leaves. In the case of normal world surfaces,
  2479. // we only want to render them if they intersect a visible leaf.
  2480. Assert( (MSurf_Flags( surfID ) & SURFDRAW_NODE) );
  2481. if ( MSurf_Flags( surfID ) & (SURFDRAW_UNDERWATER|SURFDRAW_SKY) )
  2482. continue;
  2483. Assert( !(MSurf_Flags( surfID ) & SURFDRAW_NODRAW) );
  2484. // Back face cull
  2485. if ( (MSurf_Flags( surfID ) & SURFDRAW_NOCULL) == 0 )
  2486. {
  2487. if (MSurf_Plane( surfID ).normal.z <= 0.0f)
  2488. continue;
  2489. }
  2490. // FIXME: For now, blow off translucent world polygons.
  2491. // Gotta solve the problem of how to render them all, unsorted,
  2492. // in a pass after the opaque world polygons, and before the
  2493. // translucent entities.
  2494. if ( !( MSurf_Flags( surfID ) & SURFDRAW_TRANS ) )
  2495. // if ( !surf->texinfo->material->IsTranslucent() )
  2496. Shader_WorldSurface( pRenderList, surfID );
  2497. }
  2498. }
  2499. // Recurse down both children, we don't care the order...
  2500. R_RenderWorldTopView ( pRenderList, node->children[0]);
  2501. node = node->children[1];
  2502. } while (node);
  2503. }
  2504. //-----------------------------------------------------------------------------
  2505. // Spews the leaf we're in
  2506. //-----------------------------------------------------------------------------
  2507. static void SpewLeaf()
  2508. {
  2509. int leaf = CM_PointLeafnum( g_EngineRenderer->ViewOrigin() );
  2510. ConMsg( "view leaf %d\n", leaf );
  2511. }
  2512. //-----------------------------------------------------------------------------
  2513. // Main entry points for starting + ending rendering the world
  2514. //-----------------------------------------------------------------------------
  2515. void R_BuildWorldLists( IWorldRenderList *pRenderListIn, WorldListInfo_t* pInfo,
  2516. int iForceViewLeaf, const VisOverrideData_t* pVisData, bool bShadowDepth /* = false */, float *pWaterReflectionHeight )
  2517. {
  2518. CWorldRenderList *pRenderList = assert_cast<CWorldRenderList *>(pRenderListIn);
  2519. // Safety measure just in case. I haven't seen that we need this, but...
  2520. if ( g_LostVideoMemory )
  2521. {
  2522. if (pInfo)
  2523. {
  2524. pInfo->m_ViewFogVolume = MAT_SORT_GROUP_STRICTLY_ABOVEWATER;
  2525. pInfo->m_LeafCount = 0;
  2526. pInfo->m_pLeafList = pRenderList->m_VisibleLeaves.Base();
  2527. pInfo->m_pLeafFogVolume = pRenderList->m_VisibleLeafFogVolumes.Base();
  2528. }
  2529. return;
  2530. }
  2531. VPROF( "R_BuildWorldLists" );
  2532. VectorCopy( g_EngineRenderer->ViewOrigin(), modelorg );
  2533. #ifdef USE_CONVARS
  2534. static ConVar r_spewleaf("r_spewleaf", "0");
  2535. if ( r_spewleaf.GetInt() )
  2536. {
  2537. SpewLeaf();
  2538. }
  2539. #endif
  2540. Shader_WorldBegin( pRenderList );
  2541. if ( !r_drawtopview )
  2542. {
  2543. R_SetupAreaBits( iForceViewLeaf, pVisData, pWaterReflectionHeight );
  2544. if ( bShadowDepth )
  2545. {
  2546. R_RecursiveWorldNodeNoCull( pRenderList, host_state.worldbrush->nodes, r_frustumcullworld.GetBool() ? FRUSTUM_CLIP_ALL : FRUSTUM_SUPPRESS_CLIPPING );
  2547. }
  2548. else
  2549. {
  2550. R_RecursiveWorldNode( pRenderList, host_state.worldbrush->nodes, r_frustumcullworld.GetBool() ? FRUSTUM_CLIP_ALL : FRUSTUM_SUPPRESS_CLIPPING );
  2551. }
  2552. }
  2553. else
  2554. {
  2555. R_RenderWorldTopView( pRenderList, host_state.worldbrush->nodes );
  2556. }
  2557. // This builds all lightmaps, including those for translucent surfaces
  2558. // Don't bother in topview?
  2559. if ( !r_drawtopview && !bShadowDepth )
  2560. {
  2561. Shader_BuildDynamicLightmaps( pRenderList );
  2562. }
  2563. // Return the back-to-front leaf ordering
  2564. if ( pInfo )
  2565. {
  2566. // Compute fog volume info for rendering
  2567. if ( !bShadowDepth )
  2568. {
  2569. FogVolumeInfo_t fogInfo;
  2570. ComputeFogVolumeInfo( &fogInfo );
  2571. if( fogInfo.m_InFogVolume )
  2572. {
  2573. pInfo->m_ViewFogVolume = MAT_SORT_GROUP_STRICTLY_UNDERWATER;
  2574. }
  2575. else
  2576. {
  2577. pInfo->m_ViewFogVolume = MAT_SORT_GROUP_STRICTLY_ABOVEWATER;
  2578. }
  2579. }
  2580. else
  2581. {
  2582. pInfo->m_ViewFogVolume = MAT_SORT_GROUP_STRICTLY_ABOVEWATER;
  2583. }
  2584. pInfo->m_LeafCount = pRenderList->m_VisibleLeaves.Count();
  2585. pInfo->m_pLeafList = pRenderList->m_VisibleLeaves.Base();
  2586. pInfo->m_pLeafFogVolume = pRenderList->m_VisibleLeafFogVolumes.Base();
  2587. }
  2588. }
  2589. //-----------------------------------------------------------------------------
  2590. // Used to determine visible fog volumes
  2591. //-----------------------------------------------------------------------------
  2592. class CVisibleFogVolumeQuery
  2593. {
  2594. public:
  2595. void FindVisibleFogVolume( const Vector &vecViewPoint, int *pVisibleFogVolume, int *pVisibleFogVolumeLeaf );
  2596. private:
  2597. bool RecursiveGetVisibleFogVolume( mnode_t *node );
  2598. // Input
  2599. Vector m_vecSearchPoint;
  2600. // Output
  2601. int m_nVisibleFogVolume;
  2602. int m_nVisibleFogVolumeLeaf;
  2603. };
  2604. //-----------------------------------------------------------------------------
  2605. // Main entry point for the query
  2606. //-----------------------------------------------------------------------------
  2607. void CVisibleFogVolumeQuery::FindVisibleFogVolume( const Vector &vecViewPoint, int *pVisibleFogVolume, int *pVisibleFogVolumeLeaf )
  2608. {
  2609. R_SetupAreaBits();
  2610. m_vecSearchPoint = vecViewPoint;
  2611. m_nVisibleFogVolume = -1;
  2612. m_nVisibleFogVolumeLeaf = -1;
  2613. RecursiveGetVisibleFogVolume( host_state.worldbrush->nodes );
  2614. *pVisibleFogVolume = m_nVisibleFogVolume;
  2615. *pVisibleFogVolumeLeaf = m_nVisibleFogVolumeLeaf;
  2616. }
  2617. //-----------------------------------------------------------------------------
  2618. // return true to continue searching
  2619. //-----------------------------------------------------------------------------
  2620. bool CVisibleFogVolumeQuery::RecursiveGetVisibleFogVolume( mnode_t *node )
  2621. {
  2622. int side;
  2623. cplane_t *plane;
  2624. float dot;
  2625. // no polygons in solid nodes
  2626. if (node->contents == CONTENTS_SOLID)
  2627. return true; // solid
  2628. // Check PVS signature
  2629. if (node->visframe != r_visframecount)
  2630. return true;
  2631. // Cull against the screen frustum or the appropriate area's frustum.
  2632. int fixmeTempRemove = FRUSTUM_CLIP_ALL;
  2633. if( R_CullNode( &g_Frustum, node, fixmeTempRemove ) )
  2634. return true;
  2635. // if a leaf node, check if we are in a fog volume and get outta here.
  2636. if (node->contents >= 0)
  2637. {
  2638. mleaf_t *pLeaf = (mleaf_t *)node;
  2639. // Don't return a leaf that's not filled with liquid
  2640. if ( pLeaf->leafWaterDataID == -1 )
  2641. return true;
  2642. // Never return SLIME as being visible, as it's opaque
  2643. if ( pLeaf->contents & CONTENTS_SLIME )
  2644. return true;
  2645. m_nVisibleFogVolume = pLeaf->leafWaterDataID;
  2646. m_nVisibleFogVolumeLeaf = pLeaf - host_state.worldbrush->leafs;
  2647. return false; // found it, so stop searching
  2648. }
  2649. // node is just a decision point, so go down the apropriate sides
  2650. // find which side of the node we are on
  2651. plane = node->plane;
  2652. if ( plane->type <= PLANE_Z )
  2653. {
  2654. dot = m_vecSearchPoint[plane->type] - plane->dist;
  2655. }
  2656. else
  2657. {
  2658. dot = DotProduct( m_vecSearchPoint, plane->normal ) - plane->dist;
  2659. }
  2660. // recurse down the children, closer side first.
  2661. // We have to do this because we need to find if the surfaces at this node
  2662. // exist in any visible leaves closer to the camera than the node is. If so,
  2663. // their r_surfacevisframe is set to indicate that we need to render them
  2664. // at this node.
  2665. side = (dot >= 0) ? 0 : 1;
  2666. // Recurse down the side closer to the camera
  2667. if( !RecursiveGetVisibleFogVolume (node->children[side]) )
  2668. return false;
  2669. // recurse down the side farther from the camera
  2670. return RecursiveGetVisibleFogVolume (node->children[!side]);
  2671. }
  2672. static void ClearFogInfo( VisibleFogVolumeInfo_t *pInfo )
  2673. {
  2674. pInfo->m_bEyeInFogVolume = false;
  2675. pInfo->m_nVisibleFogVolume = -1;
  2676. pInfo->m_nVisibleFogVolumeLeaf = -1;
  2677. pInfo->m_pFogVolumeMaterial = NULL;
  2678. pInfo->m_flWaterHeight = INVALID_WATER_HEIGHT;
  2679. }
  2680. ConVar fast_fogvolume("fast_fogvolume", "0");
  2681. //-----------------------------------------------------------------------------
  2682. // Main entry point from renderer to get the fog volume
  2683. //-----------------------------------------------------------------------------
  2684. void R_GetVisibleFogVolume( const Vector& vEyePoint, VisibleFogVolumeInfo_t *pInfo )
  2685. {
  2686. VPROF_BUDGET( "R_GetVisibleFogVolume", VPROF_BUDGETGROUP_WORLD_RENDERING );
  2687. if ( host_state.worldmodel->brush.pShared->numleafwaterdata == 0 )
  2688. {
  2689. ClearFogInfo( pInfo );
  2690. return;
  2691. }
  2692. int nLeafID = CM_PointLeafnum( vEyePoint );
  2693. mleaf_t* pLeaf = &host_state.worldbrush->leafs[nLeafID];
  2694. int nLeafContents = pLeaf->contents;
  2695. if ( pLeaf->leafWaterDataID != -1 )
  2696. {
  2697. Assert( nLeafContents & (CONTENTS_SLIME | CONTENTS_WATER) );
  2698. pInfo->m_bEyeInFogVolume = true;
  2699. pInfo->m_nVisibleFogVolume = pLeaf->leafWaterDataID;
  2700. pInfo->m_nVisibleFogVolumeLeaf = nLeafID;
  2701. pInfo->m_pFogVolumeMaterial = R_GetFogVolumeMaterial( pInfo->m_nVisibleFogVolume, true );
  2702. pInfo->m_flWaterHeight = R_GetWaterHeight( pInfo->m_nVisibleFogVolume );
  2703. }
  2704. else if ( nLeafContents & CONTENTS_TESTFOGVOLUME )
  2705. {
  2706. Assert( (nLeafContents & (CONTENTS_SLIME | CONTENTS_WATER)) == 0 );
  2707. if ( fast_fogvolume.GetBool() && host_state.worldbrush->numleafwaterdata == 1 )
  2708. {
  2709. pInfo->m_nVisibleFogVolume = 0;
  2710. pInfo->m_nVisibleFogVolumeLeaf = host_state.worldbrush->leafwaterdata[0].firstLeafIndex;
  2711. }
  2712. else
  2713. {
  2714. CVisibleFogVolumeQuery query;
  2715. query.FindVisibleFogVolume( vEyePoint, &pInfo->m_nVisibleFogVolume, &pInfo->m_nVisibleFogVolumeLeaf );
  2716. }
  2717. pInfo->m_bEyeInFogVolume = false;
  2718. pInfo->m_pFogVolumeMaterial = R_GetFogVolumeMaterial( pInfo->m_nVisibleFogVolume, false );
  2719. pInfo->m_flWaterHeight = R_GetWaterHeight( pInfo->m_nVisibleFogVolume );
  2720. }
  2721. else
  2722. {
  2723. ClearFogInfo( pInfo );
  2724. }
  2725. if( host_state.worldbrush->m_LeafMinDistToWater )
  2726. {
  2727. pInfo->m_flDistanceToWater = ( float )host_state.worldbrush->m_LeafMinDistToWater[nLeafID];
  2728. }
  2729. else
  2730. {
  2731. pInfo->m_flDistanceToWater = 0.0f;
  2732. }
  2733. }
  2734. //-----------------------------------------------------------------------------
  2735. // Draws the list of surfaces build in the BuildWorldLists phase
  2736. //-----------------------------------------------------------------------------
  2737. // Uncomment this to allow code to draw wireframe over a particular surface for debugging
  2738. //#define DEBUG_SURF 1
  2739. #ifdef DEBUG_SURF
  2740. int g_DebugSurfIndex = -1;
  2741. #endif
  2742. void R_DrawWorldLists( IWorldRenderList *pRenderListIn, unsigned long flags, float waterZAdjust )
  2743. {
  2744. CWorldRenderList *pRenderList = assert_cast<CWorldRenderList *>(pRenderListIn);
  2745. if ( g_bTextMode || g_LostVideoMemory )
  2746. return;
  2747. VPROF("R_DrawWorldLists");
  2748. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  2749. Shader_WorldEnd( pRenderList, flags, waterZAdjust );
  2750. #ifdef DEBUG_SURF
  2751. {
  2752. VPROF("R_DrawWorldLists (DEBUG_SURF)");
  2753. if (g_pDebugSurf)
  2754. {
  2755. CMatRenderContextPtr pRenderContext( materials );
  2756. pRenderContext->Bind( g_materialWorldWireframe );
  2757. Shader_DrawSurfaceDynamic( pRenderContext, g_pDebugSurf, false );
  2758. }
  2759. }
  2760. #endif
  2761. }
  2762. //-----------------------------------------------------------------------------
  2763. // Purpose:
  2764. //-----------------------------------------------------------------------------
  2765. void R_SceneBegin( void )
  2766. {
  2767. ComputeDebugSettings();
  2768. }
  2769. void R_SceneEnd( void )
  2770. {
  2771. }
  2772. //-----------------------------------------------------------------------------
  2773. // Debugging code to draw the lightmap pages
  2774. //-----------------------------------------------------------------------------
  2775. void Shader_DrawLightmapPageSurface( SurfaceHandle_t surfID, float red, float green, float blue )
  2776. {
  2777. Vector2D lightCoords[32][4];
  2778. int bumpID, count;
  2779. if ( MSurf_Flags( surfID ) & SURFDRAW_BUMPLIGHT )
  2780. {
  2781. count = NUM_BUMP_VECTS + 1;
  2782. }
  2783. else
  2784. {
  2785. count = 1;
  2786. }
  2787. BuildMSurfaceVerts( host_state.worldbrush, surfID, NULL, NULL, lightCoords );
  2788. int lightmapPageWidth, lightmapPageHeight;
  2789. CMatRenderContextPtr pRenderContext( materials );
  2790. pRenderContext->Bind( g_materialWireframe );
  2791. materials->GetLightmapPageSize(
  2792. SortInfoToLightmapPage(MSurf_MaterialSortID( surfID )),
  2793. &lightmapPageWidth, &lightmapPageHeight );
  2794. for( bumpID = 0; bumpID < count; bumpID++ )
  2795. {
  2796. // assumes that we are already in ortho mode.
  2797. IMesh* pMesh = pRenderContext->GetDynamicMesh( );
  2798. CMeshBuilder meshBuilder;
  2799. meshBuilder.Begin( pMesh, MATERIAL_LINES, MSurf_VertCount( surfID ) );
  2800. int i;
  2801. for( i = 0; i < MSurf_VertCount( surfID ); i++ )
  2802. {
  2803. float x, y;
  2804. float *texCoord;
  2805. texCoord = &lightCoords[i][bumpID][0];
  2806. x = lightmapPageWidth * texCoord[0];
  2807. y = lightmapPageHeight * texCoord[1];
  2808. #ifdef _XBOX
  2809. // xboxissue - border safe
  2810. x += 32;
  2811. y += 32;
  2812. #endif
  2813. meshBuilder.Position3f( x, y, 0.0f );
  2814. meshBuilder.AdvanceVertex();
  2815. texCoord = &lightCoords[(i+1)%MSurf_VertCount( surfID )][bumpID][0];
  2816. x = lightmapPageWidth * texCoord[0];
  2817. y = lightmapPageHeight * texCoord[1];
  2818. #ifdef _XBOX
  2819. // xboxissue - border safe
  2820. x += 32;
  2821. y += 32;
  2822. #endif
  2823. meshBuilder.Position3f( x, y, 0.0f );
  2824. meshBuilder.AdvanceVertex();
  2825. }
  2826. meshBuilder.End();
  2827. pMesh->Draw();
  2828. }
  2829. }
  2830. void Shader_DrawLightmapPageChains( IWorldRenderList *pRenderListIn, int pageId )
  2831. {
  2832. CWorldRenderList *pRenderList = assert_cast<CWorldRenderList *>(pRenderListIn);
  2833. for (int j = 0; j < MAX_MAT_SORT_GROUPS; ++j)
  2834. {
  2835. MSL_FOREACH_GROUP_BEGIN( pRenderList->m_SortList, j, group )
  2836. {
  2837. SurfaceHandle_t surfID = pRenderList->m_SortList.GetSurfaceAtHead( group );
  2838. Assert(IS_SURF_VALID(surfID));
  2839. Assert( MSurf_MaterialSortID( surfID ) >= 0 && MSurf_MaterialSortID( surfID ) < g_WorldStaticMeshes.Count() );
  2840. if( materialSortInfoArray[MSurf_MaterialSortID( surfID ) ].lightmapPageID != pageId )
  2841. {
  2842. continue;
  2843. }
  2844. MSL_FOREACH_SURFACE_IN_GROUP_BEGIN( pRenderList->m_SortList, group, surfIDList )
  2845. {
  2846. Assert( !SurfaceHasDispInfo( surfIDList ) );
  2847. Shader_DrawLightmapPageSurface( surfIDList, 0.0f, 1.0f, 0.0f );
  2848. }
  2849. MSL_FOREACH_SURFACE_IN_GROUP_END()
  2850. }
  2851. MSL_FOREACH_GROUP_END()
  2852. // render displacement lightmap page info
  2853. MSL_FOREACH_SURFACE_BEGIN(pRenderList->m_DispSortList, j, surfID)
  2854. {
  2855. surfID->pDispInfo->RenderWireframeInLightmapPage( pageId );
  2856. }
  2857. MSL_FOREACH_SURFACE_END()
  2858. }
  2859. }
  2860. //-----------------------------------------------------------------------------
  2861. //
  2862. // All code related to brush model rendering
  2863. //
  2864. //-----------------------------------------------------------------------------
  2865. class CBrushSurface : public IBrushSurface
  2866. {
  2867. public:
  2868. CBrushSurface( SurfaceHandle_t surfID );
  2869. // Computes texture coordinates + lightmap coordinates given a world position
  2870. virtual void ComputeTextureCoordinate( const Vector& worldPos, Vector2D& texCoord );
  2871. virtual void ComputeLightmapCoordinate( const Vector& worldPos, Vector2D& lightmapCoord );
  2872. // Gets the vertex data for this surface
  2873. virtual int GetVertexCount() const;
  2874. virtual void GetVertexData( BrushVertex_t* pVerts );
  2875. // Gets at the material properties for this surface
  2876. virtual IMaterial* GetMaterial();
  2877. private:
  2878. SurfaceHandle_t m_SurfaceID;
  2879. SurfaceCtx_t m_Ctx;
  2880. };
  2881. //-----------------------------------------------------------------------------
  2882. // Constructor
  2883. //-----------------------------------------------------------------------------
  2884. CBrushSurface::CBrushSurface( SurfaceHandle_t surfID ) : m_SurfaceID(surfID)
  2885. {
  2886. Assert(IS_SURF_VALID(surfID));
  2887. SurfSetupSurfaceContext( m_Ctx, surfID );
  2888. }
  2889. //-----------------------------------------------------------------------------
  2890. // Computes texture coordinates + lightmap coordinates given a world position
  2891. //-----------------------------------------------------------------------------
  2892. void CBrushSurface::ComputeTextureCoordinate( const Vector& worldPos, Vector2D& texCoord )
  2893. {
  2894. SurfComputeTextureCoordinate( m_Ctx, m_SurfaceID, worldPos, texCoord );
  2895. }
  2896. void CBrushSurface::ComputeLightmapCoordinate( const Vector& worldPos, Vector2D& lightmapCoord )
  2897. {
  2898. SurfComputeLightmapCoordinate( m_Ctx, m_SurfaceID, worldPos, lightmapCoord );
  2899. }
  2900. //-----------------------------------------------------------------------------
  2901. // Gets the vertex data for this surface
  2902. //-----------------------------------------------------------------------------
  2903. int CBrushSurface::GetVertexCount() const
  2904. {
  2905. if( !SurfaceHasPrims( m_SurfaceID ) )
  2906. {
  2907. // Create a temporary vertex array for the data...
  2908. return MSurf_VertCount( m_SurfaceID );
  2909. }
  2910. else
  2911. {
  2912. // not implemented yet
  2913. Assert(0);
  2914. return 0;
  2915. }
  2916. }
  2917. void CBrushSurface::GetVertexData( BrushVertex_t* pVerts )
  2918. {
  2919. Assert( pVerts );
  2920. if( !SurfaceHasPrims( m_SurfaceID ) )
  2921. {
  2922. // Fill in the vertex data
  2923. BuildBrushModelVertexArray( host_state.worldbrush, m_SurfaceID, pVerts );
  2924. }
  2925. else
  2926. {
  2927. // not implemented yet
  2928. Assert(0);
  2929. }
  2930. }
  2931. //-----------------------------------------------------------------------------
  2932. // Activates fast z reject for displacements
  2933. //-----------------------------------------------------------------------------
  2934. void R_FastZRejectDisplacements( bool bEnable )
  2935. {
  2936. s_bFastZRejectDisplacements = bEnable;
  2937. }
  2938. //-----------------------------------------------------------------------------
  2939. // Gets at the material properties for this surface
  2940. //-----------------------------------------------------------------------------
  2941. IMaterial* CBrushSurface::GetMaterial()
  2942. {
  2943. return MSurf_TexInfo( m_SurfaceID )->material;
  2944. }
  2945. //-----------------------------------------------------------------------------
  2946. // Installs a client-side renderer for brush models
  2947. //-----------------------------------------------------------------------------
  2948. void R_InstallBrushRenderOverride( IBrushRenderer* pBrushRenderer )
  2949. {
  2950. s_pBrushRenderOverride = pBrushRenderer;
  2951. }
  2952. //-----------------------------------------------------------------------------
  2953. // Here, we allow the client DLL to render brush surfaces however they'd like
  2954. // NOTE: This involves a vertex copy, so don't use this everywhere
  2955. //-----------------------------------------------------------------------------
  2956. bool Shader_DrawBrushSurfaceOverride( IMatRenderContext *pRenderContext, SurfaceHandle_t surfID, IClientEntity *baseentity )
  2957. {
  2958. // Set the lightmap state
  2959. Shader_SetChainLightmapState( pRenderContext, surfID );
  2960. CBrushSurface brushSurface( surfID );
  2961. return s_pBrushRenderOverride->RenderBrushModelSurface( baseentity, &brushSurface );
  2962. }
  2963. FORCEINLINE void ModulateMaterial( IMaterial *pMaterial, float *pOldColor )
  2964. {
  2965. if ( g_bIsBlendingOrModulating )
  2966. {
  2967. pOldColor[3] = pMaterial->GetAlphaModulation( );
  2968. pMaterial->GetColorModulation( &pOldColor[0], &pOldColor[1], &pOldColor[2] );
  2969. pMaterial->AlphaModulate( r_blend );
  2970. pMaterial->ColorModulate( r_colormod[0], r_colormod[1], r_colormod[2] );
  2971. }
  2972. }
  2973. FORCEINLINE void UnModulateMaterial( IMaterial *pMaterial, float *pOldColor )
  2974. {
  2975. if ( g_bIsBlendingOrModulating )
  2976. {
  2977. pMaterial->AlphaModulate( pOldColor[3] );
  2978. pMaterial->ColorModulate( pOldColor[0], pOldColor[1], pOldColor[2] );
  2979. }
  2980. }
  2981. //-----------------------------------------------------------------------------
  2982. // Main method to draw brush surfaces
  2983. //-----------------------------------------------------------------------------
  2984. void Shader_BrushSurface( SurfaceHandle_t surfID, model_t *model, IClientEntity *baseentity )
  2985. {
  2986. CMatRenderContextPtr pRenderContext(materials);
  2987. float pOldColor[4];
  2988. bool drawDecals;
  2989. if (!s_pBrushRenderOverride)
  2990. {
  2991. drawDecals = true;
  2992. IMaterial *pMaterial = MSurf_TexInfo( surfID )->material;
  2993. ModulateMaterial( pMaterial, pOldColor );
  2994. Shader_SetChainTextureState( pRenderContext, surfID, baseentity, false );
  2995. // NOTE: Since a static vb/dynamic ib IMesh doesn't buffer, we shouldn't use this
  2996. // since it causes a lock and drawindexedprimitive per surface! (gary)
  2997. // Shader_DrawSurfaceStatic( surfID );
  2998. Shader_DrawSurfaceDynamic( pRenderContext, surfID, false );
  2999. // FIXME: This may cause an unnecessary flush to occur!
  3000. // Thankfully, this is a rare codepath. I don't think anything uses it now.
  3001. UnModulateMaterial( pMaterial, pOldColor );
  3002. }
  3003. else
  3004. {
  3005. drawDecals = Shader_DrawBrushSurfaceOverride( pRenderContext, surfID, baseentity );
  3006. }
  3007. // fixme: need to get "allowDecals" from the material
  3008. // if ( g_BrushProperties.allowDecals && pSurf->pdecals )
  3009. if( SurfaceHasDecals( surfID ) && drawDecals )
  3010. {
  3011. DecalSurfaceAdd( surfID, BRUSHMODEL_DECAL_SORT_GROUP );
  3012. }
  3013. // Add overlay fragments to list.
  3014. // FIXME: A little code support is necessary to get overlays working on brush models
  3015. // OverlayMgr()->AddFragmentListToRenderList( MSurf_OverlayFragmentList( surfID ), false );
  3016. // Add shadows too....
  3017. ShadowDecalHandle_t decalHandle = MSurf_ShadowDecals( surfID );
  3018. if (decalHandle != SHADOW_DECAL_HANDLE_INVALID)
  3019. {
  3020. g_pShadowMgr->AddShadowsOnSurfaceToRenderList( decalHandle );
  3021. }
  3022. }
  3023. // UNDONE: These are really guesses. Do we ever exceed these limits?
  3024. const int MAX_TRANS_NODES = 256;
  3025. const int MAX_TRANS_DECALS = 256;
  3026. const int MAX_TRANS_BATCHES = 1024;
  3027. const int MAX_TRANS_SURFACES = 1024;
  3028. class CBrushBatchRender
  3029. {
  3030. public:
  3031. // These are the compact structs produced by the brush render cache. The goal is to have a compact
  3032. // list of drawing instructions for drawing an opaque brush model in the most optimal order.
  3033. // These structs contain ONLY the opaque surfaces of a brush model.
  3034. struct brushrendersurface_t
  3035. {
  3036. short surfaceIndex;
  3037. short planeIndex;
  3038. };
  3039. // a batch is a list of surfaces with the same material - they can be drawn with one call to the materialsystem
  3040. struct brushrenderbatch_t
  3041. {
  3042. short firstSurface;
  3043. short surfaceCount;
  3044. IMaterial *pMaterial;
  3045. int sortID;
  3046. int indexCount;
  3047. };
  3048. // a mesh is a list of batches with the same vertex format.
  3049. struct brushrendermesh_t
  3050. {
  3051. short firstBatch;
  3052. short batchCount;
  3053. };
  3054. // This is the top-level struct containing all data necessary to render an opaque brush model in optimal order
  3055. struct brushrender_t
  3056. {
  3057. // UNDONE: Compact these arrays into a single allocation
  3058. // UNDONE: Compact entire struct to a single allocation? Store brushrender_t * in the linked list?
  3059. void Free()
  3060. {
  3061. delete[] pPlanes;
  3062. delete[] pMeshes;
  3063. delete[] pBatches;
  3064. delete[] pSurfaces;
  3065. pPlanes = NULL;
  3066. pMeshes = NULL;
  3067. pBatches = NULL;
  3068. pSurfaces = NULL;
  3069. }
  3070. cplane_t **pPlanes;
  3071. brushrendermesh_t *pMeshes;
  3072. brushrenderbatch_t *pBatches;
  3073. brushrendersurface_t *pSurfaces;
  3074. short planeCount;
  3075. short meshCount;
  3076. short batchCount;
  3077. short surfaceCount;
  3078. short totalIndexCount;
  3079. short totalVertexCount;
  3080. };
  3081. // Surfaces are stored in a list like this temporarily for sorting purposes only. The compact structs do not store these.
  3082. struct surfacelist_t
  3083. {
  3084. SurfaceHandle_t surfID;
  3085. short surfaceIndex;
  3086. short planeIndex;
  3087. };
  3088. // These are the compact structs produced for translucent brush models. These structs contain
  3089. // only the translucent surfaces of a brush model.
  3090. // a batch is a list of surfaces with the same material - they can be drawn with one call to the materialsystem
  3091. struct transbatch_t
  3092. {
  3093. short firstSurface;
  3094. short surfaceCount;
  3095. IMaterial *pMaterial;
  3096. int sortID;
  3097. int indexCount;
  3098. };
  3099. // This is a list of surfaces that have decals.
  3100. struct transdecal_t
  3101. {
  3102. short firstSurface;
  3103. short surfaceCount;
  3104. };
  3105. // A node is the list of batches that can be drawn without sorting errors. When no decals are present, surfaces
  3106. // from the next node may be appended to this one to improve performance without causing sorting errors.
  3107. struct transnode_t
  3108. {
  3109. short firstBatch;
  3110. short batchCount;
  3111. short firstDecalSurface;
  3112. short decalSurfaceCount;
  3113. };
  3114. // This is the top-level struct containing all data necessary to render a translucent brush model in optimal order.
  3115. // NOTE: Unlike the opaque struct, the order of the batches is view-dependent, so caching this is pointless since
  3116. // the view usually changes.
  3117. struct transrender_t
  3118. {
  3119. transnode_t nodes[MAX_TRANS_NODES];
  3120. SurfaceHandle_t surfaces[MAX_TRANS_SURFACES];
  3121. SurfaceHandle_t decalSurfaces[MAX_TRANS_DECALS];
  3122. transbatch_t batches[MAX_TRANS_BATCHES];
  3123. transbatch_t *pLastBatch; // These are used to append surfaces to existing batches across nodes.
  3124. transnode_t *pLastNode; // This improves performance.
  3125. short nodeCount;
  3126. short batchCount;
  3127. short surfaceCount;
  3128. short decalSurfaceCount;
  3129. };
  3130. // Builds a transrender_t, then executes it's drawing commands
  3131. void DrawTranslucentBrushModel( model_t *model, IClientEntity *baseentity )
  3132. {
  3133. transrender_t renderT;
  3134. renderT.pLastBatch = NULL;
  3135. renderT.pLastNode = NULL;
  3136. renderT.nodeCount = 0;
  3137. renderT.surfaceCount = 0;
  3138. renderT.batchCount = 0;
  3139. renderT.decalSurfaceCount = 0;
  3140. BuildTransLists_r( renderT, model, model->brush.pShared->nodes + model->brush.firstnode );
  3141. void *pProxyData = baseentity ? baseentity->GetClientRenderable() : NULL;
  3142. DrawTransLists( renderT, pProxyData );
  3143. }
  3144. void AddSurfaceToBatch( transrender_t &renderT, transnode_t *pNode, transbatch_t *pBatch, SurfaceHandle_t surfID )
  3145. {
  3146. pBatch->surfaceCount++;
  3147. Assert( renderT.surfaceCount < MAX_TRANS_SURFACES);
  3148. pBatch->indexCount += (MSurf_VertCount( surfID )-2)*3;
  3149. renderT.surfaces[renderT.surfaceCount] = surfID;
  3150. renderT.surfaceCount++;
  3151. if ( SurfaceHasDecals( surfID ) )
  3152. {
  3153. Assert( renderT.decalSurfaceCount < MAX_TRANS_DECALS);
  3154. pNode->decalSurfaceCount++;
  3155. renderT.decalSurfaces[renderT.decalSurfaceCount] = surfID;
  3156. renderT.decalSurfaceCount++;
  3157. }
  3158. }
  3159. void AddTransNode( transrender_t &renderT )
  3160. {
  3161. renderT.pLastNode = &renderT.nodes[renderT.nodeCount];
  3162. renderT.nodeCount++;
  3163. Assert( renderT.nodeCount < MAX_TRANS_NODES);
  3164. renderT.pLastBatch = NULL;
  3165. renderT.pLastNode->firstBatch = renderT.batchCount;
  3166. renderT.pLastNode->firstDecalSurface = renderT.decalSurfaceCount;
  3167. renderT.pLastNode->batchCount = 0;
  3168. renderT.pLastNode->decalSurfaceCount = 0;
  3169. }
  3170. void AddTransBatch( transrender_t &renderT, SurfaceHandle_t surfID )
  3171. {
  3172. transbatch_t &batch = renderT.batches[renderT.pLastNode->firstBatch + renderT.pLastNode->batchCount];
  3173. Assert( renderT.batchCount < MAX_TRANS_BATCHES);
  3174. renderT.pLastNode->batchCount++;
  3175. renderT.batchCount++;
  3176. batch.firstSurface = renderT.surfaceCount;
  3177. batch.surfaceCount = 0;
  3178. batch.pMaterial = MSurf_TexInfo( surfID )->material;
  3179. batch.sortID = MSurf_MaterialSortID( surfID );
  3180. batch.indexCount = 0;
  3181. renderT.pLastBatch = &batch;
  3182. AddSurfaceToBatch( renderT, renderT.pLastNode, &batch, surfID );
  3183. }
  3184. // build node lists
  3185. void BuildTransLists_r( transrender_t &renderT, model_t *model, mnode_t *node )
  3186. {
  3187. float dot;
  3188. if (node->contents >= 0)
  3189. return;
  3190. // node is just a decision point, so go down the apropriate sides
  3191. // find which side of the node we are on
  3192. cplane_t *plane = node->plane;
  3193. if ( plane->type <= PLANE_Z )
  3194. {
  3195. dot = modelorg[plane->type] - plane->dist;
  3196. }
  3197. else
  3198. {
  3199. dot = DotProduct (modelorg, plane->normal) - plane->dist;
  3200. }
  3201. int side = (dot >= 0) ? 0 : 1;
  3202. // back side first - translucent surfaces need to render in back to front order
  3203. // to appear correctly.
  3204. BuildTransLists_r( renderT, model, node->children[!side]);
  3205. // emit all surfaces on node
  3206. CUtlVectorFixed<surfacelist_t, 256> sortList;
  3207. SurfaceHandle_t surfID = SurfaceHandleFromIndex( node->firstsurface, model->brush.pShared );
  3208. for ( int i = 0; i < node->numsurfaces; i++, surfID++ )
  3209. {
  3210. // skip opaque surfaces
  3211. if ( MSurf_Flags(surfID) & SURFDRAW_TRANS )
  3212. {
  3213. if ( ((MSurf_Flags( surfID ) & SURFDRAW_NOCULL) == 0) )
  3214. {
  3215. // Backface cull here, so they won't do any more work
  3216. if ( ( side ^ !!(MSurf_Flags( surfID ) & SURFDRAW_PLANEBACK)) )
  3217. continue;
  3218. }
  3219. // If this can be appended to the previous batch, do so
  3220. int sortID = MSurf_MaterialSortID( surfID );
  3221. if ( renderT.pLastBatch && renderT.pLastBatch->sortID == sortID )
  3222. {
  3223. AddSurfaceToBatch( renderT, renderT.pLastNode, renderT.pLastBatch, surfID );
  3224. }
  3225. else
  3226. {
  3227. // save it off for sorting, then a later append
  3228. int sortIndex = sortList.AddToTail();
  3229. sortList[sortIndex].surfID = surfID;
  3230. }
  3231. }
  3232. }
  3233. // We've got surfaces on this node that can't be added to the previous node
  3234. if ( sortList.Count() )
  3235. {
  3236. // sort by material
  3237. sortList.Sort( SurfaceCmp );
  3238. // add a new sort group
  3239. AddTransNode( renderT );
  3240. int lastSortID = -1;
  3241. // now add the optimal number of batches to that group
  3242. for ( int i = 0; i < sortList.Count(); i++ )
  3243. {
  3244. surfID = sortList[i].surfID;
  3245. int sortID = MSurf_MaterialSortID( surfID );
  3246. if ( lastSortID == sortID )
  3247. {
  3248. // can be drawn in a single call with the current list of surfaces, append
  3249. AddSurfaceToBatch( renderT, renderT.pLastNode, renderT.pLastBatch, surfID );
  3250. }
  3251. else
  3252. {
  3253. // requires a break (material/lightmap change).
  3254. AddTransBatch( renderT, surfID );
  3255. lastSortID = sortID;
  3256. }
  3257. }
  3258. // don't batch across decals or decals will sort incorrectly
  3259. if ( renderT.pLastNode->decalSurfaceCount )
  3260. {
  3261. renderT.pLastNode = NULL;
  3262. renderT.pLastBatch = NULL;
  3263. }
  3264. }
  3265. // front side
  3266. BuildTransLists_r( renderT, model, node->children[side]);
  3267. }
  3268. void DrawTransLists( transrender_t &renderT, void *pProxyData )
  3269. {
  3270. CMatRenderContextPtr pRenderContext( materials );
  3271. PIXEVENT( pRenderContext, "DrawTransLists" );
  3272. bool skipLight = false;
  3273. if ( g_pMaterialSystemConfig->nFullbright == 1 )
  3274. {
  3275. pRenderContext->BindLightmapPage( MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP );
  3276. skipLight = true;
  3277. }
  3278. float pOldColor[4];
  3279. for ( int i = 0; i < renderT.nodeCount; i++ )
  3280. {
  3281. int j;
  3282. const transnode_t &node = renderT.nodes[i];
  3283. for ( j = 0; j < node.batchCount; j++ )
  3284. {
  3285. const transbatch_t &batch = renderT.batches[node.firstBatch+j];
  3286. #ifdef NEWMESH
  3287. CIndexBufferBuilder indexBufferBuilder;
  3288. #else
  3289. CMeshBuilder meshBuilder;
  3290. #endif
  3291. IMaterial *pMaterial = batch.pMaterial;
  3292. ModulateMaterial( pMaterial, pOldColor );
  3293. if ( !skipLight )
  3294. {
  3295. pRenderContext->BindLightmapPage( materialSortInfoArray[batch.sortID].lightmapPageID );
  3296. }
  3297. pRenderContext->Bind( pMaterial, pProxyData );
  3298. #ifdef NEWMESH
  3299. IIndexBuffer *pBuildIndexBuffer = pRenderContext->GetDynamicIndexBuffer( MATERIAL_INDEX_FORMAT_16BIT, false );
  3300. indexBufferBuilder.Begin( pBuildIndexBuffer, batch.indexCount );
  3301. #else
  3302. IMesh *pBuildMesh = pRenderContext->GetDynamicMesh( false, g_WorldStaticMeshes[batch.sortID], NULL, NULL );
  3303. meshBuilder.Begin( pBuildMesh, MATERIAL_TRIANGLES, 0, batch.indexCount );
  3304. #endif
  3305. for ( int k = 0; k < batch.surfaceCount; k++ )
  3306. {
  3307. SurfaceHandle_t surfID = renderT.surfaces[batch.firstSurface + k];
  3308. Assert( !(MSurf_Flags( surfID ) & SURFDRAW_NODRAW) );
  3309. #ifdef NEWMESH
  3310. BuildIndicesForSurface( indexBufferBuilder, surfID );
  3311. #else
  3312. BuildIndicesForSurface( meshBuilder, surfID );
  3313. #endif
  3314. }
  3315. #ifdef NEWMESH
  3316. indexBufferBuilder.End( false ); // haven't tested this one yet (alpha blended world geom I think)
  3317. // FIXME: IMaterial::GetVertexFormat() should do this stripping (add a separate 'SupportsCompression' accessor)
  3318. VertexFormat_t vertexFormat = pMaterial->GetVertexFormat() & ~VERTEX_FORMAT_COMPRESSED;
  3319. pRenderContext->BindVertexBuffer( 0, g_WorldStaticMeshes[batch.sortID], 0, vertexFormat );
  3320. pRenderContext->BindIndexBuffer( pBuildIndexBuffer, 0 );
  3321. pRenderContext->Draw( MATERIAL_TRIANGLES, 0, batch.indexCount );
  3322. #else
  3323. meshBuilder.End( false, true );
  3324. #endif
  3325. // Don't leave the material in a bogus state
  3326. UnModulateMaterial( pMaterial, pOldColor );
  3327. }
  3328. if ( node.decalSurfaceCount )
  3329. {
  3330. for ( j = 0; j < node.decalSurfaceCount; j++ )
  3331. {
  3332. SurfaceHandle_t surfID = renderT.decalSurfaces[node.firstDecalSurface + j];
  3333. Assert( !(MSurf_Flags( surfID ) & SURFDRAW_NODRAW) );
  3334. if( SurfaceHasDecals( surfID ) )
  3335. {
  3336. DecalSurfaceAdd( surfID, BRUSHMODEL_DECAL_SORT_GROUP );
  3337. }
  3338. // Add shadows too....
  3339. ShadowDecalHandle_t decalHandle = MSurf_ShadowDecals( surfID );
  3340. if (decalHandle != SHADOW_DECAL_HANDLE_INVALID)
  3341. {
  3342. g_pShadowMgr->AddShadowsOnSurfaceToRenderList( decalHandle );
  3343. }
  3344. }
  3345. // Now draw the decals + shadows for this node
  3346. // This order relative to the surfaces is important for translucency to work correctly.
  3347. DecalSurfaceDraw(pRenderContext, BRUSHMODEL_DECAL_SORT_GROUP);
  3348. // FIXME: Decals are not being rendered while illuminated by the flashlight
  3349. DecalSurfacesInit( true );
  3350. // Draw all shadows on the brush
  3351. g_pShadowMgr->RenderProjectedTextures( );
  3352. }
  3353. if ( g_ShaderDebug.anydebug )
  3354. {
  3355. CUtlVector<msurface2_t *> brushList;
  3356. for ( j = 0; j < node.batchCount; j++ )
  3357. {
  3358. const transbatch_t &batch = renderT.batches[node.firstBatch+j];
  3359. for ( int k = 0; k < batch.surfaceCount; k++ )
  3360. {
  3361. brushList.AddToTail( renderT.surfaces[batch.firstSurface + k] );
  3362. }
  3363. }
  3364. DrawDebugInformation( brushList );
  3365. }
  3366. }
  3367. }
  3368. static int __cdecl SurfaceCmp(const surfacelist_t *s0, const surfacelist_t *s1 );
  3369. void LevelInit();
  3370. brushrender_t *FindOrCreateRenderBatch( model_t *pModel );
  3371. void DrawOpaqueBrushModel( IClientEntity *baseentity, model_t *model, const Vector& origin, ERenderDepthMode DepthMode );
  3372. void DrawTranslucentBrushModel( IClientEntity *baseentity, model_t *model, const Vector& origin, bool bShadowDepth, bool bDrawOpaque, bool bDrawTranslucent );
  3373. void DrawBrushModelShadow( model_t *model, IClientRenderable *pRenderable );
  3374. private:
  3375. void ClearRenderHandles();
  3376. CUtlLinkedList<brushrender_t> m_renderList;
  3377. };
  3378. int __cdecl CBrushBatchRender::SurfaceCmp(const surfacelist_t *s0, const surfacelist_t *s1 )
  3379. {
  3380. int sortID0 = MSurf_MaterialSortID( s0->surfID );
  3381. int sortID1 = MSurf_MaterialSortID( s1->surfID );
  3382. return sortID0 - sortID1;
  3383. }
  3384. CBrushBatchRender g_BrushBatchRenderer;
  3385. //-----------------------------------------------------------------------------
  3386. // Purpose: This is used when the mat_dxlevel is changed to reset the brush
  3387. // models.
  3388. //-----------------------------------------------------------------------------
  3389. void R_BrushBatchInit( void )
  3390. {
  3391. g_BrushBatchRenderer.LevelInit();
  3392. }
  3393. void CBrushBatchRender::LevelInit()
  3394. {
  3395. unsigned short iNext;
  3396. for( unsigned short i=m_renderList.Head(); i != m_renderList.InvalidIndex(); i=iNext )
  3397. {
  3398. iNext = m_renderList.Next(i);
  3399. m_renderList.Element(i).Free();
  3400. }
  3401. m_renderList.Purge();
  3402. ClearRenderHandles();
  3403. }
  3404. void CBrushBatchRender::ClearRenderHandles( void )
  3405. {
  3406. for ( int iBrush = 1 ; iBrush < host_state.worldbrush->numsubmodels ; ++iBrush )
  3407. {
  3408. char szBrushModel[5]; // inline model names "*1", "*2" etc
  3409. Q_snprintf( szBrushModel, sizeof( szBrushModel ), "*%i", iBrush );
  3410. model_t *pModel = modelloader->GetModelForName( szBrushModel, IModelLoader::FMODELLOADER_SERVER );
  3411. if ( pModel )
  3412. {
  3413. pModel->brush.renderHandle = 0;
  3414. }
  3415. }
  3416. }
  3417. // Create a compact, optimal list of rendering commands for the opaque parts of a brush model
  3418. // NOTE: This just skips translucent surfaces assuming a separate transrender_t pass!
  3419. CBrushBatchRender::brushrender_t *CBrushBatchRender::FindOrCreateRenderBatch( model_t *pModel )
  3420. {
  3421. if ( !pModel->brush.nummodelsurfaces )
  3422. return NULL;
  3423. unsigned short index = pModel->brush.renderHandle - 1;
  3424. if ( m_renderList.IsValidIndex( index ) )
  3425. return &m_renderList.Element(index);
  3426. index = m_renderList.AddToTail();
  3427. pModel->brush.renderHandle = index + 1;
  3428. brushrender_t &renderT = m_renderList.Element(index);
  3429. renderT.pPlanes = NULL;
  3430. renderT.pMeshes = NULL;
  3431. renderT.planeCount = 0;
  3432. renderT.meshCount = 0;
  3433. renderT.totalIndexCount = 0;
  3434. renderT.totalVertexCount = 0;
  3435. CUtlVector<cplane_t *> planeList;
  3436. CUtlVector<surfacelist_t> surfaceList;
  3437. int i;
  3438. SurfaceHandle_t surfID = SurfaceHandleFromIndex( pModel->brush.firstmodelsurface, pModel->brush.pShared );
  3439. for (i=0 ; i<pModel->brush.nummodelsurfaces; i++, surfID++)
  3440. {
  3441. // UNDONE: For now, just draw these in a separate pass
  3442. if ( MSurf_Flags(surfID) & SURFDRAW_TRANS )
  3443. continue;
  3444. cplane_t *plane = surfID->plane;
  3445. int planeIndex = planeList.Find(plane);
  3446. if ( planeIndex == -1 )
  3447. {
  3448. planeIndex = planeList.AddToTail( plane );
  3449. }
  3450. surfacelist_t tmp;
  3451. tmp.surfID = surfID;
  3452. tmp.surfaceIndex = i;
  3453. tmp.planeIndex = planeIndex;
  3454. surfaceList.AddToTail( tmp );
  3455. }
  3456. surfaceList.Sort( SurfaceCmp );
  3457. renderT.pPlanes = new cplane_t *[planeList.Count()];
  3458. renderT.planeCount = planeList.Count();
  3459. memcpy( renderT.pPlanes, planeList.Base(), sizeof(cplane_t *)*planeList.Count() );
  3460. renderT.pSurfaces = new brushrendersurface_t[surfaceList.Count()];
  3461. renderT.surfaceCount = surfaceList.Count();
  3462. int meshCount = 0;
  3463. int batchCount = 0;
  3464. int lastSortID = -1;
  3465. #ifdef NEWMESH
  3466. IVertexBuffer *pLastVertexBuffer = NULL;
  3467. #else
  3468. IMesh *pLastMesh = NULL;
  3469. #endif
  3470. brushrendermesh_t *pMesh = NULL;
  3471. brushrendermesh_t tmpMesh[MAX_VERTEX_FORMAT_CHANGES];
  3472. brushrenderbatch_t *pBatch = NULL;
  3473. brushrenderbatch_t tmpBatch[128];
  3474. for ( i = 0; i < surfaceList.Count(); i++ )
  3475. {
  3476. renderT.pSurfaces[i].surfaceIndex = surfaceList[i].surfaceIndex;
  3477. renderT.pSurfaces[i].planeIndex = surfaceList[i].planeIndex;
  3478. surfID = surfaceList[i].surfID;
  3479. int sortID = MSurf_MaterialSortID( surfID );
  3480. #ifdef NEWMESH
  3481. if ( g_WorldStaticMeshes[sortID] != pLastVertexBuffer )
  3482. #else
  3483. if ( g_WorldStaticMeshes[sortID] != pLastMesh )
  3484. #endif
  3485. {
  3486. pMesh = tmpMesh + meshCount;
  3487. pMesh->firstBatch = batchCount;
  3488. pMesh->batchCount = 0;
  3489. lastSortID = -1; // force a new batch
  3490. meshCount++;
  3491. }
  3492. if ( sortID != lastSortID )
  3493. {
  3494. pBatch = tmpBatch + batchCount;
  3495. pBatch->firstSurface = i;
  3496. pBatch->surfaceCount = 0;
  3497. pBatch->sortID = sortID;
  3498. pBatch->pMaterial = MSurf_TexInfo( surfID )->material;
  3499. pBatch->indexCount = 0;
  3500. pMesh->batchCount++;
  3501. batchCount++;
  3502. }
  3503. #ifdef NEWMESH
  3504. pLastVertexBuffer = g_WorldStaticMeshes[sortID];
  3505. #else
  3506. pLastMesh = g_WorldStaticMeshes[sortID];
  3507. #endif
  3508. lastSortID = sortID;
  3509. pBatch->surfaceCount++;
  3510. int vertCount = MSurf_VertCount( surfID );
  3511. int indexCount = (vertCount - 2) * 3;
  3512. pBatch->indexCount += indexCount;
  3513. renderT.totalIndexCount += indexCount;
  3514. renderT.totalVertexCount += vertCount;
  3515. }
  3516. renderT.pMeshes = new brushrendermesh_t[meshCount];
  3517. memcpy( renderT.pMeshes, tmpMesh, sizeof(brushrendermesh_t) * meshCount );
  3518. renderT.meshCount = meshCount;
  3519. renderT.pBatches = new brushrenderbatch_t[batchCount];
  3520. memcpy( renderT.pBatches, tmpBatch, sizeof(brushrenderbatch_t) * batchCount );
  3521. renderT.batchCount = batchCount;
  3522. return &renderT;
  3523. }
  3524. //-----------------------------------------------------------------------------
  3525. // Draws an opaque (parts of a) brush model
  3526. //-----------------------------------------------------------------------------
  3527. void CBrushBatchRender::DrawOpaqueBrushModel( IClientEntity *baseentity, model_t *model, const Vector& origin, ERenderDepthMode DepthMode )
  3528. {
  3529. VPROF( "R_DrawOpaqueBrushModel" );
  3530. SurfaceHandle_t firstSurfID = SurfaceHandleFromIndex( model->brush.firstmodelsurface, model->brush.pShared );
  3531. brushrender_t *pRender = FindOrCreateRenderBatch( model );
  3532. int i;
  3533. if ( !pRender )
  3534. return;
  3535. bool skipLight = false;
  3536. CMatRenderContextPtr pRenderContext( materials );
  3537. PIXEVENT( pRenderContext, "DrawOpaqueBrushModel" );
  3538. if ( (g_pMaterialSystemConfig->nFullbright == 1) || DepthMode == DEPTH_MODE_SHADOW )
  3539. {
  3540. pRenderContext->BindLightmapPage( MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP );
  3541. skipLight = true;
  3542. }
  3543. void *pProxyData = baseentity ? baseentity->GetClientRenderable() : NULL;
  3544. bool backface[1024];
  3545. Assert( pRender->planeCount < 1024 );
  3546. // NOTE: Backface culling is almost no perf gain. Can be removed from brush model rendering.
  3547. // Check the shared planes once
  3548. for ( i = 0; i < pRender->planeCount; i++ )
  3549. {
  3550. float dot = DotProduct( modelorg, pRender->pPlanes[i]->normal) - pRender->pPlanes[i]->dist;
  3551. backface[i] = ( DepthMode == DEPTH_MODE_NORMAL && ( dot < BACKFACE_EPSILON ) ) ? true : false; // don't backface cull when rendering to shadow map
  3552. }
  3553. float pOldColor[4];
  3554. for ( i = 0; i < pRender->meshCount; i++ )
  3555. {
  3556. brushrendermesh_t &mesh = pRender->pMeshes[i];
  3557. for ( int j = 0; j < mesh.batchCount; j++ )
  3558. {
  3559. brushrenderbatch_t &batch = pRender->pBatches[mesh.firstBatch + j];
  3560. int k;
  3561. for ( k = 0; k < batch.surfaceCount; k++ )
  3562. {
  3563. brushrendersurface_t &surface = pRender->pSurfaces[batch.firstSurface + k];
  3564. if ( !backface[surface.planeIndex] )
  3565. break;
  3566. }
  3567. if ( k == batch.surfaceCount )
  3568. continue;
  3569. CMeshBuilder meshBuilder;
  3570. IMaterial *pMaterial = NULL;
  3571. if ( DepthMode != DEPTH_MODE_NORMAL )
  3572. {
  3573. // Select proper override material
  3574. int nAlphaTest = (int) batch.pMaterial->IsAlphaTested();
  3575. int nNoCull = (int) batch.pMaterial->IsTwoSided();
  3576. IMaterial *pDepthWriteMaterial;
  3577. if ( DepthMode == DEPTH_MODE_SSA0 )
  3578. {
  3579. pDepthWriteMaterial = g_pMaterialSSAODepthWrite[nAlphaTest][nNoCull];
  3580. }
  3581. else
  3582. {
  3583. pDepthWriteMaterial = g_pMaterialDepthWrite[nAlphaTest][nNoCull];
  3584. }
  3585. if ( nAlphaTest == 1 )
  3586. {
  3587. static unsigned int originalTextureVarCache = 0;
  3588. IMaterialVar *pOriginalTextureVar = batch.pMaterial->FindVarFast( "$basetexture", &originalTextureVarCache );
  3589. static unsigned int originalTextureFrameVarCache = 0;
  3590. IMaterialVar *pOriginalTextureFrameVar = batch.pMaterial->FindVarFast( "$frame", &originalTextureFrameVarCache );
  3591. static unsigned int originalAlphaRefCache = 0;
  3592. IMaterialVar *pOriginalAlphaRefVar = batch.pMaterial->FindVarFast( "$AlphaTestReference", &originalAlphaRefCache );
  3593. static unsigned int textureVarCache = 0;
  3594. IMaterialVar *pTextureVar = pDepthWriteMaterial->FindVarFast( "$basetexture", &textureVarCache );
  3595. static unsigned int textureFrameVarCache = 0;
  3596. IMaterialVar *pTextureFrameVar = pDepthWriteMaterial->FindVarFast( "$frame", &textureFrameVarCache );
  3597. static unsigned int alphaRefCache = 0;
  3598. IMaterialVar *pAlphaRefVar = pDepthWriteMaterial->FindVarFast( "$AlphaTestReference", &alphaRefCache );
  3599. if( pTextureVar && pOriginalTextureVar )
  3600. {
  3601. pTextureVar->SetTextureValue( pOriginalTextureVar->GetTextureValue() );
  3602. }
  3603. if( pTextureFrameVar && pOriginalTextureFrameVar )
  3604. {
  3605. pTextureFrameVar->SetIntValue( pOriginalTextureFrameVar->GetIntValue() );
  3606. }
  3607. if( pAlphaRefVar && pOriginalAlphaRefVar )
  3608. {
  3609. pAlphaRefVar->SetFloatValue( pOriginalAlphaRefVar->GetFloatValue() );
  3610. }
  3611. }
  3612. pMaterial = pDepthWriteMaterial;
  3613. }
  3614. else
  3615. {
  3616. pMaterial = batch.pMaterial;
  3617. // Store off the old color + alpha
  3618. ModulateMaterial( pMaterial, pOldColor );
  3619. if ( !skipLight )
  3620. {
  3621. pRenderContext->BindLightmapPage( materialSortInfoArray[batch.sortID].lightmapPageID );
  3622. }
  3623. }
  3624. pRenderContext->Bind( pMaterial, pProxyData );
  3625. #ifdef NEWMESH
  3626. IIndexBuffer *pBuildIndexBuffer = pRenderContext->GetDynamicIndexBuffer( MATERIAL_INDEX_FORMAT_16BIT, false );
  3627. CIndexBufferBuilder indexBufferBuilder;
  3628. indexBufferBuilder.Begin( pBuildIndexBuffer, batch.indexCount );
  3629. #else
  3630. IMesh *pBuildMesh = pRenderContext->GetDynamicMesh( false, g_WorldStaticMeshes[batch.sortID], NULL, NULL );
  3631. meshBuilder.Begin( pBuildMesh, MATERIAL_TRIANGLES, 0, batch.indexCount );
  3632. #endif
  3633. for ( ; k < batch.surfaceCount; k++ )
  3634. {
  3635. brushrendersurface_t &surface = pRender->pSurfaces[batch.firstSurface + k];
  3636. if ( backface[surface.planeIndex] )
  3637. continue;
  3638. SurfaceHandle_t surfID = firstSurfID + surface.surfaceIndex;
  3639. Assert( !(MSurf_Flags( surfID ) & SURFDRAW_NODRAW) );
  3640. #ifdef NEWMESH
  3641. BuildIndicesForSurface( indexBufferBuilder, surfID );
  3642. #else
  3643. BuildIndicesForSurface( meshBuilder, surfID );
  3644. #endif
  3645. if( SurfaceHasDecals( surfID ) && DepthMode == DEPTH_MODE_NORMAL )
  3646. {
  3647. DecalSurfaceAdd( surfID, BRUSHMODEL_DECAL_SORT_GROUP );
  3648. }
  3649. // Add overlay fragments to list.
  3650. // FIXME: A little code support is necessary to get overlays working on brush models
  3651. // OverlayMgr()->AddFragmentListToRenderList( MSurf_OverlayFragmentList( surfID ), false );
  3652. if ( DepthMode == DEPTH_MODE_NORMAL )
  3653. {
  3654. // Add render-to-texture shadows too....
  3655. ShadowDecalHandle_t decalHandle = MSurf_ShadowDecals( surfID );
  3656. if (decalHandle != SHADOW_DECAL_HANDLE_INVALID)
  3657. {
  3658. g_pShadowMgr->AddShadowsOnSurfaceToRenderList( decalHandle );
  3659. }
  3660. }
  3661. }
  3662. #ifdef NEWMESH
  3663. indexBufferBuilder.End( false ); // this one is broken (opaque brush model. .tv)
  3664. pRenderContext->BindVertexBuffer( 0, g_WorldStaticMeshes[batch.sortID], 0, g_WorldStaticMeshes[batch.sortID]->GetVertexFormat() );
  3665. pRenderContext->BindIndexBuffer( pBuildIndexBuffer, 0 );
  3666. pRenderContext->Draw( MATERIAL_TRIANGLES, 0, pBuildIndexBuffer->NumIndices() );//batch.indexCount );
  3667. #else
  3668. meshBuilder.End( false, true );
  3669. #endif
  3670. if ( DepthMode == DEPTH_MODE_NORMAL )
  3671. {
  3672. // Don't leave the material in a bogus state
  3673. UnModulateMaterial( pMaterial, pOldColor );
  3674. }
  3675. }
  3676. }
  3677. if ( DepthMode != DEPTH_MODE_NORMAL )
  3678. {
  3679. return;
  3680. }
  3681. if ( g_ShaderDebug.anydebug )
  3682. {
  3683. for ( i = 0; i < pRender->meshCount; i++ )
  3684. {
  3685. brushrendermesh_t &mesh = pRender->pMeshes[i];
  3686. CUtlVector<msurface2_t *> brushList;
  3687. for ( int j = 0; j < mesh.batchCount; j++ )
  3688. {
  3689. brushrenderbatch_t &batch = pRender->pBatches[mesh.firstBatch + j];
  3690. for ( int k = 0; k < batch.surfaceCount; k++ )
  3691. {
  3692. brushrendersurface_t &surface = pRender->pSurfaces[batch.firstSurface + k];
  3693. if ( backface[surface.planeIndex] )
  3694. continue;
  3695. SurfaceHandle_t surfID = firstSurfID + surface.surfaceIndex;
  3696. brushList.AddToTail(surfID);
  3697. }
  3698. }
  3699. // now draw debug for each drawn surface
  3700. DrawDebugInformation( brushList );
  3701. }
  3702. }
  3703. }
  3704. //-----------------------------------------------------------------------------
  3705. // Draws an translucent (sorted) brush model
  3706. //-----------------------------------------------------------------------------
  3707. void CBrushBatchRender::DrawTranslucentBrushModel( IClientEntity *baseentity, model_t *model, const Vector& origin, bool bShadowDepth, bool bDrawOpaque, bool bDrawTranslucent )
  3708. {
  3709. if ( bDrawOpaque )
  3710. {
  3711. DrawOpaqueBrushModel( baseentity, model, origin, bShadowDepth ? DEPTH_MODE_SHADOW : DEPTH_MODE_NORMAL );
  3712. }
  3713. if ( !bShadowDepth && bDrawTranslucent )
  3714. {
  3715. DrawTranslucentBrushModel( model, baseentity );
  3716. }
  3717. }
  3718. //-----------------------------------------------------------------------------
  3719. // Purpose: Draws a brush model shadow for render-to-texture shadows
  3720. //-----------------------------------------------------------------------------
  3721. // UNDONE: This is reasonable, but it could be much faster as follows:
  3722. // Build a vertex buffer cache. A block-allocated static mesh with 1024 verts
  3723. // per block or something.
  3724. // When a new brush is encountered, fill it in to the current block or the
  3725. // next one (first fit allocator). Then this routine could simply draw
  3726. // a static mesh with a single index buffer build, draw call (no dynamic vb).
  3727. void CBrushBatchRender::DrawBrushModelShadow( model_t *model, IClientRenderable *pRenderable )
  3728. {
  3729. brushrender_t *pRender = FindOrCreateRenderBatch( (model_t *)model );
  3730. if ( !pRender )
  3731. return;
  3732. CMatRenderContextPtr pRenderContext( materials );
  3733. pRenderContext->Bind( g_pMaterialShadowBuild, pRenderable );
  3734. // Draws all surfaces in the brush model in arbitrary order
  3735. SurfaceHandle_t surfID = SurfaceHandleFromIndex( model->brush.firstmodelsurface, model->brush.pShared );
  3736. IMesh *pMesh = pRenderContext->GetDynamicMesh();
  3737. CMeshBuilder meshBuilder;
  3738. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, pRender->totalVertexCount, pRender->totalIndexCount );
  3739. for ( int i=0 ; i<model->brush.nummodelsurfaces ; i++, surfID++)
  3740. {
  3741. Assert( !(MSurf_Flags( surfID ) & SURFDRAW_NODRAW) );
  3742. if ( MSurf_Flags(surfID) & SURFDRAW_TRANS )
  3743. continue;
  3744. int startVert = MSurf_FirstVertIndex( surfID );
  3745. int vertCount = MSurf_VertCount( surfID );
  3746. int startIndex = meshBuilder.GetCurrentVertex();
  3747. int j;
  3748. for ( j = 0; j < vertCount; j++ )
  3749. {
  3750. int vertIndex = model->brush.pShared->vertindices[startVert + j];
  3751. // world-space vertex
  3752. meshBuilder.Position3fv( model->brush.pShared->vertexes[vertIndex].position.Base() );
  3753. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  3754. meshBuilder.AdvanceVertex();
  3755. }
  3756. for ( j = 0; j < vertCount-2; j++ )
  3757. {
  3758. meshBuilder.FastIndex( startIndex );
  3759. meshBuilder.FastIndex( startIndex + j + 1 );
  3760. meshBuilder.FastIndex( startIndex + j + 2 );
  3761. }
  3762. }
  3763. meshBuilder.End();
  3764. pMesh->Draw();
  3765. }
  3766. void R_Surface_LevelInit()
  3767. {
  3768. g_BrushBatchRenderer.LevelInit();
  3769. // reset this to the default at the start of each level
  3770. g_MaxLeavesVisible = 512;
  3771. }
  3772. void R_Surface_LevelShutdown()
  3773. {
  3774. CWorldRenderList::PurgeAll();
  3775. }
  3776. //-----------------------------------------------------------------------------
  3777. static void R_DrawBrushModel_Override( IClientEntity *baseentity, model_t *model, const Vector& origin )
  3778. {
  3779. VPROF( "R_DrawOpaqueBrushModel_Override" );
  3780. SurfaceHandle_t surfID = SurfaceHandleFromIndex( model->brush.firstmodelsurface, model->brush.pShared );
  3781. for (int i=0 ; i<model->brush.nummodelsurfaces ; i++, surfID++)
  3782. {
  3783. Assert( !(MSurf_Flags( surfID ) & SURFDRAW_NODRAW) );
  3784. Shader_BrushSurface( surfID, model, baseentity );
  3785. }
  3786. // now draw debug for each drawn surface
  3787. if ( g_ShaderDebug.anydebug )
  3788. {
  3789. CUtlVector<msurface2_t *> surfaceList;
  3790. surfID = SurfaceHandleFromIndex( model->brush.firstmodelsurface, model->brush.pShared );
  3791. for (int i=0 ; i<model->brush.nummodelsurfaces ; i++, surfID++)
  3792. {
  3793. surfaceList.AddToTail(surfID);
  3794. }
  3795. DrawDebugInformation( surfaceList );
  3796. }
  3797. }
  3798. int R_MarkDlightsOnBrushModel( model_t *model, IClientRenderable *pRenderable )
  3799. {
  3800. int count = 0;
  3801. if ( g_bActiveDlights )
  3802. {
  3803. extern int R_MarkLights (dlight_t *light, int bit, mnode_t *node);
  3804. g_BrushToWorldMatrix.SetupMatrixOrgAngles( pRenderable->GetRenderOrigin(), pRenderable->GetRenderAngles() );
  3805. Vector saveOrigin;
  3806. for (int k=0 ; k<MAX_DLIGHTS ; k++)
  3807. {
  3808. if ((cl_dlights[k].die < cl.GetTime()) ||
  3809. (!cl_dlights[k].IsRadiusGreaterThanZero()))
  3810. continue;
  3811. VectorCopy( cl_dlights[k].origin, saveOrigin );
  3812. cl_dlights[k].origin = g_BrushToWorldMatrix.VMul4x3Transpose( saveOrigin );
  3813. mnode_t *node = model->brush.pShared->nodes + model->brush.firstnode;
  3814. if ( IsBoxIntersectingSphereExtents( node->m_vecCenter, node->m_vecHalfDiagonal, cl_dlights[k].origin, cl_dlights[k].GetRadius() ) )
  3815. {
  3816. count += R_MarkLights( &cl_dlights[k], 1<<k, node );
  3817. }
  3818. VectorCopy( saveOrigin, cl_dlights[k].origin );
  3819. }
  3820. if ( count )
  3821. {
  3822. model->flags |= MODELFLAG_HAS_DLIGHT;
  3823. }
  3824. g_BrushToWorldMatrix.Identity();
  3825. }
  3826. return count;
  3827. }
  3828. //-----------------------------------------------------------------------------
  3829. // Stuff to do right before and after brush model rendering
  3830. //-----------------------------------------------------------------------------
  3831. void Shader_BrushBegin( model_t *model, IClientEntity *baseentity /*=NULL*/ )
  3832. {
  3833. // Clear out the render list of decals
  3834. DecalSurfacesInit( true );
  3835. // Clear out the render lists of shadows
  3836. g_pShadowMgr->ClearShadowRenderList( );
  3837. }
  3838. void Shader_BrushEnd( IMatRenderContext *pRenderContext, VMatrix const* pBrushToWorld, model_t *model, bool bShadowDepth, IClientEntity *baseentity /* = NULL */ )
  3839. {
  3840. if ( bShadowDepth )
  3841. return;
  3842. DecalSurfaceDraw(pRenderContext, BRUSHMODEL_DECAL_SORT_GROUP);
  3843. // draw the flashlight lighting for the decals on the brush.
  3844. g_pShadowMgr->DrawFlashlightDecals( BRUSHMODEL_DECAL_SORT_GROUP, false );
  3845. // Draw all shadows on the brush
  3846. g_pShadowMgr->RenderProjectedTextures( pBrushToWorld );
  3847. }
  3848. class CBrushModelTransform
  3849. {
  3850. public:
  3851. CBrushModelTransform( const Vector &origin, const QAngle &angles, IMatRenderContext *pRenderContext )
  3852. {
  3853. bool rotated = ( angles[0] || angles[1] || angles[2] );
  3854. m_bIdentity = (origin == vec3_origin) && (!rotated);
  3855. // Don't change state if we don't need to
  3856. if (!m_bIdentity)
  3857. {
  3858. m_savedModelorg = modelorg;
  3859. pRenderContext->MatrixMode( MATERIAL_MODEL );
  3860. pRenderContext->PushMatrix();
  3861. g_BrushToWorldMatrix.SetupMatrixOrgAngles( origin, angles );
  3862. pRenderContext->LoadMatrix( g_BrushToWorldMatrix );
  3863. modelorg = g_BrushToWorldMatrix.VMul4x3Transpose(g_EngineRenderer->ViewOrigin());
  3864. }
  3865. }
  3866. ~CBrushModelTransform()
  3867. {
  3868. if ( !m_bIdentity )
  3869. {
  3870. CMatRenderContextPtr pRenderContext( materials );
  3871. pRenderContext->MatrixMode( MATERIAL_MODEL );
  3872. pRenderContext->PopMatrix();
  3873. g_BrushToWorldMatrix.Identity();
  3874. modelorg = m_savedModelorg;
  3875. }
  3876. }
  3877. VMatrix *GetNonIdentityMatrix()
  3878. {
  3879. return m_bIdentity ? NULL : &g_BrushToWorldMatrix;
  3880. }
  3881. inline bool IsIdentity() { return m_bIdentity; }
  3882. Vector m_savedModelorg;
  3883. bool m_bIdentity;
  3884. };
  3885. //-----------------------------------------------------------------------------
  3886. // Purpose: Draws a brush model using the global shader/surfaceVisitor
  3887. // Input : *e - entity to draw
  3888. // Output : void R_DrawBrushModel
  3889. //-----------------------------------------------------------------------------
  3890. void R_DrawBrushModel( IClientEntity *baseentity, model_t *model,
  3891. const Vector& origin, const QAngle& angles, ERenderDepthMode DepthMode, bool bDrawOpaque, bool bDrawTranslucent )
  3892. {
  3893. VPROF( "R_DrawBrushModel" );
  3894. #ifdef USE_CONVARS
  3895. if ( !r_drawbrushmodels.GetInt() )
  3896. {
  3897. return;
  3898. }
  3899. bool bWireframe = false;
  3900. if ( r_drawbrushmodels.GetInt() == 2 )
  3901. {
  3902. // save and override
  3903. bWireframe = g_ShaderDebug.wireframe;
  3904. g_ShaderDebug.wireframe = true;
  3905. g_ShaderDebug.anydebug = true;
  3906. }
  3907. #endif
  3908. CMatRenderContextPtr pRenderContext( materials );
  3909. CBrushModelTransform brushTransform( origin, angles, pRenderContext );
  3910. Assert(model->brush.firstmodelsurface != 0);
  3911. // Draw the puppy...
  3912. Shader_BrushBegin( model, baseentity );
  3913. if ( model->flags & MODELFLAG_FRAMEBUFFER_TEXTURE )
  3914. {
  3915. CMatRenderContextPtr pRenderContextMat( materials );
  3916. pRenderContext->CopyRenderTargetToTexture( pRenderContextMat->GetFrameBufferCopyTexture( 0 ) );
  3917. }
  3918. if ( s_pBrushRenderOverride )
  3919. {
  3920. R_DrawBrushModel_Override( baseentity, model, origin );
  3921. }
  3922. else
  3923. {
  3924. if ( model->flags & MODELFLAG_TRANSLUCENT )
  3925. {
  3926. if ( DepthMode == DEPTH_MODE_NORMAL )
  3927. {
  3928. g_BrushBatchRenderer.DrawTranslucentBrushModel( baseentity, model, origin, false, bDrawOpaque, bDrawTranslucent );
  3929. }
  3930. }
  3931. else if ( bDrawOpaque )
  3932. {
  3933. g_BrushBatchRenderer.DrawOpaqueBrushModel( baseentity, model, origin, DepthMode );
  3934. }
  3935. }
  3936. Shader_BrushEnd( pRenderContext, brushTransform.GetNonIdentityMatrix(), model, DepthMode != DEPTH_MODE_NORMAL, baseentity );
  3937. #ifdef USE_CONVARS
  3938. if ( r_drawbrushmodels.GetInt() == 2 )
  3939. {
  3940. // restore
  3941. g_ShaderDebug.wireframe = bWireframe;
  3942. g_ShaderDebug.TestAnyDebug();
  3943. }
  3944. #endif
  3945. }
  3946. //-----------------------------------------------------------------------------
  3947. // Purpose: Draws a brush model shadow for render-to-texture shadows
  3948. //-----------------------------------------------------------------------------
  3949. void R_DrawBrushModelShadow( IClientRenderable *pRenderable )
  3950. {
  3951. if( !r_drawbrushmodels.GetInt() )
  3952. return;
  3953. model_t *model = (model_t *)pRenderable->GetModel();
  3954. const Vector& origin = pRenderable->GetRenderOrigin();
  3955. QAngle const& angles = pRenderable->GetRenderAngles();
  3956. CMatRenderContextPtr pRenderContext( materials );
  3957. CBrushModelTransform brushTransform( origin, angles, pRenderContext );
  3958. g_BrushBatchRenderer.DrawBrushModelShadow( model, pRenderable );
  3959. }
  3960. void R_DrawIdentityBrushModel( IWorldRenderList *pRenderListIn, model_t *model )
  3961. {
  3962. if ( !model )
  3963. return;
  3964. CWorldRenderList *pRenderList = assert_cast<CWorldRenderList *>(pRenderListIn);
  3965. SurfaceHandle_t surfID = SurfaceHandleFromIndex( model->brush.firstmodelsurface, model->brush.pShared );
  3966. for (int j=0 ; j<model->brush.nummodelsurfaces ; ++j, surfID++)
  3967. {
  3968. Assert( !(MSurf_Flags( surfID ) & SURFDRAW_NODRAW) );
  3969. // FIXME: Can't insert translucent stuff into the list
  3970. // of translucent surfaces because we don't know what leaf
  3971. // we're in. At the moment, the client doesn't add translucent
  3972. // brushes to the identity brush model list
  3973. // Assert ( (psurf->flags & SURFDRAW_TRANS ) == 0 );
  3974. // OPTIMIZE: Backface cull these guys?!?!?
  3975. if ( MSurf_Flags( surfID ) & SURFDRAW_TRANS)
  3976. // if ( psurf->texinfo->material->IsTranslucent() )
  3977. {
  3978. Shader_TranslucentWorldSurface( pRenderList, surfID );
  3979. }
  3980. else
  3981. {
  3982. Shader_WorldSurface( pRenderList, surfID );
  3983. }
  3984. }
  3985. }
  3986. #endif
  3987. //-----------------------------------------------------------------------------
  3988. // Converts leaf pointer to index
  3989. //-----------------------------------------------------------------------------
  3990. inline int LeafToIndex( mleaf_t* pLeaf )
  3991. {
  3992. return pLeaf - host_state.worldbrush->leafs;
  3993. }
  3994. //-----------------------------------------------------------------------------
  3995. // Structures to help out with enumeration
  3996. //-----------------------------------------------------------------------------
  3997. enum
  3998. {
  3999. ENUM_SPHERE_TEST_X = 0x1,
  4000. ENUM_SPHERE_TEST_Y = 0x2,
  4001. ENUM_SPHERE_TEST_Z = 0x4,
  4002. ENUM_SPHERE_TEST_ALL = 0x7
  4003. };
  4004. struct EnumLeafBoxInfo_t
  4005. {
  4006. VectorAligned m_vecBoxMax;
  4007. VectorAligned m_vecBoxMin;
  4008. VectorAligned m_vecBoxCenter;
  4009. VectorAligned m_vecBoxHalfDiagonal;
  4010. ISpatialLeafEnumerator *m_pIterator;
  4011. int m_nContext;
  4012. };
  4013. struct EnumLeafSphereInfo_t
  4014. {
  4015. Vector m_vecCenter;
  4016. float m_flRadius;
  4017. Vector m_vecBoxCenter;
  4018. Vector m_vecBoxHalfDiagonal;
  4019. ISpatialLeafEnumerator *m_pIterator;
  4020. int m_nContext;
  4021. };
  4022. //-----------------------------------------------------------------------------
  4023. // Finds all leaves of the BSP tree within a particular volume
  4024. //-----------------------------------------------------------------------------
  4025. static bool EnumerateLeafInBox_R(mnode_t *node, EnumLeafBoxInfo_t& info )
  4026. {
  4027. // no polygons in solid nodes (don't report these leaves either)
  4028. if (node->contents == CONTENTS_SOLID)
  4029. return true; // solid
  4030. // rough cull...
  4031. if (!IsBoxIntersectingBoxExtents(node->m_vecCenter, node->m_vecHalfDiagonal,
  4032. info.m_vecBoxCenter, info.m_vecBoxHalfDiagonal))
  4033. {
  4034. return true;
  4035. }
  4036. if (node->contents >= 0)
  4037. {
  4038. // if a leaf node, report it to the iterator...
  4039. return info.m_pIterator->EnumerateLeaf( LeafToIndex( (mleaf_t *)node ), info.m_nContext );
  4040. }
  4041. // Does the node plane split the box?
  4042. // find which side of the node we are on
  4043. cplane_t* plane = node->plane;
  4044. if ( plane->type <= PLANE_Z )
  4045. {
  4046. if (info.m_vecBoxMax[plane->type] <= plane->dist)
  4047. {
  4048. return EnumerateLeafInBox_R( node->children[1], info );
  4049. }
  4050. else if (info.m_vecBoxMin[plane->type] >= plane->dist)
  4051. {
  4052. return EnumerateLeafInBox_R( node->children[0], info );
  4053. }
  4054. else
  4055. {
  4056. // Here the box is split by the node
  4057. bool ret = EnumerateLeafInBox_R( node->children[0], info );
  4058. if (!ret)
  4059. return false;
  4060. return EnumerateLeafInBox_R( node->children[1], info );
  4061. }
  4062. }
  4063. // Arbitrary split plane here
  4064. Vector cornermin, cornermax;
  4065. for (int i = 0; i < 3; ++i)
  4066. {
  4067. if (plane->normal[i] >= 0)
  4068. {
  4069. cornermin[i] = info.m_vecBoxMin[i];
  4070. cornermax[i] = info.m_vecBoxMax[i];
  4071. }
  4072. else
  4073. {
  4074. cornermin[i] = info.m_vecBoxMax[i];
  4075. cornermax[i] = info.m_vecBoxMin[i];
  4076. }
  4077. }
  4078. if (DotProduct( plane->normal, cornermax ) <= plane->dist)
  4079. {
  4080. return EnumerateLeafInBox_R( node->children[1], info );
  4081. }
  4082. else if (DotProduct( plane->normal, cornermin ) >= plane->dist)
  4083. {
  4084. return EnumerateLeafInBox_R( node->children[0], info );
  4085. }
  4086. else
  4087. {
  4088. // Here the box is split by the node
  4089. bool ret = EnumerateLeafInBox_R( node->children[0], info );
  4090. if (!ret)
  4091. return false;
  4092. return EnumerateLeafInBox_R( node->children[1], info );
  4093. }
  4094. }
  4095. #ifdef _X360
  4096. static fltx4 AlignThatVector(const Vector &vc)
  4097. {
  4098. fltx4 out = __loadunalignedvector(vc.Base());
  4099. /*
  4100. out.x = vc.x;
  4101. out.y = vc.y;
  4102. out.z = vc.z;
  4103. */
  4104. // squelch the w component
  4105. return __vrlimi( out, __vzero(), 1, 0 );
  4106. }
  4107. //-----------------------------------------------------------------------------
  4108. // Finds all leaves of the BSP tree within a particular volume
  4109. //-----------------------------------------------------------------------------
  4110. static bool EnumerateLeafInBox_R(mnode_t * RESTRICT node, const EnumLeafBoxInfo_t * RESTRICT pInfo )
  4111. {
  4112. // no polygons in solid nodes (don't report these leaves either)
  4113. if (node->contents == CONTENTS_SOLID)
  4114. return true; // solid
  4115. // speculatively get the children into the cache
  4116. __dcbt(0,node->children[0]);
  4117. __dcbt(0,node->children[1]);
  4118. // constructing these here prevents LHS if we spill.
  4119. // it's not quite a quick enough operation to do extemporaneously.
  4120. fltx4 infoBoxCenter = LoadAlignedSIMD(pInfo->m_vecBoxCenter);
  4121. fltx4 infoBoxHalfDiagonal = LoadAlignedSIMD(pInfo->m_vecBoxHalfDiagonal);
  4122. Assert(IsBoxIntersectingBoxExtents(AlignThatVector(node->m_vecCenter), AlignThatVector(node->m_vecHalfDiagonal),
  4123. LoadAlignedSIMD(pInfo->m_vecBoxCenter), LoadAlignedSIMD(pInfo->m_vecBoxHalfDiagonal)) ==
  4124. IsBoxIntersectingBoxExtents((node->m_vecCenter), node->m_vecHalfDiagonal,
  4125. pInfo->m_vecBoxCenter, pInfo->m_vecBoxHalfDiagonal));
  4126. // rough cull...
  4127. if (!IsBoxIntersectingBoxExtents(LoadAlignedSIMD(node->m_vecCenter), LoadAlignedSIMD(node->m_vecHalfDiagonal),
  4128. infoBoxCenter, infoBoxHalfDiagonal))
  4129. {
  4130. return true;
  4131. }
  4132. if (node->contents >= 0)
  4133. {
  4134. // if a leaf node, report it to the iterator...
  4135. return pInfo->m_pIterator->EnumerateLeaf( LeafToIndex( (mleaf_t *)node ), pInfo->m_nContext );
  4136. }
  4137. // Does the node plane split the box?
  4138. // find which side of the node we are on
  4139. cplane_t* RESTRICT plane = node->plane;
  4140. if ( plane->type <= PLANE_Z )
  4141. {
  4142. if (pInfo->m_vecBoxMax[plane->type] <= plane->dist)
  4143. {
  4144. return EnumerateLeafInBox_R( node->children[1], pInfo );
  4145. }
  4146. else if (pInfo->m_vecBoxMin[plane->type] >= plane->dist)
  4147. {
  4148. return EnumerateLeafInBox_R( node->children[0], pInfo );
  4149. }
  4150. else
  4151. {
  4152. // Here the box is split by the node
  4153. return EnumerateLeafInBox_R( node->children[0], pInfo ) &&
  4154. EnumerateLeafInBox_R( node->children[1], pInfo );
  4155. }
  4156. }
  4157. // Arbitrary split plane here
  4158. /*
  4159. Vector cornermin, cornermax;
  4160. for (int i = 0; i < 3; ++i)
  4161. {
  4162. if (plane->normal[i] >= 0)
  4163. {
  4164. cornermin[i] = info.m_vecBoxMin[i];
  4165. cornermax[i] = info.m_vecBoxMax[i];
  4166. }
  4167. else
  4168. {
  4169. cornermin[i] = info.m_vecBoxMax[i];
  4170. cornermax[i] = info.m_vecBoxMin[i];
  4171. }
  4172. }
  4173. */
  4174. // take advantage of high throughput/high latency
  4175. fltx4 planeNormal = LoadUnaligned3SIMD( plane->normal.Base() );
  4176. fltx4 vecBoxMin = LoadAlignedSIMD(pInfo->m_vecBoxMin);
  4177. fltx4 vecBoxMax = LoadAlignedSIMD(pInfo->m_vecBoxMax);
  4178. fltx4 cornermin, cornermax;
  4179. // by now planeNormal is ready...
  4180. fltx4 control = XMVectorGreaterOrEqual( planeNormal, __vzero() );
  4181. // now control[i] = planeNormal[i] > 0 ? 0xFF : 0x00
  4182. cornermin = XMVectorSelect( vecBoxMax, vecBoxMin, control); // cornermin[i] = control[i] ? vecBoxMin[i] : vecBoxMax[i]
  4183. cornermax = XMVectorSelect( vecBoxMin, vecBoxMax, control);
  4184. // compute dot products
  4185. fltx4 dotCornerMax = __vmsum3fp(planeNormal, cornermax); // vsumfp ignores w component
  4186. fltx4 dotCornerMin = __vmsum3fp(planeNormal, cornermin);
  4187. fltx4 vPlaneDist = ReplicateX4(plane->dist);
  4188. UINT conditionRegister;
  4189. XMVectorGreaterR(&conditionRegister,vPlaneDist,dotCornerMax);
  4190. if (XMComparisonAllTrue(conditionRegister)) // plane->normal . cornermax <= plane->dist
  4191. return EnumerateLeafInBox_R( node->children[1], pInfo );
  4192. XMVectorGreaterOrEqualR(&conditionRegister,dotCornerMin,vPlaneDist);
  4193. if ( XMComparisonAllTrue(conditionRegister) )
  4194. return EnumerateLeafInBox_R( node->children[0], pInfo );
  4195. return EnumerateLeafInBox_R( node->children[0], pInfo ) &&
  4196. EnumerateLeafInBox_R( node->children[1], pInfo );
  4197. /*
  4198. if (DotProduct( plane->normal, cornermax ) <= plane->dist)
  4199. {
  4200. return EnumerateLeafInBox_R( node->children[1], info, infoBoxCenter, infoBoxHalfDiagonal );
  4201. }
  4202. else if (DotProduct( plane->normal, cornermin ) >= plane->dist)
  4203. {
  4204. return EnumerateLeafInBox_R( node->children[0], info, infoBoxCenter, infoBoxHalfDiagonal );
  4205. }
  4206. else
  4207. {
  4208. // Here the box is split by the node
  4209. bool ret = EnumerateLeafInBox_R( node->children[0], info, infoBoxCenter, infoBoxHalfDiagonal );
  4210. if (!ret)
  4211. return false;
  4212. return EnumerateLeafInBox_R( node->children[1], info, infoBoxCenter, infoBoxHalfDiagonal );
  4213. }
  4214. */
  4215. }
  4216. #endif
  4217. //-----------------------------------------------------------------------------
  4218. // Returns all leaves that lie within a spherical volume
  4219. //-----------------------------------------------------------------------------
  4220. bool EnumerateLeafInSphere_R( mnode_t *node, EnumLeafSphereInfo_t& info, int nTestFlags )
  4221. {
  4222. while (true)
  4223. {
  4224. // no polygons in solid nodes (don't report these leaves either)
  4225. if (node->contents == CONTENTS_SOLID)
  4226. return true; // solid
  4227. if (node->contents >= 0)
  4228. {
  4229. // leaf cull...
  4230. // NOTE: using nTestFlags here means that we may be passing in some
  4231. // leaves that don't actually intersect the sphere, but instead intersect
  4232. // the box that surrounds the sphere.
  4233. if (nTestFlags)
  4234. {
  4235. if (!IsBoxIntersectingSphereExtents (node->m_vecCenter, node->m_vecHalfDiagonal, info.m_vecCenter, info.m_flRadius))
  4236. return true;
  4237. }
  4238. // if a leaf node, report it to the iterator...
  4239. return info.m_pIterator->EnumerateLeaf( LeafToIndex( (mleaf_t *)node ), info.m_nContext );
  4240. }
  4241. else if (nTestFlags)
  4242. {
  4243. if (node->contents == -1)
  4244. {
  4245. // faster cull...
  4246. if (nTestFlags & ENUM_SPHERE_TEST_X)
  4247. {
  4248. float flDelta = FloatMakePositive( node->m_vecCenter.x - info.m_vecBoxCenter.x );
  4249. float flSize = node->m_vecHalfDiagonal.x + info.m_vecBoxHalfDiagonal.x;
  4250. if ( flDelta > flSize )
  4251. return true;
  4252. // This checks for the node being completely inside the box...
  4253. if ( flDelta + node->m_vecHalfDiagonal.x < info.m_vecBoxHalfDiagonal.x )
  4254. nTestFlags &= ~ENUM_SPHERE_TEST_X;
  4255. }
  4256. if (nTestFlags & ENUM_SPHERE_TEST_Y)
  4257. {
  4258. float flDelta = FloatMakePositive( node->m_vecCenter.y - info.m_vecBoxCenter.y );
  4259. float flSize = node->m_vecHalfDiagonal.y + info.m_vecBoxHalfDiagonal.y;
  4260. if ( flDelta > flSize )
  4261. return true;
  4262. // This checks for the node being completely inside the box...
  4263. if ( flDelta + node->m_vecHalfDiagonal.y < info.m_vecBoxHalfDiagonal.y )
  4264. nTestFlags &= ~ENUM_SPHERE_TEST_Y;
  4265. }
  4266. if (nTestFlags & ENUM_SPHERE_TEST_Z)
  4267. {
  4268. float flDelta = FloatMakePositive( node->m_vecCenter.z - info.m_vecBoxCenter.z );
  4269. float flSize = node->m_vecHalfDiagonal.z + info.m_vecBoxHalfDiagonal.z;
  4270. if ( flDelta > flSize )
  4271. return true;
  4272. if ( flDelta + node->m_vecHalfDiagonal.z < info.m_vecBoxHalfDiagonal.z )
  4273. nTestFlags &= ~ENUM_SPHERE_TEST_Z;
  4274. }
  4275. }
  4276. else if (node->contents == -2)
  4277. {
  4278. // If the box is too small to bother with testing, then blat out the flags
  4279. nTestFlags = 0;
  4280. }
  4281. }
  4282. // Does the node plane split the sphere?
  4283. // find which side of the node we are on
  4284. float flNormalDotCenter;
  4285. cplane_t* plane = node->plane;
  4286. if ( plane->type <= PLANE_Z )
  4287. {
  4288. flNormalDotCenter = info.m_vecCenter[plane->type];
  4289. }
  4290. else
  4291. {
  4292. // Here, we've got a plane which is not axis aligned, so we gotta do more work
  4293. flNormalDotCenter = DotProduct( plane->normal, info.m_vecCenter );
  4294. }
  4295. if (flNormalDotCenter + info.m_flRadius <= plane->dist)
  4296. {
  4297. node = node->children[1];
  4298. }
  4299. else if (flNormalDotCenter - info.m_flRadius >= plane->dist)
  4300. {
  4301. node = node->children[0];
  4302. }
  4303. else
  4304. {
  4305. // Here the box is split by the node
  4306. if (!EnumerateLeafInSphere_R( node->children[0], info, nTestFlags ))
  4307. return false;
  4308. node = node->children[1];
  4309. }
  4310. }
  4311. }
  4312. //-----------------------------------------------------------------------------
  4313. // Enumerate leaves along a non-extruded ray
  4314. //-----------------------------------------------------------------------------
  4315. static bool EnumerateLeavesAlongRay_R( mnode_t *node, Ray_t const& ray,
  4316. float start, float end, ISpatialLeafEnumerator* pEnum, int context )
  4317. {
  4318. // no polygons in solid nodes (don't report these leaves either)
  4319. if (node->contents == CONTENTS_SOLID)
  4320. return true; // solid, keep recursing
  4321. // didn't hit anything
  4322. if (node->contents >= 0)
  4323. {
  4324. // if a leaf node, report it to the iterator...
  4325. return pEnum->EnumerateLeaf( LeafToIndex( (mleaf_t *)node ), context );
  4326. }
  4327. // Determine which side of the node plane our points are on
  4328. cplane_t* plane = node->plane;
  4329. float startDotN,deltaDotN;
  4330. if (plane->type <= PLANE_Z)
  4331. {
  4332. startDotN = ray.m_Start[plane->type];
  4333. deltaDotN = ray.m_Delta[plane->type];
  4334. }
  4335. else
  4336. {
  4337. startDotN = DotProduct( ray.m_Start, plane->normal );
  4338. deltaDotN = DotProduct( ray.m_Delta, plane->normal );
  4339. }
  4340. float front = startDotN + start * deltaDotN - plane->dist;
  4341. float back = startDotN + end * deltaDotN - plane->dist;
  4342. int side = front < 0;
  4343. // If they're both on the same side of the plane, don't bother to split
  4344. // just check the appropriate child
  4345. if ( (back < 0) == side )
  4346. {
  4347. return EnumerateLeavesAlongRay_R (node->children[side], ray, start, end, pEnum, context );
  4348. }
  4349. // calculate mid point
  4350. float frac = front / (front - back);
  4351. float mid = start * (1.0f - frac) + end * frac;
  4352. // go down front side
  4353. bool ok = EnumerateLeavesAlongRay_R (node->children[side], ray, start, mid, pEnum, context );
  4354. if (!ok)
  4355. return ok;
  4356. // go down back side
  4357. return EnumerateLeavesAlongRay_R (node->children[!side], ray, mid, end, pEnum, context );
  4358. }
  4359. //-----------------------------------------------------------------------------
  4360. // Enumerate leaves along a non-extruded ray
  4361. //-----------------------------------------------------------------------------
  4362. static bool EnumerateLeavesAlongExtrudedRay_R( mnode_t *node, Ray_t const& ray,
  4363. float start, float end, ISpatialLeafEnumerator* pEnum, int context )
  4364. {
  4365. // no polygons in solid nodes (don't report these leaves either)
  4366. if (node->contents == CONTENTS_SOLID)
  4367. return true; // solid, keep recursing
  4368. // didn't hit anything
  4369. if (node->contents >= 0)
  4370. {
  4371. // if a leaf node, report it to the iterator...
  4372. return pEnum->EnumerateLeaf( LeafToIndex( (mleaf_t *)node ), context );
  4373. }
  4374. // Determine which side of the node plane our points are on
  4375. cplane_t* plane = node->plane;
  4376. //
  4377. float t1, t2, offset;
  4378. float startDotN,deltaDotN;
  4379. if (plane->type <= PLANE_Z)
  4380. {
  4381. startDotN = ray.m_Start[plane->type];
  4382. deltaDotN = ray.m_Delta[plane->type];
  4383. offset = ray.m_Extents[plane->type] + DIST_EPSILON;
  4384. }
  4385. else
  4386. {
  4387. startDotN = DotProduct( ray.m_Start, plane->normal );
  4388. deltaDotN = DotProduct( ray.m_Delta, plane->normal );
  4389. offset = fabs(ray.m_Extents[0]*plane->normal[0]) +
  4390. fabs(ray.m_Extents[1]*plane->normal[1]) +
  4391. fabs(ray.m_Extents[2]*plane->normal[2]) + DIST_EPSILON;
  4392. }
  4393. t1 = startDotN + start * deltaDotN - plane->dist;
  4394. t2 = startDotN + end * deltaDotN - plane->dist;
  4395. // If they're both on the same side of the plane (further than the trace
  4396. // extents), don't bother to split, just check the appropriate child
  4397. if (t1 > offset && t2 > offset )
  4398. // if (t1 >= offset && t2 >= offset)
  4399. {
  4400. return EnumerateLeavesAlongExtrudedRay_R( node->children[0], ray,
  4401. start, end, pEnum, context );
  4402. }
  4403. if (t1 < -offset && t2 < -offset)
  4404. {
  4405. return EnumerateLeavesAlongExtrudedRay_R( node->children[1], ray,
  4406. start, end, pEnum, context );
  4407. }
  4408. // For the segment of the line that we are going to use
  4409. // to test against the back side of the plane, we're going
  4410. // to use the part that goes from start to plane + extent
  4411. // (which causes it to extend somewhat into the front halfspace,
  4412. // since plane + extent is in the front halfspace).
  4413. // Similarly, front the segment which tests against the front side,
  4414. // we use the entire front side part of the ray + a portion of the ray that
  4415. // extends by -extents into the back side.
  4416. if (fabs(t1-t2) < DIST_EPSILON)
  4417. {
  4418. // Parallel case, send entire ray to both children...
  4419. bool ret = EnumerateLeavesAlongExtrudedRay_R( node->children[0],
  4420. ray, start, end, pEnum, context );
  4421. if (!ret)
  4422. return false;
  4423. return EnumerateLeavesAlongExtrudedRay_R( node->children[1],
  4424. ray, start, end, pEnum, context );
  4425. }
  4426. // Compute the two fractions...
  4427. // We need one at plane + extent and another at plane - extent.
  4428. // put the crosspoint DIST_EPSILON pixels on the near side
  4429. float idist, frac2, frac;
  4430. int side;
  4431. if (t1 < t2)
  4432. {
  4433. idist = 1.0/(t1-t2);
  4434. side = 1;
  4435. frac2 = (t1 + offset) * idist;
  4436. frac = (t1 - offset) * idist;
  4437. }
  4438. else if (t1 > t2)
  4439. {
  4440. idist = 1.0/(t1-t2);
  4441. side = 0;
  4442. frac2 = (t1 - offset) * idist;
  4443. frac = (t1 + offset) * idist;
  4444. }
  4445. else
  4446. {
  4447. side = 0;
  4448. frac = 1;
  4449. frac2 = 0;
  4450. }
  4451. // move up to the node
  4452. frac = clamp( frac, 0.f, 1.f );
  4453. float midf = start + (end - start)*frac;
  4454. bool ret = EnumerateLeavesAlongExtrudedRay_R( node->children[side], ray, start, midf, pEnum, context );
  4455. if (!ret)
  4456. return ret;
  4457. // go past the node
  4458. frac2 = clamp( frac2, 0.f, 1.f );
  4459. midf = start + (end - start)*frac2;
  4460. return EnumerateLeavesAlongExtrudedRay_R( node->children[!side], ray, midf, end, pEnum, context );
  4461. }
  4462. //-----------------------------------------------------------------------------
  4463. //
  4464. // Helper class to iterate over leaves
  4465. //
  4466. //-----------------------------------------------------------------------------
  4467. class CEngineBSPTree : public IEngineSpatialQuery
  4468. {
  4469. public:
  4470. // Returns the number of leaves
  4471. int LeafCount() const;
  4472. // Enumerates the leaves along a ray, box, etc.
  4473. bool EnumerateLeavesAtPoint( const Vector& pt, ISpatialLeafEnumerator* pEnum, int context );
  4474. bool EnumerateLeavesInBox( const Vector& mins, const Vector& maxs, ISpatialLeafEnumerator* pEnum, int context );
  4475. bool EnumerateLeavesInSphere( const Vector& center, float radius, ISpatialLeafEnumerator* pEnum, int context );
  4476. bool EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context );
  4477. };
  4478. //-----------------------------------------------------------------------------
  4479. // Singleton accessor
  4480. //-----------------------------------------------------------------------------
  4481. static CEngineBSPTree s_ToolBSPTree;
  4482. IEngineSpatialQuery* g_pToolBSPTree = &s_ToolBSPTree;
  4483. //-----------------------------------------------------------------------------
  4484. // Returns the number of leaves
  4485. //-----------------------------------------------------------------------------
  4486. int CEngineBSPTree::LeafCount() const
  4487. {
  4488. return host_state.worldbrush->numleafs;
  4489. }
  4490. //-----------------------------------------------------------------------------
  4491. // Enumerates the leaves at a point
  4492. //-----------------------------------------------------------------------------
  4493. bool CEngineBSPTree::EnumerateLeavesAtPoint( const Vector& pt,
  4494. ISpatialLeafEnumerator* pEnum, int context )
  4495. {
  4496. int leaf = CM_PointLeafnum( pt );
  4497. return pEnum->EnumerateLeaf( leaf, context );
  4498. }
  4499. static ConVar opt_EnumerateLeavesFastAlgorithm( "opt_EnumerateLeavesFastAlgorithm", "1", FCVAR_NONE, "Use the new SIMD version of CEngineBSPTree::EnumerateLeavesInBox." );
  4500. bool CEngineBSPTree::EnumerateLeavesInBox( const Vector& mins, const Vector& maxs,
  4501. ISpatialLeafEnumerator* pEnum, int context )
  4502. {
  4503. if ( !host_state.worldmodel )
  4504. return false;
  4505. EnumLeafBoxInfo_t info;
  4506. VectorAdd( mins, maxs, info.m_vecBoxCenter );
  4507. info.m_vecBoxCenter *= 0.5f;
  4508. VectorSubtract( maxs, info.m_vecBoxCenter, info.m_vecBoxHalfDiagonal );
  4509. info.m_pIterator = pEnum;
  4510. info.m_nContext = context;
  4511. info.m_vecBoxMax = maxs;
  4512. info.m_vecBoxMin = mins;
  4513. #ifdef _X360
  4514. if (opt_EnumerateLeavesFastAlgorithm.GetBool())
  4515. return EnumerateLeafInBox_R( host_state.worldbrush->nodes, &info );
  4516. else
  4517. return EnumerateLeafInBox_R( host_state.worldbrush->nodes, info );
  4518. #else
  4519. return EnumerateLeafInBox_R( host_state.worldbrush->nodes, info );
  4520. #endif
  4521. }
  4522. bool CEngineBSPTree::EnumerateLeavesInSphere( const Vector& center, float radius,
  4523. ISpatialLeafEnumerator* pEnum, int context )
  4524. {
  4525. EnumLeafSphereInfo_t info;
  4526. info.m_vecCenter = center;
  4527. info.m_flRadius = radius;
  4528. info.m_pIterator = pEnum;
  4529. info.m_nContext = context;
  4530. info.m_vecBoxCenter = center;
  4531. info.m_vecBoxHalfDiagonal.Init( radius, radius, radius );
  4532. return EnumerateLeafInSphere_R( host_state.worldbrush->nodes, info, ENUM_SPHERE_TEST_ALL );
  4533. }
  4534. bool CEngineBSPTree::EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, int context )
  4535. {
  4536. if (!ray.m_IsSwept)
  4537. {
  4538. Vector mins, maxs;
  4539. VectorAdd( ray.m_Start, ray.m_Extents, maxs );
  4540. VectorSubtract( ray.m_Start, ray.m_Extents, mins );
  4541. return EnumerateLeavesInBox( mins, maxs, pEnum, context );
  4542. }
  4543. Vector end;
  4544. VectorAdd( ray.m_Start, ray.m_Delta, end );
  4545. if ( ray.m_IsRay )
  4546. {
  4547. return EnumerateLeavesAlongRay_R( host_state.worldbrush->nodes, ray, 0.0f, 1.0f, pEnum, context );
  4548. }
  4549. else
  4550. {
  4551. return EnumerateLeavesAlongExtrudedRay_R( host_state.worldbrush->nodes, ray, 0.0f, 1.0f, pEnum, context );
  4552. }
  4553. }