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

6465 lines
204 KiB

  1. //===== Copyright (c) 1996-2007, 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 "brushbatchrender.h"
  28. #include "bsptreedata.h"
  29. #include "cmodel_private.h"
  30. #include "tier0/dbg.h"
  31. #include "crtmemdebug.h"
  32. #include "iclientrenderable.h"
  33. #include "icliententitylist.h"
  34. #include "icliententity.h"
  35. #include "gl_rmain.h"
  36. #include "tier0/vprof.h"
  37. #include "bitvec.h"
  38. #include "debugoverlay.h"
  39. #include "host.h"
  40. #include "materialsystem/imaterialsystemhardwareconfig.h"
  41. #include "cl_main.h"
  42. #include "cmodel_engine.h"
  43. #include "r_decal.h"
  44. #include "materialsystem/materialsystem_config.h"
  45. #include "materialsystem/imaterialproxy.h"
  46. #include "materialsystem/imaterialvar.h"
  47. #include "coordsize.h"
  48. #include "mempool.h"
  49. #include "tier0/cache_hints.h"
  50. #ifndef DEDICATED
  51. #include "Overlay.h"
  52. #endif
  53. #include "paint.h"
  54. #include "disp.h"
  55. #include "mathlib/volumeculler.h"
  56. #include "vstdlib/jobthread.h"
  57. #if defined(_PS3)
  58. #include "buildindices_PS3.h"
  59. #include "buildworldlists_PS3.h"
  60. #endif
  61. // memdbgon must be the last include file in a .cpp file!!!
  62. #include "tier0/memdbgon.h"
  63. //-----------------------------------------------------------------------------
  64. // forward declarations
  65. //-----------------------------------------------------------------------------
  66. class IClientEntity;
  67. // interface to shader drawing
  68. void Shader_BrushBegin( model_t *model, IClientEntity *baseentity = NULL );
  69. void Shader_BrushSurfaceOverride( IMatRenderContext *pRenderContext, SurfaceHandle_t surfID, model_t *model, IClientEntity *baseentity = NULL );
  70. void Shader_BrushEnd( IMatRenderContext *pRenderContext, VMatrix const* brushToWorld, model_t *model, bool bShadowDepth, IClientEntity *baseentity = NULL );
  71. void BuildMSurfaceVertexArrays( worldbrushdata_t *pBrushData, SurfaceHandle_t surfID, CMeshBuilder &builder );
  72. ConVar r_hidepaintedsurfaces( "r_hidepaintedsurfaces", "0", 0, "If enabled, hides all surfaces which have been painted." );
  73. //-----------------------------------------------------------------------------
  74. // Information about the fog volumes for this pass of rendering
  75. //-----------------------------------------------------------------------------
  76. struct FogState_t
  77. {
  78. MaterialFogMode_t m_FogMode;
  79. float m_FogStart;
  80. float m_FogEnd;
  81. float m_FogColor[3];
  82. bool m_FogEnabled;
  83. };
  84. struct FogVolumeInfo_t : public FogState_t
  85. {
  86. bool m_InFogVolume;
  87. float m_FogSurfaceZ;
  88. float m_FogMinZ;
  89. int m_FogVolumeID;
  90. };
  91. //-----------------------------------------------------------------------------
  92. // Cached convars...
  93. //-----------------------------------------------------------------------------
  94. struct CachedConvars_t
  95. {
  96. bool m_bDrawWorld;
  97. int m_nDrawLeaf;
  98. bool m_bDrawFuncDetail;
  99. };
  100. static CachedConvars_t s_ShaderConvars;
  101. // AR - moved so DEDICATED can access these vars
  102. Frustum_t g_Frustum;
  103. //-----------------------------------------------------------------------------
  104. // Convars
  105. //-----------------------------------------------------------------------------
  106. static ConVar r_drawtranslucentworld( "r_drawtranslucentworld", "1", FCVAR_CHEAT );
  107. static ConVar mat_forcedynamic( "mat_forcedynamic", "0", FCVAR_CHEAT );
  108. static ConVar r_drawleaf( "r_drawleaf", "-1", FCVAR_CHEAT, "Draw the specified leaf." );
  109. static ConVar r_drawworld( "r_drawworld", "1", FCVAR_CHEAT, "Render the world." );
  110. static ConVar r_drawfuncdetail( "r_drawfuncdetail", "1", FCVAR_CHEAT, "Render func_detail" );
  111. static ConVar fog_enable_water_fog( "fog_enable_water_fog", "1", FCVAR_CHEAT );
  112. ConVar r_fastzreject( "r_fastzreject", "0", 0, "Activate/deactivates a fast z-setting algorithm to take advantage of hardware with fast z reject. Use -1 to default to hardware settings" );
  113. static ConVar r_fastzrejectdisp( "r_fastzrejectdisp", "0", 0, "Activates/deactivates fast z rejection on displacements (360 only). Only active when r_fastzreject is on." );
  114. ConVar r_skybox_draw_last( "r_skybox_draw_last", IsPS3()? "1" : "0", 0, "Draws skybox after world brush geometry, rather than before." );
  115. #if defined(_PS3)
  116. ConVar r_PS3_SPU_buildindices( "r_PS3_SPU_buildindices", "1", 0, "0: PPU, 1: SPU, 2: SPU with debug stop on job entry" );
  117. ConVar r_PS3_SPU_buildworldlists( "r_PS3_SPU_buildworldlists", "1", 0, "0: PPU, 1: SPU" );
  118. #endif
  119. ConVar r_csm_static_vb("r_csm_static_vb","1", 0, "Use a precomputed static VB for CSM rendering");
  120. ConVar r_csm_fast_path("r_csm_fast_path","1", FCVAR_DEVELOPMENTONLY, "Use shadow fast path for CSM rendering - minimize number of draw call");
  121. //-----------------------------------------------------------------------------
  122. // Installs a client-side renderer for brush models
  123. //-----------------------------------------------------------------------------
  124. static IBrushRenderer* s_pBrushRenderOverride = 0;
  125. //-----------------------------------------------------------------------------
  126. // Make sure we don't render the same surfaces twice
  127. //-----------------------------------------------------------------------------
  128. int r_surfacevisframe = 0;
  129. #define r_surfacevisframe dont_use_r_surfacevisframe_here
  130. //-----------------------------------------------------------------------------
  131. // Fast z reject displacements?
  132. //-----------------------------------------------------------------------------
  133. static bool s_bFastZRejectDisplacements = false;
  134. //-----------------------------------------------------------------------------
  135. // Top view bounds
  136. //-----------------------------------------------------------------------------
  137. static bool r_drawtopview = false;
  138. static bool r_bTopViewNoBackfaceCulling = false;
  139. static bool r_bTopViewNoVisCheck = false;
  140. // These have to be explicitly initialized because in debug builds Vector2D's default
  141. // constructor initializes the components to VEC_T_NAN, leading to asserts and errors.
  142. static Vector2D s_OrthographicCenter(0.0f, 0.0f);
  143. static Vector2D s_OrthographicHalfDiagonal(0.0f, 0.0f);
  144. static const CVolumeCuller *s_pTopViewVolumeCuller = NULL;
  145. //-----------------------------------------------------------------------------
  146. //
  147. //-----------------------------------------------------------------------------
  148. class CVisitedSurfs
  149. {
  150. public:
  151. FORCEINLINE bool VisitSurface( SurfaceHandle_t surfID )
  152. {
  153. return !m_bits.TestAndSet( MSurf_Index( surfID ) );
  154. }
  155. FORCEINLINE void MarkSurfaceVisited( SurfaceHandle_t surfID )
  156. {
  157. m_bits.Set( MSurf_Index( surfID ) );
  158. }
  159. FORCEINLINE bool VisitedSurface( SurfaceHandle_t surfID )
  160. {
  161. return m_bits.IsBitSet( MSurf_Index( surfID ) );
  162. }
  163. FORCEINLINE bool VisitedSurface( int index )
  164. {
  165. return m_bits.IsBitSet( index );
  166. }
  167. FORCEINLINE int GetSize() { return m_bits.GetNumBits(); }
  168. void Resize( int nSurfaces )
  169. {
  170. m_bits.Resize(nSurfaces);
  171. }
  172. void ClearAll()
  173. {
  174. m_bits.ClearAll();
  175. }
  176. CVarBitVec m_bits;
  177. };
  178. //-----------------------------------------------------------------------------
  179. // Returns planes in brush models
  180. //-----------------------------------------------------------------------------
  181. int R_GetBrushModelPlaneCount( const model_t *model )
  182. {
  183. return model->brush.nummodelsurfaces;
  184. }
  185. const cplane_t &R_GetBrushModelPlane( const model_t *model, int nIndex, Vector *pOrigin )
  186. {
  187. SurfaceHandle_t surfID = SurfaceHandleFromIndex( model->brush.firstmodelsurface, model->brush.pShared );
  188. surfID += nIndex;
  189. Assert( !(MSurf_Flags( surfID ) & SURFDRAW_NODRAW) );
  190. if ( pOrigin )
  191. {
  192. int vertCount = MSurf_VertCount( surfID );
  193. if ( vertCount > 0 )
  194. {
  195. int nFirstVertex = model->brush.pShared->vertindices[MSurf_FirstVertIndex( surfID )];
  196. *pOrigin = model->brush.pShared->vertexes[nFirstVertex].position;
  197. }
  198. else
  199. {
  200. const cplane_t &plane = MSurf_Plane( surfID );
  201. VectorMultiply( plane.normal, plane.dist, *pOrigin );
  202. }
  203. }
  204. return MSurf_Plane( surfID );
  205. }
  206. //-----------------------------------------------------------------------------
  207. // Computes the centroid of a surface
  208. //-----------------------------------------------------------------------------
  209. void Surf_ComputeCentroid( SurfaceHandle_t surfID, Vector *pVecCentroid )
  210. {
  211. int nCount = MSurf_VertCount( surfID );
  212. int nFirstVertIndex = MSurf_FirstVertIndex( surfID );
  213. float flTotalArea = 0.0f;
  214. Vector vecNormal;
  215. pVecCentroid->Init(0,0,0);
  216. int vertIndex = host_state.worldbrush->vertindices[nFirstVertIndex];
  217. Vector vecApex = host_state.worldbrush->vertexes[vertIndex].position;
  218. for (int v = 1; v < nCount - 1; ++v )
  219. {
  220. vertIndex = host_state.worldbrush->vertindices[nFirstVertIndex+v];
  221. Vector v1 = host_state.worldbrush->vertexes[vertIndex].position;
  222. vertIndex = host_state.worldbrush->vertindices[nFirstVertIndex+v+1];
  223. Vector v2 = host_state.worldbrush->vertexes[vertIndex].position;
  224. CrossProduct( v2 - v1, v1 - vecApex, vecNormal );
  225. float flArea = vecNormal.Length();
  226. flTotalArea += flArea;
  227. *pVecCentroid += (vecApex + v1 + v2) * flArea / 3.0f;
  228. }
  229. if (flTotalArea)
  230. {
  231. *pVecCentroid /= flTotalArea;
  232. }
  233. }
  234. //-----------------------------------------------------------------------------
  235. // Converts sort infos to lightmap pages
  236. //-----------------------------------------------------------------------------
  237. int SortInfoToLightmapPage( int sortID )
  238. {
  239. return materialSortInfoArray[sortID].lightmapPageID;
  240. }
  241. #ifndef DEDICATED
  242. class CWorldRenderList : public CRefCounted1<IWorldRenderList>
  243. {
  244. public:
  245. CWorldRenderList()
  246. {
  247. }
  248. ~CWorldRenderList()
  249. {
  250. Purge();
  251. }
  252. #if defined(_PS3)
  253. static CWorldRenderList *FindOrCreateList_PS3( int nSurfaces, int viewID );
  254. #endif
  255. static CWorldRenderList *FindOrCreateList( int nSurfaces )
  256. {
  257. CWorldRenderList *p = g_Pool.GetObject();
  258. if ( p->m_VisitedSurfs.GetSize() != nSurfaces )
  259. {
  260. p->Init(nSurfaces);
  261. }
  262. else
  263. {
  264. p->AddRef();
  265. AssertMsg( p->m_VisitedSurfs.GetSize() == nSurfaces, "World render list pool not cleared between maps" );
  266. }
  267. return p;
  268. }
  269. static void PurgeAll()
  270. {
  271. CWorldRenderList *p;
  272. while ( ( p = g_Pool.GetObject( false ) ) != NULL )
  273. {
  274. p->Purge();
  275. delete p;
  276. }
  277. }
  278. virtual bool OnFinalRelease()
  279. {
  280. Reset();
  281. g_Pool.PutObject( this );
  282. return false;
  283. }
  284. void Init( int nSurfaces )
  285. {
  286. m_SortList.Init(materials->GetNumSortIDs(), 512);
  287. m_DispSortList.Init(materials->GetNumSortIDs(), 32);
  288. m_VisitedSurfs.Resize( nSurfaces );
  289. m_leaves.EnsureCapacity(1024);
  290. #if defined(_PS3)
  291. m_SPUDecalSurfsToAdd.EnsureCapacity(0x180);
  292. #endif
  293. m_DecalSurfsToAdd.EnsureCapacity( 512 );
  294. m_bSkyVisible = false;
  295. m_bWaterVisible = false;
  296. }
  297. void Purge()
  298. {
  299. m_leaves.Purge();
  300. for ( int i = 0; i < MAX_MAT_SORT_GROUPS; i++ )
  301. {
  302. m_ShadowHandles[i].Purge();
  303. m_DlightSurfaces[i].Purge();
  304. m_PaintedSurfaces[i].Purge();
  305. }
  306. m_SortList.Shutdown();
  307. m_DispSortList.Shutdown();
  308. m_AlphaSurfaces.Purge();
  309. #if defined(_PS3)
  310. m_SPUDecalSurfsToAdd.Purge();
  311. #endif
  312. m_DecalSurfsToAdd.Purge();
  313. }
  314. void Reset()
  315. {
  316. m_SortList.Reset();
  317. m_AlphaSurfaces.RemoveAll();
  318. m_DispSortList.Reset();
  319. m_bSkyVisible = false;
  320. m_bWaterVisible = false;
  321. for (int j = 0; j < MAX_MAT_SORT_GROUPS; ++j)
  322. {
  323. //Assert(pRenderList->m_ShadowHandles[j].Count() == 0 );
  324. m_ShadowHandles[j].RemoveAll();
  325. m_DlightSurfaces[j].RemoveAll();
  326. m_PaintedSurfaces[j].RemoveAll();
  327. }
  328. // We haven't found any visible leafs this frame
  329. m_leaves.RemoveAll();
  330. #if defined(_PS3)
  331. m_SPUDecalSurfsToAdd.RemoveAll();
  332. #endif
  333. m_DecalSurfsToAdd.RemoveAll();
  334. m_VisitedSurfs.ClearAll();
  335. }
  336. void CountTranslucentSurfaces()
  337. {
  338. int count = m_leaves.Count();
  339. if ( count > 0 )
  340. {
  341. int test = m_leaves[0].firstTranslucentSurface;
  342. for ( int i = 1; i < count; i++ )
  343. {
  344. int transCount = m_leaves[i].firstTranslucentSurface - test;
  345. if ( transCount )
  346. {
  347. m_leaves[i-1].translucentSurfaceCount = transCount;
  348. test = m_leaves[i].firstTranslucentSurface;
  349. }
  350. }
  351. if ( m_leaves[count-1].firstTranslucentSurface != m_AlphaSurfaces.Count() )
  352. {
  353. m_leaves[count-1].translucentSurfaceCount = m_AlphaSurfaces.Count() - m_leaves[count-1].firstTranslucentSurface;
  354. }
  355. }
  356. }
  357. void QueueDecalSurf( SurfaceHandle_t surfID, int renderGroup )
  358. {
  359. DecalSurfPair_t decal;
  360. decal.m_surfID = surfID;
  361. decal.m_renderGroup = renderGroup;
  362. m_DecalSurfsToAdd.AddToTail( decal );
  363. }
  364. void AddDecalSurfs( void )
  365. {
  366. int count = m_DecalSurfsToAdd.Count();
  367. for( int i = 0; i < count ; i++ )
  368. {
  369. const DecalSurfPair_t& surfPair = m_DecalSurfsToAdd[i];
  370. DecalSurfaceAdd( surfPair.m_surfID, surfPair.m_renderGroup );
  371. }
  372. }
  373. #if defined(_PS3)
  374. // kludgy, but get theory of this working first TODO:tidy...
  375. // these must match the same definitions in job_worldlists.cpp
  376. #define MAX_DRAWN_SURF 0x260
  377. #define MAX_LEAVES 0x520
  378. #define MAX_DECAL_SURF 0x180
  379. void EnsureCapacityForSPU( int maxSortID, int surfVisited )
  380. {
  381. m_SortList.EnsureCapacityForSPU(maxSortID, MAX_DRAWN_SURF);
  382. m_DispSortList.EnsureCapacityForSPU(maxSortID, MAX_DRAWN_SURF/8); // was 32
  383. m_VisitedSurfs.Resize( surfVisited );
  384. m_leaves.EnsureCapacity(MAX_LEAVES);
  385. m_AlphaSurfaces.EnsureCapacity(MAX_DRAWN_SURF/2); // was 512
  386. for ( int i = 0; i < MAX_MAT_SORT_GROUPS; i++ )
  387. {
  388. m_DlightSurfaces[i].EnsureCapacity(MAX_DRAWN_SURF/4);
  389. m_PaintedSurfaces[i].EnsureCapacity(MAX_DRAWN_SURF/4);
  390. }
  391. m_bSkyVisible = false;
  392. m_bWaterVisible = false;
  393. m_VisitedSurfs.ClearAll();
  394. m_SPUDecalSurfsToAdd.EnsureCapacity(MAX_DECAL_SURF);
  395. }
  396. void FillOutputParamsForSPU( job_buildworldlists::buildWorldListsDMAOut *pDMAOut )
  397. {
  398. // renderlist destination dma data
  399. // m_SortList
  400. pDMAOut->m_pSortList_m_list = uintp(m_SortList.GetMaterialList());
  401. pDMAOut->m_pSortList_m_listUtlPtr = uintp(m_SortList.GetMaterialListUtlPtr());
  402. pDMAOut->m_pSortList_m_groupsShared = uintp(m_SortList.GetGroupsShared());
  403. pDMAOut->m_pSortList_m_groupsSharedUtlPtr = uintp(m_SortList.GetGroupsSharedUtlPtr());
  404. pDMAOut->m_pSortList_m_groupIndices = uintp(m_SortList.GetGroupIndices());
  405. pDMAOut->m_pSortList_m_groupIndicesUtlPtr = uintp(m_SortList.GetGroupIndicesUtlPtr());
  406. for( int lp = 0; lp < MAX_MAT_SORT_GROUPS; lp++ )
  407. {
  408. pDMAOut->m_pSortList_m_sortGroupLists[lp] = uintp(m_SortList.GetSortGroupLists( lp ));
  409. pDMAOut->m_pSortList_m_sortGroupListsUtlPtr[lp] = uintp(m_SortList.GetSortGroupListsUtlPtr( lp ));
  410. }
  411. // m_DispSortList
  412. pDMAOut->m_pDispSortList_m_list = uintp(m_DispSortList.GetMaterialList());
  413. pDMAOut->m_pDispSortList_m_listUtlPtr = uintp(m_DispSortList.GetMaterialListUtlPtr());
  414. pDMAOut->m_pDispSortList_m_groupsShared = uintp(m_DispSortList.GetGroupsShared());
  415. pDMAOut->m_pDispSortList_m_groupsSharedUtlPtr = uintp(m_DispSortList.GetGroupsSharedUtlPtr());
  416. pDMAOut->m_pDispSortList_m_groupIndices = uintp(m_DispSortList.GetGroupIndices());
  417. pDMAOut->m_pDispSortList_m_groupIndicesUtlPtr = uintp(m_DispSortList.GetGroupIndicesUtlPtr());
  418. for( int lp = 0; lp < MAX_MAT_SORT_GROUPS; lp++ )
  419. {
  420. pDMAOut->m_pDispSortList_m_sortGroupLists[lp] = uintp(m_DispSortList.GetSortGroupLists( lp ));
  421. pDMAOut->m_pDispSortList_m_sortGroupListsUtlPtr[lp] = uintp(m_DispSortList.GetSortGroupListsUtlPtr( lp ));
  422. }
  423. // m_AlphaSurfaces
  424. pDMAOut->m_pAlphaSurfaces = uintp(m_AlphaSurfaces.Base());
  425. pDMAOut->m_pAlphaSurfacesUtlPtr = uintp(&m_AlphaSurfaces);
  426. // m_DlightSurfaces
  427. for( int lp = 0; lp < MAX_MAT_SORT_GROUPS; lp++ )
  428. {
  429. pDMAOut->m_pDlightSurfaces[lp] = uintp(m_DlightSurfaces[lp].Base());
  430. pDMAOut->m_pDlightSurfacesUtlPtr[lp] = uintp(&m_DlightSurfaces[lp]);
  431. }
  432. // m_PaintedSurfaces
  433. for( int lp = 0; lp < MAX_MAT_SORT_GROUPS; lp++ )
  434. {
  435. pDMAOut->m_pPaintedSurfaces[lp] = uintp(m_PaintedSurfaces[lp].Base());
  436. pDMAOut->m_pPaintedSurfacesUtlPtr[lp] = uintp(&m_PaintedSurfaces[lp]);
  437. }
  438. // m_leaves
  439. pDMAOut->m_pLeaves = uintp(m_leaves.Base());
  440. pDMAOut->m_pLeavesUtlPtr = uintp(&m_leaves);
  441. // m_VisitedSurfs
  442. pDMAOut->m_pVisitedSurfs = uintp(m_VisitedSurfs.m_bits.Base());
  443. // decal surfs to add
  444. pDMAOut->m_pDecalSurfsToAdd = uintp(m_SPUDecalSurfsToAdd.Base());
  445. pDMAOut->m_pDecalSurfsToAddUtlPtr = uintp(&m_SPUDecalSurfsToAdd);
  446. // m_bSkyVisible
  447. pDMAOut->m_pSkyVisible = uintp(&m_bSkyVisible);
  448. // m_bWaterVisible
  449. pDMAOut->m_pWaterVisible = uintp(&m_bWaterVisible);
  450. }
  451. void AddSPUDecalSurfs( void )
  452. {
  453. int count = m_SPUDecalSurfsToAdd.Count();
  454. for( int i = 0; i < count ; i++ )
  455. {
  456. job_buildworldlists::decalSurfPair &surfPair = m_SPUDecalSurfsToAdd[i];
  457. DecalSurfaceAdd( (SurfaceHandle_t)surfPair.m_surfID, surfPair.m_renderGroup );
  458. }
  459. }
  460. CUtlVector<job_buildworldlists::decalSurfPair> m_SPUDecalSurfsToAdd;
  461. #endif
  462. struct DecalSurfPair_t
  463. {
  464. SurfaceHandle_t m_surfID;
  465. int m_renderGroup;
  466. };
  467. CMSurfaceSortList m_SortList;
  468. CMSurfaceSortList m_DispSortList;
  469. CUtlVector<SurfaceHandle_t> m_AlphaSurfaces;
  470. //-------------------------------------------------------------------------
  471. // List of decals to render this frame (need an extra one for brush models)
  472. //-------------------------------------------------------------------------
  473. CUtlVector<ShadowDecalHandle_t> m_ShadowHandles[MAX_MAT_SORT_GROUPS];
  474. // list of surfaces with dynamic lightmaps
  475. CUtlVector<SurfaceHandle_t> m_DlightSurfaces[MAX_MAT_SORT_GROUPS];
  476. // PORTAL 2 HACK
  477. // list of surfaces with paint applied
  478. CUtlVector<SurfaceHandle_t> m_PaintedSurfaces[MAX_MAT_SORT_GROUPS];
  479. //-------------------------------------------------------------------------
  480. // Used to generate a list of the leaves visited, and in back-to-front order
  481. // for this frame of rendering
  482. //-------------------------------------------------------------------------
  483. CUtlVector<WorldListLeafData_t> m_leaves;
  484. //-------------------------------------------------------------------------
  485. // List of decals queued when building world list as DecalSurfaceAdd is not
  486. // threadsafe. Decals are then added in R_BuildWorldLists_Epilogue
  487. //-------------------------------------------------------------------------
  488. CUtlVector<DecalSurfPair_t> m_DecalSurfsToAdd;
  489. CVisitedSurfs m_VisitedSurfs;
  490. bool m_bSkyVisible;
  491. bool m_bWaterVisible;
  492. static CObjectPool<CWorldRenderList> g_Pool;
  493. };
  494. CObjectPool<CWorldRenderList> CWorldRenderList::g_Pool;
  495. IWorldRenderList *AllocWorldRenderList()
  496. {
  497. return CWorldRenderList::FindOrCreateList( host_state.worldbrush->numsurfaces );
  498. }
  499. #if defined(_PS3)
  500. static CWorldRenderList g_Pool_PS3[ MAX_CONCURRENT_BUILDVIEWS ];
  501. // use viewID to ensure a unique list is grabbed from the pool every time
  502. IWorldRenderList *AllocWorldRenderList_PS3( int viewID )
  503. {
  504. return CWorldRenderList::FindOrCreateList_PS3( host_state.worldbrush->numsurfaces, viewID );
  505. }
  506. CWorldRenderList *CWorldRenderList::FindOrCreateList_PS3( int nSurfaces, int viewID )
  507. {
  508. if( viewID >= MAX_CONCURRENT_BUILDVIEWS )
  509. {
  510. Error("*** Exceeded max concurrent buildviews, FindOrCreateList_PS3 ***\n");
  511. }
  512. CWorldRenderList *p = &g_Pool_PS3[ viewID ];
  513. if ( p->m_VisitedSurfs.GetSize() != nSurfaces )
  514. {
  515. p->Init(nSurfaces);
  516. }
  517. // else
  518. // {
  519. // p->AddRef();
  520. // AssertMsg( p->m_VisitedSurfs.GetSize() == nSurfaces, "World render list pool not cleared between maps" );
  521. // }
  522. return p;
  523. }
  524. #endif
  525. //-----------------------------------------------------------------------------
  526. // Activates top view
  527. //-----------------------------------------------------------------------------
  528. void R_DrawTopView( bool enable )
  529. {
  530. r_drawtopview = enable;
  531. }
  532. void R_TopViewNoBackfaceCulling( bool bDisable )
  533. {
  534. r_bTopViewNoBackfaceCulling = bDisable;
  535. }
  536. void R_TopViewNoVisCheck( bool bDisable )
  537. {
  538. r_bTopViewNoVisCheck = bDisable;
  539. }
  540. void R_TopViewBounds( Vector2D const& mins, Vector2D const& maxs )
  541. {
  542. Vector2DAdd( maxs, mins, s_OrthographicCenter );
  543. s_OrthographicCenter *= 0.5f;
  544. Vector2DSubtract( maxs, s_OrthographicCenter, s_OrthographicHalfDiagonal );
  545. }
  546. void R_SetTopViewVolumeCuller( const CVolumeCuller *pTopViewVolumeCuller )
  547. {
  548. s_pTopViewVolumeCuller = pTopViewVolumeCuller;
  549. }
  550. //-----------------------------------------------------------------------------
  551. // Adds surfaces to list of things to render
  552. //-----------------------------------------------------------------------------
  553. void Shader_TranslucentWorldSurface( CWorldRenderList *pRenderList, SurfaceHandle_t surfID )
  554. {
  555. Assert( !SurfaceHasDispInfo( surfID ) && (pRenderList->m_leaves.Count() > 0) );
  556. // Hook into the chain of translucent objects for this leaf
  557. int sortGroup = MSurf_SortGroup( surfID );
  558. pRenderList->m_AlphaSurfaces.AddToTail( surfID );
  559. if ( MSurf_Flags( surfID ) & (SURFDRAW_HASLIGHTSYTLES|SURFDRAW_HASDLIGHT) )
  560. {
  561. pRenderList->m_DlightSurfaces[sortGroup].AddToTail( surfID );
  562. }
  563. }
  564. static inline void Shader_WorldSurface( CWorldRenderList *pRenderList, SurfaceHandle_t surfID )
  565. {
  566. // Hook it into the list of surfaces to render with this material
  567. // Do it in a way that generates a front-to-back ordering for fast z reject
  568. Assert( !SurfaceHasDispInfo( surfID ) );
  569. // Each surface is in exactly one group
  570. int nSortGroup = MSurf_SortGroup( surfID );
  571. // Add decals on non-displacement surfaces
  572. if( SurfaceHasDecals( surfID ) )
  573. {
  574. DecalSurfaceAdd( surfID, nSortGroup );
  575. }
  576. int nMaterialSortID = MSurf_MaterialSortID( surfID );
  577. if ( MSurf_Flags( surfID ) & (SURFDRAW_HASLIGHTSYTLES|SURFDRAW_HASDLIGHT) )
  578. {
  579. pRenderList->m_DlightSurfaces[nSortGroup].AddToTail( surfID );
  580. }
  581. if ( MSurf_Flags( surfID ) & SURFDRAW_PAINTED )
  582. {
  583. pRenderList->m_PaintedSurfaces[nSortGroup].AddToTail( surfID );
  584. }
  585. pRenderList->m_SortList.AddSurfaceToTail( surfID, nSortGroup, nMaterialSortID );
  586. }
  587. //-----------------------------------------------------------------------------
  588. // Adds displacement surfaces to list of things to render
  589. //-----------------------------------------------------------------------------
  590. void Shader_TranslucentDisplacementSurface( CWorldRenderList *pRenderList, SurfaceHandle_t surfID )
  591. {
  592. Assert( SurfaceHasDispInfo( surfID ) && (pRenderList->m_leaves.Count() > 0));
  593. // For translucent displacement surfaces, they can exist in many
  594. // leaves. We want to choose the leaf that's closest to the camera
  595. // to render it in. Thankfully, we're iterating the tree in front-to-back
  596. // order, so this is very simple.
  597. // NOTE: You might expect some problems here when displacements cross fog volume
  598. // planes. However, these problems go away (I hope!) because the first planes
  599. // that split a scene are the fog volume planes. That means that if we're
  600. // in a fog volume, the closest leaf that the displacement will be in will
  601. // also be in the fog volume. If we're not in a fog volume, the closest
  602. // leaf that the displacement will be in will not be a fog volume. That should
  603. // hopefully hide any discontinuities between fog state that occur when
  604. // rendering displacements that straddle fog volume boundaries.
  605. // Each surface is in exactly one group
  606. int sortGroup = MSurf_SortGroup( surfID );
  607. if ( MSurf_Flags( surfID ) & (SURFDRAW_HASLIGHTSYTLES|SURFDRAW_HASDLIGHT) )
  608. {
  609. pRenderList->m_DlightSurfaces[sortGroup].AddToTail( surfID );
  610. }
  611. pRenderList->m_AlphaSurfaces.AddToTail(surfID);
  612. }
  613. static void Shader_DisplacementSurface( CWorldRenderList *pRenderList, SurfaceHandle_t surfID )
  614. {
  615. Assert( SurfaceHasDispInfo( surfID ) );
  616. // For opaque displacement surfaces, we're going to build a temporary list of
  617. // displacement surfaces in each material bucket, and then add those to
  618. // the actual displacement lists in a separate pass.
  619. // We do this to sort the displacement surfaces by material
  620. // Each surface is in exactly one group
  621. int nSortGroup = MSurf_SortGroup( surfID );
  622. int nMaterialSortID = MSurf_MaterialSortID( surfID );
  623. if ( MSurf_Flags( surfID ) & (SURFDRAW_HASLIGHTSYTLES|SURFDRAW_HASDLIGHT) )
  624. {
  625. pRenderList->m_DlightSurfaces[nSortGroup].AddToTail( surfID );
  626. }
  627. pRenderList->m_DispSortList.AddSurfaceToTail( surfID, nSortGroup, nMaterialSortID );
  628. }
  629. //-----------------------------------------------------------------------------
  630. // Purpose: This draws a single surface using the dynamic mesh
  631. //-----------------------------------------------------------------------------
  632. void Shader_DrawSurfaceDynamic( IMatRenderContext *pRenderContext, SurfaceHandle_t surfID )
  633. {
  634. if( !SurfaceHasPrims( surfID ) )
  635. {
  636. IMesh *pMesh = pRenderContext->GetDynamicMesh( );
  637. CMeshBuilder meshBuilder;
  638. meshBuilder.Begin( pMesh, MATERIAL_POLYGON, MSurf_VertCount( surfID ) );
  639. BuildMSurfaceVertexArrays( host_state.worldbrush, surfID, meshBuilder );
  640. meshBuilder.End();
  641. pMesh->Draw();
  642. return;
  643. }
  644. mprimitive_t *pPrim = &host_state.worldbrush->primitives[MSurf_FirstPrimID( surfID )];
  645. if ( pPrim->vertCount )
  646. {
  647. #ifdef DBGFLAG_ASSERT
  648. int primType = pPrim->type;
  649. #endif
  650. IMesh *pMesh = pRenderContext->GetDynamicMesh( false );
  651. CMeshBuilder meshBuilder;
  652. for( int i = 0; i < MSurf_NumPrims( surfID ); i++, pPrim++ )
  653. {
  654. // Can't have heterogeneous primitive lists
  655. Assert( primType == pPrim->type );
  656. switch( pPrim->type )
  657. {
  658. case PRIM_TRILIST:
  659. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, pPrim->vertCount, pPrim->indexCount );
  660. break;
  661. case PRIM_TRISTRIP:
  662. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, pPrim->vertCount, pPrim->indexCount );
  663. break;
  664. default:
  665. Assert( 0 );
  666. return;
  667. }
  668. Assert( pPrim->indexCount );
  669. BuildMSurfacePrimVerts( host_state.worldbrush, pPrim, meshBuilder, surfID );
  670. BuildMSurfacePrimIndices( host_state.worldbrush, pPrim, meshBuilder );
  671. meshBuilder.End();
  672. pMesh->Draw();
  673. }
  674. }
  675. else
  676. {
  677. // prims are just a tessellation
  678. IMesh *pMesh = pRenderContext->GetDynamicMesh( );
  679. CMeshBuilder meshBuilder;
  680. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, MSurf_VertCount( surfID ), pPrim->indexCount );
  681. BuildMSurfaceVertexArrays( host_state.worldbrush, surfID, meshBuilder );
  682. for ( int primIndex = 0; primIndex < pPrim->indexCount; primIndex++ )
  683. {
  684. meshBuilder.FastIndex( host_state.worldbrush->primindices[pPrim->firstIndex + primIndex] );
  685. }
  686. meshBuilder.End();
  687. pMesh->Draw();
  688. }
  689. }
  690. //-----------------------------------------------------------------------------
  691. // Purpose: This draws a single surface using its static mesh
  692. //-----------------------------------------------------------------------------
  693. // NOTE: Since a static vb/dynamic ib IMesh doesn't buffer, we shouldn't use this
  694. // since it causes a lock and drawindexedprimitive per surface! (gary)
  695. void Shader_DrawSurfaceListStatic( IMatRenderContext *pRenderContext, SurfaceHandle_t *pList, int listCount, int triangleCount )
  696. {
  697. VPROF( "Shader_DrawSurfaceListStatic" );
  698. if (
  699. #ifdef USE_CONVARS
  700. mat_forcedynamic.GetInt() ||
  701. #endif
  702. (MSurf_Flags( pList[0] ) & SURFDRAW_WATERSURFACE) )
  703. {
  704. for ( int i = 0; i < listCount; i++ )
  705. Shader_DrawSurfaceDynamic( pRenderContext, pList[i] );
  706. return;
  707. }
  708. if ( triangleCount )
  709. {
  710. int indexCount = triangleCount * 3;
  711. IMesh *pMesh = pRenderContext->GetDynamicMesh( true, g_WorldStaticMeshes[MSurf_MaterialSortID( pList[0] )] );
  712. CMeshBuilder meshBuilder;
  713. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 0, indexCount );
  714. for ( int i = 0; i < listCount; i++ )
  715. {
  716. BuildIndicesForWorldSurface( meshBuilder, pList[i], host_state.worldbrush );
  717. }
  718. meshBuilder.End();
  719. pMesh->Draw();
  720. }
  721. }
  722. //-----------------------------------------------------------------------------
  723. // Sets the lightmapping state
  724. //-----------------------------------------------------------------------------
  725. static inline void Shader_SetChainLightmapState( IMatRenderContext *pRenderContext, SurfaceHandle_t surfID )
  726. {
  727. if ( g_pMaterialSystemConfig->nFullbright == 1 )
  728. {
  729. if( MSurf_Flags( surfID ) & SURFDRAW_BUMPLIGHT )
  730. {
  731. pRenderContext->BindLightmapPage( MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP );
  732. }
  733. else
  734. {
  735. pRenderContext->BindLightmapPage( MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE );
  736. }
  737. }
  738. else
  739. {
  740. Assert( MSurf_MaterialSortID( surfID ) >= 0 && MSurf_MaterialSortID( surfID ) < g_WorldStaticMeshes.Count() );
  741. pRenderContext->BindLightmapPage( materialSortInfoArray[MSurf_MaterialSortID( surfID )].lightmapPageID );
  742. }
  743. }
  744. //-----------------------------------------------------------------------------
  745. // Sets the lightmap + texture to render with
  746. //-----------------------------------------------------------------------------
  747. IMaterial *Shader_SetChainTextureState( IMatRenderContext *pRenderContext, SurfaceHandle_t surfID, IClientEntity* pBaseEntity, ERenderDepthMode_t DepthMode )
  748. {
  749. IMaterial *pSurfaceMaterial = MSurf_TexInfo( surfID )->material;
  750. if ( DepthMode )
  751. {
  752. // Select proper override material
  753. int nAlphaTest = (int) pSurfaceMaterial->IsAlphaTested();
  754. int nNoCull = (int) pSurfaceMaterial->IsTwoSided();
  755. IMaterial *pDepthWriteMaterial;
  756. if ( DepthMode == DEPTH_MODE_SHADOW )
  757. {
  758. pDepthWriteMaterial = g_pMaterialDepthWrite[ nAlphaTest ][ nNoCull ];
  759. }
  760. else
  761. {
  762. pDepthWriteMaterial = g_pMaterialSSAODepthWrite[ nAlphaTest ][ nNoCull ];
  763. }
  764. if ( nAlphaTest == 1 )
  765. {
  766. static unsigned int originalTextureVarCache = 0;
  767. IMaterialVar *pOriginalTextureVar = pSurfaceMaterial->FindVarFast( "$basetexture", &originalTextureVarCache );
  768. static unsigned int originalTextureFrameVarCache = 0;
  769. IMaterialVar *pOriginalTextureFrameVar = pSurfaceMaterial->FindVarFast( "$frame", &originalTextureFrameVarCache );
  770. static unsigned int originalAlphaRefCache = 0;
  771. IMaterialVar *pOriginalAlphaRefVar = pSurfaceMaterial->FindVarFast( "$AlphaTestReference", &originalAlphaRefCache );
  772. static unsigned int textureVarCache = 0;
  773. IMaterialVar *pTextureVar = pDepthWriteMaterial->FindVarFast( "$basetexture", &textureVarCache );
  774. static unsigned int textureFrameVarCache = 0;
  775. IMaterialVar *pTextureFrameVar = pDepthWriteMaterial->FindVarFast( "$frame", &textureFrameVarCache );
  776. static unsigned int alphaRefCache = 0;
  777. IMaterialVar *pAlphaRefVar = pDepthWriteMaterial->FindVarFast( "$AlphaTestReference", &alphaRefCache );
  778. if( pTextureVar && pOriginalTextureVar )
  779. {
  780. pTextureVar->SetTextureValue( pOriginalTextureVar->GetTextureValue() );
  781. }
  782. if( pTextureFrameVar && pOriginalTextureFrameVar )
  783. {
  784. pTextureFrameVar->SetIntValue( pOriginalTextureFrameVar->GetIntValue() );
  785. }
  786. if( pAlphaRefVar && pOriginalAlphaRefVar )
  787. {
  788. pAlphaRefVar->SetFloatValue( pOriginalAlphaRefVar->GetFloatValue() );
  789. }
  790. }
  791. pRenderContext->Bind( pDepthWriteMaterial );
  792. pSurfaceMaterial = pDepthWriteMaterial;
  793. }
  794. else
  795. {
  796. pRenderContext->Bind( pSurfaceMaterial, pBaseEntity ? pBaseEntity->GetClientRenderable() : NULL );
  797. Shader_SetChainLightmapState( pRenderContext, surfID );
  798. }
  799. return pSurfaceMaterial;
  800. }
  801. static byte flatColor[4] = { 255, 255, 255, 255 };
  802. static byte flatColorNoAlpha[4] = { 255, 255, 255, 0 };
  803. // simple helper class to cache off material properties to avoid conversions, calls, etc in loops
  804. struct texturegen_t
  805. {
  806. Vector uAxis;
  807. float uOffset;
  808. Vector vAxis;
  809. float vOffset;
  810. float invU;
  811. float invV;
  812. byte *pColor;
  813. void Init( SurfaceHandle_t surfID )
  814. {
  815. mtexinfo_t* pTexInfo = MSurf_TexInfo( surfID );
  816. uAxis = pTexInfo->textureVecsTexelsPerWorldUnits[0].AsVector3D();
  817. uOffset = pTexInfo->textureVecsTexelsPerWorldUnits[0][3];
  818. vAxis = pTexInfo->textureVecsTexelsPerWorldUnits[1].AsVector3D();
  819. vOffset = pTexInfo->textureVecsTexelsPerWorldUnits[1][3];
  820. invU = 1.0f / pTexInfo->material->GetMappingWidth();
  821. invV = 1.0f / pTexInfo->material->GetMappingHeight();
  822. // The amount to blend between basetexture and basetexture2 used to sit in lightmap
  823. // alpha, so we didn't care about the vertex color or vertex alpha. But now if they're
  824. // using it, we have to make sure the vertex has the color and alpha specified correctly
  825. // or it will look weird.
  826. if ( (pTexInfo->texinfoFlags & TEXINFO_USING_BASETEXTURE2) )
  827. {
  828. pColor = flatColorNoAlpha;
  829. }
  830. else
  831. {
  832. pColor = flatColor;
  833. }
  834. }
  835. inline float ComputeU( const Vector &pos ) const
  836. {
  837. return invU * (DotProduct(pos, uAxis) + uOffset);
  838. }
  839. inline float ComputeV( const Vector &pos ) const
  840. {
  841. return invV * (DotProduct(pos, vAxis) + vOffset);
  842. }
  843. };
  844. void BuildMSurfaceVertexArraysTextureOnly( worldbrushdata_t *pBrushData, SurfaceHandle_t surfID, CMeshBuilder &builder )
  845. {
  846. int vertCount = MSurf_VertCount(surfID);
  847. unsigned short *pVertIndex = &pBrushData->vertindices[MSurf_FirstVertIndex( surfID )];
  848. for ( int i = 0; i < vertCount; i++ )
  849. {
  850. // world-space vertex
  851. // output to mesh
  852. Vector &vec = pBrushData->vertexes[pVertIndex[i]].position;
  853. builder.Position3fv( vec.Base() );
  854. Vector2D uv;
  855. SurfComputeTextureCoordinate( surfID, vec, uv.Base() );
  856. builder.TexCoord2fv( 0, uv.Base() );
  857. builder.Color4ubv( flatColor );
  858. builder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
  859. }
  860. }
  861. void Shader_AddSurfaceDynamicTextureOnly( CMeshBuilder &meshBuilder, SurfaceHandle_t surfID )
  862. {
  863. int startVert = meshBuilder.VertexCount();
  864. worldbrushdata_t *pData = host_state.worldbrush;
  865. BuildMSurfaceVertexArraysTextureOnly( pData, surfID, meshBuilder );
  866. CIndexBuilder &indexBuilder = meshBuilder;
  867. if ( SurfaceHasPrims(surfID) )
  868. {
  869. mprimitive_t *pPrim = &pData->primitives[MSurf_FirstPrimID( surfID, pData )];
  870. Assert(pPrim->vertCount==0);
  871. Assert( pPrim->indexCount == ((MSurf_VertCount( surfID ) - 2)*3));
  872. indexBuilder.FastIndexList( &pData->primindices[pPrim->firstIndex], startVert, pPrim->indexCount );
  873. }
  874. else
  875. {
  876. int triangleCount = MSurf_VertCount(surfID)-2;
  877. indexBuilder.FastPolygon( startVert, triangleCount );
  878. }
  879. }
  880. void Shader_AddSurfaceDynamic( CMeshBuilder &meshBuilder, SurfaceHandle_t surfID )
  881. {
  882. int startVert = meshBuilder.VertexCount();
  883. worldbrushdata_t *pData = host_state.worldbrush;
  884. BuildMSurfaceVertexArrays( pData, surfID, meshBuilder );
  885. CIndexBuilder &indexBuilder = meshBuilder;
  886. if ( SurfaceHasPrims(surfID) )
  887. {
  888. mprimitive_t *pPrim = &pData->primitives[MSurf_FirstPrimID( surfID, pData )];
  889. Assert(pPrim->vertCount==0);
  890. Assert( pPrim->indexCount == ((MSurf_VertCount( surfID ) - 2)*3));
  891. indexBuilder.FastIndexList( &pData->primindices[pPrim->firstIndex], startVert, pPrim->indexCount );
  892. }
  893. else
  894. {
  895. int triangleCount = MSurf_VertCount(surfID)-2;
  896. indexBuilder.FastPolygon( startVert, triangleCount );
  897. }
  898. }
  899. static void Shader_DrawDynamicChain( IMatRenderContext *pRenderContext, const CMSurfaceSortList &sortList, const surfacesortgroup_t &group, ERenderDepthMode_t DepthMode )
  900. {
  901. SurfaceHandle_t surfID = sortList.GetSurfaceAtHead(group);
  902. if ( !IS_SURF_VALID(surfID))
  903. return;
  904. IMaterial *pDrawMaterial = Shader_SetChainTextureState( pRenderContext, surfID, 0, DepthMode );
  905. int nMaxIndices = pRenderContext->GetMaxIndicesToRender();
  906. int nMaxVertices = pRenderContext->GetMaxVerticesToRender( pDrawMaterial );
  907. int nCurrIndexCount = group.triangleCount*3;
  908. int nCurrVertexCount = group.vertexCount;
  909. if ( nCurrIndexCount < nMaxIndices && nCurrVertexCount < nMaxVertices )
  910. {
  911. IMesh *pMesh = pRenderContext->GetDynamicMesh( false );
  912. CMeshBuilder meshBuilder;
  913. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nCurrVertexCount, nCurrIndexCount );
  914. if ( DepthMode != DEPTH_MODE_NORMAL )
  915. {
  916. MSL_FOREACH_SURFACE_IN_GROUP_BEGIN(sortList, group, surfID)
  917. {
  918. Shader_AddSurfaceDynamicTextureOnly( meshBuilder, surfID );
  919. }
  920. MSL_FOREACH_SURFACE_IN_GROUP_END()
  921. }
  922. else
  923. {
  924. MSL_FOREACH_SURFACE_IN_GROUP_BEGIN(sortList, group, surfID)
  925. {
  926. Shader_AddSurfaceDynamic( meshBuilder, surfID );
  927. }
  928. MSL_FOREACH_SURFACE_IN_GROUP_END()
  929. }
  930. meshBuilder.End();
  931. pMesh->Draw();
  932. }
  933. else
  934. {
  935. // UNDONE: This will have really bad perf on 360. There's a simple mod to the above code to fix it
  936. // but it never happens in l4d so I didn't bother writing/testing that code.
  937. Assert(0);
  938. MSL_FOREACH_SURFACE_IN_GROUP_BEGIN(sortList, group, surfID)
  939. {
  940. Shader_DrawSurfaceDynamic( pRenderContext, surfID );
  941. }
  942. MSL_FOREACH_SURFACE_IN_GROUP_END()
  943. }
  944. }
  945. void Shader_DrawChainsDynamic( IMatRenderContext *pRenderContext, const CMSurfaceSortList &sortList, int nSortGroup, ERenderDepthMode_t DepthMode )
  946. {
  947. MSL_FOREACH_GROUP_BEGIN(sortList, nSortGroup, group )
  948. {
  949. Shader_DrawDynamicChain( pRenderContext, sortList, group, DepthMode );
  950. }
  951. MSL_FOREACH_GROUP_END()
  952. }
  953. struct vertexformatlist_t
  954. {
  955. unsigned short numbatches;
  956. unsigned short firstbatch;
  957. IMesh *pMesh;
  958. };
  959. struct batchlist_t
  960. {
  961. SurfaceHandle_t surfID; // material and lightmap info
  962. unsigned short firstIndex;
  963. unsigned short numIndex;
  964. };
  965. static void Shader_DrawChainsStatic( IMatRenderContext *pRenderContext, const CMSurfaceSortList &sortList, int nSortGroup, ERenderDepthMode_t DepthMode )
  966. {
  967. //VPROF("DrawChainsStatic");
  968. CUtlVectorFixed<vertexformatlist_t, MAX_VERTEX_FORMAT_CHANGES> meshList;
  969. int meshMap[MAX_VERTEX_FORMAT_CHANGES];
  970. CUtlVectorFixedGrowable<batchlist_t, 512> batchList;
  971. CUtlVectorFixedGrowable<const surfacesortgroup_t *, 8> dynamicGroups;
  972. bool bWarn = true;
  973. CMeshBuilder meshBuilder;
  974. bool skipBind = false;
  975. if ( g_pMaterialSystemConfig->nFullbright == 1 )
  976. {
  977. skipBind = true;
  978. }
  979. const CUtlVector<surfacesortgroup_t *> &groupList = sortList.GetSortList(nSortGroup);
  980. int count = groupList.Count();
  981. int i, listIndex = 0;
  982. #if defined(_PS3)
  983. g_pBuildIndicesJob->m_buildIndicesJobData.EnsureCapacity( count );
  984. #endif
  985. //PIXEVENT( pRenderContext, "Shader_DrawChainsStatic" );
  986. int nMaxIndices = pRenderContext->GetMaxIndicesToRender();
  987. while ( listIndex < count )
  988. {
  989. const surfacesortgroup_t &group = *groupList[listIndex];
  990. SurfaceHandle_t surfID = sortList.GetSurfaceAtHead(group);
  991. int sortID = MSurf_MaterialSortID( surfID );
  992. IMesh *pBuildMesh = pRenderContext->GetDynamicMesh( false, g_WorldStaticMeshes[sortID] );
  993. meshBuilder.Begin( pBuildMesh, MATERIAL_TRIANGLES, 0, nMaxIndices );
  994. IMesh *pLastMesh = NULL;
  995. int indexCount = 0;
  996. int meshIndex = -1;
  997. // start SPU job here
  998. #if defined(_PS3)
  999. if( r_PS3_SPU_buildindices.GetInt() ) //&& ( count < g_pBuildIndicesJob->m_buildIndicesJobData.Count() ) )
  1000. {
  1001. PS3BuildIndicesJobData *pJobData = g_pBuildIndicesJob->GetJobData();
  1002. // fill SPU job struct
  1003. buildIndicesJob_SPU *pjob_SPU = &pJobData->buildIndicesJobSPU;
  1004. pjob_SPU->debugJob = r_PS3_SPU_buildindices.GetInt() == 2;
  1005. pjob_SPU->count = count;
  1006. pjob_SPU->maxIndices = nMaxIndices;
  1007. pjob_SPU->worldStaticMeshesCount = g_WorldStaticMeshes.Count();
  1008. pjob_SPU->listIndex = listIndex;
  1009. pjob_SPU->indexCount = indexCount;
  1010. pjob_SPU->meshListCount = meshList.Count();
  1011. pjob_SPU->batchListCount = batchList.Count();
  1012. pjob_SPU->pEA_sortList_materiallist = (void *)sortList.GetMaterialList();
  1013. pjob_SPU->group_listHead = (group).listHead;
  1014. pjob_SPU->pEA_worldbrush_surfaces1 = host_state.worldbrush->surfaces1;
  1015. pjob_SPU->pEA_worldbrush_surfaces2 = host_state.worldbrush->surfaces2;
  1016. pjob_SPU->pEA_worldbrush_primitives = host_state.worldbrush->primitives;
  1017. pjob_SPU->pEA_worldbrush_primindices = host_state.worldbrush->primindices;
  1018. pjob_SPU->worldbrush_numsurfaces = host_state.worldbrush->numsurfaces;
  1019. pjob_SPU->pEA_indexbuilder_indices = meshBuilder.m_pIndices;
  1020. pjob_SPU->indexbuilder_indexSize = meshBuilder.m_nIndexSize;
  1021. // push buildindices job
  1022. job_buildindices::JobDescriptor_t *pJobDescriptor = &pJobData->jobDescriptor;
  1023. pJobDescriptor->header = g_buildIndicesJobDescriptor.header;
  1024. pJobDescriptor->header.useInOutBuffer = 1;
  1025. pJobDescriptor->header.sizeStack = (40*1024)/8;
  1026. pJobDescriptor->header.sizeInOrInOut = 0;
  1027. pJobDescriptor->header.sizeDmaList = 0;
  1028. AddInputDma( pJobDescriptor, sizeof(buildIndicesJob_SPU), pjob_SPU );
  1029. AddInputDma( pJobDescriptor, ROUNDUPTONEXT16B( sizeof(IMesh *) * g_WorldStaticMeshes.Count() ), g_WorldStaticMeshes.Base() );
  1030. AddInputDma( pJobDescriptor, ROUNDUPTONEXT16B( sizeof(surfacesortgroup_t *) * (count) ), groupList.Base() );
  1031. // push
  1032. g_pBuildIndicesJob->Push( pJobDescriptor );
  1033. // debug
  1034. if( pjob_SPU->debugJob )
  1035. {
  1036. g_pBuildIndicesJob->Sync();
  1037. }
  1038. }
  1039. #endif
  1040. for ( ; listIndex < count; listIndex++ )
  1041. {
  1042. const surfacesortgroup_t &group = *groupList[listIndex];
  1043. surfID = sortList.GetSurfaceAtHead(group);
  1044. Assert( IS_SURF_VALID( surfID ) );
  1045. if ( MSurf_Flags(surfID) & SURFDRAW_DYNAMIC )
  1046. {
  1047. dynamicGroups.AddToTail( &group );
  1048. continue;
  1049. }
  1050. Assert( group.triangleCount > 0 );
  1051. int numIndex = group.triangleCount * 3;
  1052. if ( indexCount + numIndex > nMaxIndices )
  1053. {
  1054. if ( numIndex > nMaxIndices )
  1055. {
  1056. IMaterial *pDrawMaterial = materialSortInfoArray[MSurf_MaterialSortID( surfID )].material;
  1057. DevMsg("Too many faces with the same material in scene! Material: %s, num indices %d (max: %d)\n", pDrawMaterial ? pDrawMaterial->GetName() : "null", numIndex, nMaxIndices );
  1058. break;
  1059. }
  1060. pLastMesh = NULL;
  1061. break;
  1062. }
  1063. sortID = MSurf_MaterialSortID( surfID );
  1064. if ( g_WorldStaticMeshes[sortID] != pLastMesh )
  1065. {
  1066. if( meshList.Count() < MAX_VERTEX_FORMAT_CHANGES - 1 )
  1067. {
  1068. meshIndex = meshList.AddToTail();
  1069. meshList[meshIndex].numbatches = 0;
  1070. meshList[meshIndex].firstbatch = batchList.Count();
  1071. pLastMesh = g_WorldStaticMeshes[sortID];
  1072. Assert( pLastMesh );
  1073. meshList[meshIndex].pMesh = pLastMesh;
  1074. }
  1075. else
  1076. {
  1077. if ( bWarn )
  1078. {
  1079. DevWarning( 2, "Too many vertex format changes in frame, whole world not rendered\n" );
  1080. bWarn = false;
  1081. }
  1082. continue;
  1083. }
  1084. }
  1085. int batchIndex = batchList.AddToTail();
  1086. batchlist_t &batch = batchList[batchIndex];
  1087. batch.firstIndex = indexCount;
  1088. batch.surfID = surfID;
  1089. batch.numIndex = numIndex;
  1090. Assert( indexCount + batch.numIndex < nMaxIndices );
  1091. indexCount += batch.numIndex;
  1092. meshList[meshIndex].numbatches++;
  1093. #if defined(_PS3)
  1094. if( r_PS3_SPU_buildindices.GetInt() == 0 )
  1095. {
  1096. #endif
  1097. MSL_FOREACH_SURFACE_IN_GROUP_BEGIN(sortList, group, surfID)
  1098. {
  1099. Assert( meshBuilder.m_nFirstVertex == 0 );
  1100. //Msg("surfID %d\n", (uint32)surfID );
  1101. BuildIndicesForWorldSurface( meshBuilder, surfID, host_state.worldbrush );
  1102. }
  1103. MSL_FOREACH_SURFACE_IN_GROUP_END()
  1104. #if defined(_PS3)
  1105. }
  1106. #endif
  1107. }
  1108. #if defined(_PS3)
  1109. if( r_PS3_SPU_buildindices.GetInt() )
  1110. {
  1111. meshBuilder.AdvanceIndices( indexCount );
  1112. }
  1113. #endif
  1114. // close out the index buffer
  1115. meshBuilder.End( false, false );
  1116. int meshTotal = meshList.Count();
  1117. VPROF_INCREMENT_COUNTER( "vertex format changes", meshTotal );
  1118. // HACKHACK: Crappy little bubble sort
  1119. // UNDONE: Make the traversal happen so that they are already sorted when you get here.
  1120. // NOTE: Profiled in a fairly complex map. This is not even costing 0.01ms / frame!
  1121. for ( i = 0; i < meshTotal; i++ )
  1122. {
  1123. meshMap[i] = i;
  1124. }
  1125. bool swapped = true;
  1126. while ( swapped )
  1127. {
  1128. swapped = false;
  1129. for ( i = 1; i < meshTotal; i++ )
  1130. {
  1131. if ( meshList[meshMap[i]].pMesh < meshList[meshMap[i-1]].pMesh )
  1132. {
  1133. int tmp = meshMap[i-1];
  1134. meshMap[i-1] = meshMap[i];
  1135. meshMap[i] = tmp;
  1136. swapped = true;
  1137. }
  1138. }
  1139. }
  1140. pRenderContext->BeginBatch( pBuildMesh );
  1141. for ( int m = 0; m < meshTotal; m++ )
  1142. {
  1143. vertexformatlist_t &mesh = meshList[meshMap[m]];
  1144. IMaterial *pBindMaterial = materialSortInfoArray[MSurf_MaterialSortID( batchList[mesh.firstbatch].surfID )].material;
  1145. Assert( mesh.pMesh && pBuildMesh );
  1146. // IMesh *pMesh = pRenderContext->GetDynamicMesh( false, mesh.pMesh, pBuildMesh, pBindMaterial );
  1147. pRenderContext->BindBatch( mesh.pMesh, pBindMaterial );
  1148. for ( int b = 0; b < mesh.numbatches; b++ )
  1149. {
  1150. batchlist_t &batch = batchList[b+mesh.firstbatch];
  1151. IMaterial *pDrawMaterial = materialSortInfoArray[MSurf_MaterialSortID( batch.surfID )].material;
  1152. if ( DepthMode != DEPTH_MODE_NORMAL )
  1153. {
  1154. // Select proper override material
  1155. int nAlphaTest = (int) pDrawMaterial->IsAlphaTested();
  1156. int nNoCull = (int) pDrawMaterial->IsTwoSided();
  1157. IMaterial *pDepthWriteMaterial;
  1158. if ( DepthMode == DEPTH_MODE_SSA0 )
  1159. {
  1160. pDepthWriteMaterial = g_pMaterialSSAODepthWrite[ nAlphaTest ][ nNoCull ];
  1161. }
  1162. else
  1163. {
  1164. pDepthWriteMaterial = g_pMaterialDepthWrite[ nAlphaTest ][ nNoCull ];
  1165. }
  1166. if ( nAlphaTest == 1 )
  1167. {
  1168. static unsigned int originalTextureVarCache = 0;
  1169. IMaterialVar *pOriginalTextureVar = pDrawMaterial->FindVarFast( "$basetexture", &originalTextureVarCache );
  1170. static unsigned int originalTextureFrameVarCache = 0;
  1171. IMaterialVar *pOriginalTextureFrameVar = pDrawMaterial->FindVarFast( "$frame", &originalTextureFrameVarCache );
  1172. static unsigned int originalAlphaRefCache = 0;
  1173. IMaterialVar *pOriginalAlphaRefVar = pDrawMaterial->FindVarFast( "$AlphaTestReference", &originalAlphaRefCache );
  1174. static unsigned int textureVarCache = 0;
  1175. IMaterialVar *pTextureVar = pDepthWriteMaterial->FindVarFast( "$basetexture", &textureVarCache );
  1176. static unsigned int textureFrameVarCache = 0;
  1177. IMaterialVar *pTextureFrameVar = pDepthWriteMaterial->FindVarFast( "$frame", &textureFrameVarCache );
  1178. static unsigned int alphaRefCache = 0;
  1179. IMaterialVar *pAlphaRefVar = pDepthWriteMaterial->FindVarFast( "$AlphaTestReference", &alphaRefCache );
  1180. if( pTextureVar && pOriginalTextureVar )
  1181. {
  1182. pTextureVar->SetTextureValue( pOriginalTextureVar->GetTextureValue() );
  1183. }
  1184. if( pTextureFrameVar && pOriginalTextureFrameVar )
  1185. {
  1186. pTextureFrameVar->SetIntValue( pOriginalTextureFrameVar->GetIntValue() );
  1187. }
  1188. if( pAlphaRefVar && pOriginalAlphaRefVar )
  1189. {
  1190. pAlphaRefVar->SetFloatValue( pOriginalAlphaRefVar->GetFloatValue() );
  1191. }
  1192. }
  1193. pRenderContext->Bind( pDepthWriteMaterial );
  1194. }
  1195. else
  1196. {
  1197. pRenderContext->Bind( pDrawMaterial, NULL );
  1198. if ( skipBind )
  1199. {
  1200. if( MSurf_Flags( batch.surfID ) & SURFDRAW_BUMPLIGHT )
  1201. {
  1202. pRenderContext->BindLightmapPage( MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP );
  1203. }
  1204. else
  1205. {
  1206. pRenderContext->BindLightmapPage( MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE );
  1207. }
  1208. }
  1209. else
  1210. {
  1211. int nLightmapPageId = materialSortInfoArray[MSurf_MaterialSortID( batch.surfID )].lightmapPageID;
  1212. pRenderContext->BindLightmapPage( nLightmapPageId );
  1213. }
  1214. }
  1215. // pMesh->Draw( batch.firstIndex, batch.numIndex );
  1216. pRenderContext->DrawBatch( MATERIAL_TRIANGLES, batch.firstIndex, batch.numIndex );
  1217. }
  1218. }
  1219. pRenderContext->EndBatch();
  1220. // if we get here and pLast mesh is NULL and we rendered somthing, we need to loop
  1221. if ( pLastMesh || !meshTotal )
  1222. break;
  1223. meshList.RemoveAll();
  1224. batchList.RemoveAll();
  1225. }
  1226. for ( i = 0; i < dynamicGroups.Count(); i++ )
  1227. {
  1228. Shader_DrawDynamicChain( pRenderContext, sortList, *dynamicGroups[i], DepthMode );
  1229. }
  1230. }
  1231. #if defined(_PS3)
  1232. //-----------------------------------------------------------------------------
  1233. // End of frame sync point for SPURS jobs that require it
  1234. //-----------------------------------------------------------------------------
  1235. void R_FrameEndSPURSSync( int flags )
  1236. {
  1237. if( r_PS3_SPU_buildindices.GetInt() )
  1238. {
  1239. g_pBuildIndicesJob->Sync();
  1240. }
  1241. }
  1242. #endif
  1243. //-----------------------------------------------------------------------------
  1244. // The following methods will display debugging info in the middle of each surface
  1245. //-----------------------------------------------------------------------------
  1246. typedef void (*SurfaceDebugFunc_t)( IMatRenderContext *pRenderContext, SurfaceHandle_t surfID, const Vector &vecCentroid );
  1247. static void DrawSurfaceID( IMatRenderContext *pRenderContext, SurfaceHandle_t surfID, const Vector &vecCentroid )
  1248. {
  1249. char buf[32];
  1250. Q_snprintf(buf, sizeof( buf ), "0x%p", surfID );
  1251. CDebugOverlay::AddTextOverlay( vecCentroid, 0, buf );
  1252. }
  1253. static void DrawSurfaceIDAsInt( IMatRenderContext *pRenderContext, SurfaceHandle_t surfID, const Vector &vecCentroid )
  1254. {
  1255. int nInt = (msurface2_t*)surfID - host_state.worldbrush->surfaces2;
  1256. char buf[32];
  1257. Q_snprintf( buf, sizeof( buf ), "%d", nInt );
  1258. CDebugOverlay::AddTextOverlay( vecCentroid, 0, buf );
  1259. }
  1260. static void DrawSurfaceMaterial( IMatRenderContext *pRenderContext, SurfaceHandle_t surfID, const Vector &vecCentroid )
  1261. {
  1262. mtexinfo_t * pTexInfo = MSurf_TexInfo(surfID);
  1263. const char *pFullMaterialName = pTexInfo->material ? pTexInfo->material->GetName() : "no material";
  1264. const char *pSlash = strrchr( pFullMaterialName, '/' );
  1265. const char *pMaterialName = strrchr( pFullMaterialName, '\\' );
  1266. if (pSlash > pMaterialName)
  1267. pMaterialName = pSlash;
  1268. if (pMaterialName)
  1269. ++pMaterialName;
  1270. else
  1271. pMaterialName = pFullMaterialName;
  1272. CDebugOverlay::AddTextOverlay( vecCentroid, 0, pMaterialName );
  1273. }
  1274. //-----------------------------------------------------------------------------
  1275. // Displays the surface id # in the center of the surface.
  1276. //-----------------------------------------------------------------------------
  1277. void Shader_DrawSurfaceDebuggingInfo( IMatRenderContext *pRenderContext, SurfaceHandle_t *pList, int listCount, SurfaceDebugFunc_t func )
  1278. {
  1279. for ( int i = 0; i < listCount; i++ )
  1280. {
  1281. SurfaceHandle_t surfID = pList[i];
  1282. Assert( !SurfaceHasDispInfo( surfID ) );
  1283. // Compute the centroid of the surface
  1284. int nCount = MSurf_VertCount( surfID );
  1285. if (nCount >= 3)
  1286. {
  1287. Vector vecCentroid;
  1288. Surf_ComputeCentroid( surfID, &vecCentroid );
  1289. VectorTransform( vecCentroid, g_BrushToWorldMatrix.As3x4(), vecCentroid );
  1290. func( pRenderContext, surfID, vecCentroid );
  1291. }
  1292. }
  1293. }
  1294. //-----------------------------------------------------------------------------
  1295. // Doesn't draw internal triangles
  1296. //-----------------------------------------------------------------------------
  1297. void Shader_DrawWireframePolygons( IMatRenderContext *pRenderContext, SurfaceHandle_t *pList, int listCount )
  1298. {
  1299. int nLineCount = 0;
  1300. for ( int i = 0; i < listCount; i++ )
  1301. {
  1302. int nCount = MSurf_VertCount( pList[i] );
  1303. if (nCount >= 3)
  1304. {
  1305. nLineCount += nCount;
  1306. }
  1307. }
  1308. if (nLineCount == 0)
  1309. return;
  1310. pRenderContext->Bind( g_materialWorldWireframe );
  1311. IMesh *pMesh = pRenderContext->GetDynamicMesh( false );
  1312. CMeshBuilder meshBuilder;
  1313. meshBuilder.Begin( pMesh, MATERIAL_LINES, nLineCount );
  1314. for ( int i = 0; i < listCount; i++ )
  1315. {
  1316. SurfaceHandle_t surfID = pList[i];
  1317. Assert( !SurfaceHasDispInfo( surfID ) );
  1318. // Compute the centroid of the surface
  1319. int nCount = MSurf_VertCount( surfID );
  1320. if (nCount >= 3)
  1321. {
  1322. int nFirstVertIndex = MSurf_FirstVertIndex( surfID );
  1323. int nVertIndex = host_state.worldbrush->vertindices[nFirstVertIndex + nCount - 1];
  1324. Vector vecPrevPos = host_state.worldbrush->vertexes[nVertIndex].position;
  1325. for (int v = 0; v < nCount; ++v )
  1326. {
  1327. // world-space vertex
  1328. nVertIndex = host_state.worldbrush->vertindices[nFirstVertIndex + v];
  1329. Vector& vec = host_state.worldbrush->vertexes[nVertIndex].position;
  1330. // output to mesh
  1331. meshBuilder.Position3fv( vecPrevPos.Base() );
  1332. meshBuilder.AdvanceVertex();
  1333. meshBuilder.Position3fv( vec.Base() );
  1334. meshBuilder.AdvanceVertex();
  1335. vecPrevPos = vec;
  1336. }
  1337. }
  1338. }
  1339. meshBuilder.End();
  1340. pMesh->Draw();
  1341. }
  1342. //-----------------------------------------------------------------------------
  1343. // Debugging mode, renders the wireframe.
  1344. //-----------------------------------------------------------------------------
  1345. static void Shader_DrawChainsWireframe( IMatRenderContext *pRenderContext, SurfaceHandle_t *pList, int listCount )
  1346. {
  1347. int nWireFrameMode = WireFrameMode();
  1348. switch( nWireFrameMode )
  1349. {
  1350. case 3:
  1351. // Doesn't draw internal triangles
  1352. Shader_DrawWireframePolygons( pRenderContext, pList, listCount );
  1353. break;
  1354. default:
  1355. {
  1356. if( nWireFrameMode == 2 )
  1357. {
  1358. pRenderContext->Bind( g_materialWorldWireframeZBuffer );
  1359. }
  1360. else
  1361. {
  1362. pRenderContext->Bind( g_materialWorldWireframe );
  1363. }
  1364. for ( int i = 0; i < listCount; i++ )
  1365. {
  1366. SurfaceHandle_t surfID = pList[i];
  1367. Assert( !SurfaceHasDispInfo( surfID ) );
  1368. Shader_DrawSurfaceDynamic( pRenderContext, surfID );
  1369. }
  1370. }
  1371. }
  1372. }
  1373. //-----------------------------------------------------------------------------
  1374. // Debugging mode, renders the normals
  1375. //-----------------------------------------------------------------------------
  1376. static void Shader_DrawChainNormals( IMatRenderContext *pRenderContext, SurfaceHandle_t *pList, int listCount )
  1377. {
  1378. Vector p, tVect, tangentS, tangentT;
  1379. worldbrushdata_t *pBrushData = host_state.worldbrush;
  1380. pRenderContext->Bind( g_pMaterialWireframeVertexColor );
  1381. for ( int i = 0; i < listCount; i++ )
  1382. {
  1383. SurfaceHandle_t surfID = pList[i];
  1384. IMesh *pMesh = pRenderContext->GetDynamicMesh( );
  1385. CMeshBuilder meshBuilder;
  1386. meshBuilder.Begin( pMesh, MATERIAL_LINES, MSurf_VertCount( surfID ) * 3 );
  1387. bool negate = TangentSpaceSurfaceSetup( surfID, tVect );
  1388. int vertID;
  1389. for( vertID = 0; vertID < MSurf_VertCount( surfID ); ++vertID )
  1390. {
  1391. int vertIndex = pBrushData->vertindices[MSurf_FirstVertIndex( surfID )+vertID];
  1392. Vector& pos = pBrushData->vertexes[vertIndex].position;
  1393. Vector& norm = pBrushData->vertnormals[ pBrushData->vertnormalindices[MSurf_FirstVertNormal( surfID )+vertID] ];
  1394. TangentSpaceComputeBasis( tangentS, tangentT, norm, tVect, negate );
  1395. meshBuilder.Position3fv( pos.Base() );
  1396. meshBuilder.Color3ub( 0, 0, 255 );
  1397. meshBuilder.AdvanceVertex();
  1398. VectorMA( pos, 5.0f, norm, p );
  1399. meshBuilder.Position3fv( p.Base() );
  1400. meshBuilder.Color3ub( 0, 0, 255 );
  1401. meshBuilder.AdvanceVertex();
  1402. meshBuilder.Position3fv( pos.Base() );
  1403. meshBuilder.Color3ub( 0, 255, 0 );
  1404. meshBuilder.AdvanceVertex();
  1405. VectorMA( pos, 5.0f, tangentT, p );
  1406. meshBuilder.Position3fv( p.Base() );
  1407. meshBuilder.Color3ub( 0, 255, 0 );
  1408. meshBuilder.AdvanceVertex();
  1409. meshBuilder.Position3fv( pos.Base() );
  1410. meshBuilder.Color3ub( 255, 0, 0 );
  1411. meshBuilder.AdvanceVertex();
  1412. VectorMA( pos, 5.0f, tangentS, p );
  1413. meshBuilder.Position3fv( p.Base() );
  1414. meshBuilder.Color3ub( 255, 0, 0 );
  1415. meshBuilder.AdvanceVertex();
  1416. }
  1417. meshBuilder.End();
  1418. pMesh->Draw();
  1419. }
  1420. }
  1421. static void Shader_DrawChainBumpBasis( IMatRenderContext *pRenderContext, SurfaceHandle_t *pList, int listCount )
  1422. {
  1423. Vector p, tVect, tangentS, tangentT;
  1424. worldbrushdata_t *pBrushData = host_state.worldbrush;
  1425. pRenderContext->Bind( g_pMaterialWireframeVertexColor );
  1426. for ( int i = 0; i < listCount; i++ )
  1427. {
  1428. SurfaceHandle_t surfID = pList[i];
  1429. IMesh *pMesh = pRenderContext->GetDynamicMesh( );
  1430. CMeshBuilder meshBuilder;
  1431. meshBuilder.Begin( pMesh, MATERIAL_LINES, MSurf_VertCount( surfID ) * 3 );
  1432. bool negate = TangentSpaceSurfaceSetup( surfID, tVect );
  1433. int vertID;
  1434. for( vertID = 0; vertID < MSurf_VertCount( surfID ); ++vertID )
  1435. {
  1436. int vertIndex = pBrushData->vertindices[MSurf_FirstVertIndex( surfID )+vertID];
  1437. Vector& pos = pBrushData->vertexes[vertIndex].position;
  1438. Vector& norm = pBrushData->vertnormals[ pBrushData->vertnormalindices[MSurf_FirstVertNormal( surfID )+vertID] ];
  1439. TangentSpaceComputeBasis( tangentS, tangentT, norm, tVect, negate );
  1440. Vector worldSpaceBumpBasis[3];
  1441. int i;
  1442. for( i = 0; i < 3; i++ )
  1443. {
  1444. worldSpaceBumpBasis[i][0] =
  1445. g_localBumpBasis[i][0] * tangentS[0] +
  1446. g_localBumpBasis[i][1] * tangentS[1] +
  1447. g_localBumpBasis[i][2] * tangentS[2];
  1448. worldSpaceBumpBasis[i][1] =
  1449. g_localBumpBasis[i][0] * tangentT[0] +
  1450. g_localBumpBasis[i][1] * tangentT[1] +
  1451. g_localBumpBasis[i][2] * tangentT[2];
  1452. worldSpaceBumpBasis[i][2] =
  1453. g_localBumpBasis[i][0] * norm[0] +
  1454. g_localBumpBasis[i][1] * norm[1] +
  1455. g_localBumpBasis[i][2] * norm[2];
  1456. }
  1457. meshBuilder.Position3fv( pos.Base() );
  1458. meshBuilder.Color3ub( 255, 0, 0 );
  1459. meshBuilder.AdvanceVertex();
  1460. VectorMA( pos, 5.0f, worldSpaceBumpBasis[0], p );
  1461. meshBuilder.Position3fv( p.Base() );
  1462. meshBuilder.Color3ub( 255, 0, 0 );
  1463. meshBuilder.AdvanceVertex();
  1464. meshBuilder.Position3fv( pos.Base() );
  1465. meshBuilder.Color3ub( 0, 255, 0 );
  1466. meshBuilder.AdvanceVertex();
  1467. VectorMA( pos, 5.0f, worldSpaceBumpBasis[1], p );
  1468. meshBuilder.Position3fv( p.Base() );
  1469. meshBuilder.Color3ub( 0, 255, 0 );
  1470. meshBuilder.AdvanceVertex();
  1471. meshBuilder.Position3fv( pos.Base() );
  1472. meshBuilder.Color3ub( 0, 0, 255 );
  1473. meshBuilder.AdvanceVertex();
  1474. VectorMA( pos, 5.0f, worldSpaceBumpBasis[2], p );
  1475. meshBuilder.Position3fv( p.Base() );
  1476. meshBuilder.Color3ub( 0, 0, 255 );
  1477. meshBuilder.AdvanceVertex();
  1478. }
  1479. meshBuilder.End();
  1480. pMesh->Draw();
  1481. }
  1482. }
  1483. //-----------------------------------------------------------------------------
  1484. // Debugging mode, renders the luxel grid.
  1485. //-----------------------------------------------------------------------------
  1486. static void Shader_DrawLuxels( IMatRenderContext *pRenderContext, SurfaceHandle_t *pList, int listCount )
  1487. {
  1488. pRenderContext->Bind( g_materialDebugLuxels );
  1489. for ( int i = 0; i < listCount; i++ )
  1490. {
  1491. SurfaceHandle_t surfID = pList[i];
  1492. Assert( !SurfaceHasDispInfo( surfID ) );
  1493. // Gotta bind the lightmap page so the rendering knows the lightmap scale
  1494. pRenderContext->BindLightmapPage( materialSortInfoArray[MSurf_MaterialSortID( surfID )].lightmapPageID );
  1495. Shader_DrawSurfaceDynamic( pRenderContext, surfID );
  1496. }
  1497. }
  1498. CShaderDebug g_ShaderDebug;
  1499. ConVar mat_surfaceid("mat_surfaceid", "0", FCVAR_CHEAT);
  1500. ConVar mat_surfacemat("mat_surfacemat", "0", FCVAR_CHEAT);
  1501. //-----------------------------------------------------------------------------
  1502. // Purpose:
  1503. // Output : static void
  1504. //-----------------------------------------------------------------------------
  1505. static void ComputeDebugSettings( void )
  1506. {
  1507. g_ShaderDebug.wireframe = ShouldDrawInWireFrameMode() || (r_drawworld.GetInt() == 2);
  1508. g_ShaderDebug.normals = mat_normals.GetBool();
  1509. g_ShaderDebug.luxels = mat_luxels.GetBool();
  1510. g_ShaderDebug.bumpBasis = mat_bumpbasis.GetBool();
  1511. g_ShaderDebug.surfaceid = mat_surfaceid.GetInt();
  1512. g_ShaderDebug.surfacematerials = mat_surfacemat.GetBool();
  1513. g_ShaderDebug.TestAnyDebug();
  1514. }
  1515. //-----------------------------------------------------------------------------
  1516. // Draw debugging information
  1517. //-----------------------------------------------------------------------------
  1518. void DrawDebugInformation( IMatRenderContext *pRenderContext, SurfaceHandle_t *pList, int listCount )
  1519. {
  1520. // Overlay with wireframe if we're in that mode
  1521. if( g_ShaderDebug.wireframe )
  1522. {
  1523. Shader_DrawChainsWireframe(pRenderContext, pList, listCount);
  1524. }
  1525. // Overlay with normals if we're in that mode
  1526. if( g_ShaderDebug.normals )
  1527. {
  1528. Shader_DrawChainNormals(pRenderContext, pList, listCount);
  1529. }
  1530. if( g_ShaderDebug.bumpBasis )
  1531. {
  1532. Shader_DrawChainBumpBasis(pRenderContext, pList, listCount);
  1533. }
  1534. // Overlay with luxel grid if we're in that mode
  1535. if( g_ShaderDebug.luxels )
  1536. {
  1537. Shader_DrawLuxels(pRenderContext, pList, listCount);
  1538. }
  1539. if ( g_ShaderDebug.surfaceid )
  1540. {
  1541. // Draw the surface id in the middle of the surfaces
  1542. Shader_DrawSurfaceDebuggingInfo( pRenderContext, pList, listCount, (g_ShaderDebug.surfaceid != 2 ) ? DrawSurfaceID : DrawSurfaceIDAsInt );
  1543. }
  1544. else if ( g_ShaderDebug.surfacematerials )
  1545. {
  1546. // Draw the material name in the middle of the surfaces
  1547. Shader_DrawSurfaceDebuggingInfo( pRenderContext, pList, listCount, DrawSurfaceMaterial );
  1548. }
  1549. }
  1550. static void AddProjectedTextureDecalsToList( CWorldRenderList *pRenderList, int nSortGroup )
  1551. {
  1552. const CMSurfaceSortList &sortList = pRenderList->m_SortList;
  1553. MSL_FOREACH_GROUP_BEGIN( sortList, nSortGroup, group )
  1554. {
  1555. MSL_FOREACH_SURFACE_IN_GROUP_BEGIN(sortList, group, surfID)
  1556. {
  1557. Assert( !SurfaceHasDispInfo( surfID ) );
  1558. if ( SHADOW_DECAL_HANDLE_INVALID != MSurf_ShadowDecals( surfID ) )
  1559. {
  1560. // No shadows on water surfaces
  1561. if ((MSurf_Flags( surfID ) & SURFDRAW_NOSHADOWS) == 0)
  1562. {
  1563. MEM_ALLOC_CREDIT();
  1564. pRenderList->m_ShadowHandles[nSortGroup].AddToTail( MSurf_ShadowDecals( surfID ) );
  1565. }
  1566. }
  1567. // Add overlay fragments to list.
  1568. if ( OVERLAY_FRAGMENT_INVALID != MSurf_OverlayFragmentList( surfID ) )
  1569. {
  1570. OverlayMgr()->AddFragmentListToRenderList( nSortGroup, MSurf_OverlayFragmentList( surfID ), false );
  1571. }
  1572. }
  1573. MSL_FOREACH_SURFACE_IN_GROUP_END();
  1574. }
  1575. MSL_FOREACH_GROUP_END()
  1576. }
  1577. //-----------------------------------------------------------------------------
  1578. // Draws all of the opaque non-displacement surfaces queued up previously
  1579. //-----------------------------------------------------------------------------
  1580. static void Shader_DrawChains( IMatRenderContext *pRenderContext, const CWorldRenderList *pRenderList, int nSortGroup, ERenderDepthMode_t DepthMode )
  1581. {
  1582. Assert( !g_EngineRenderer->InLightmapUpdate() );
  1583. VPROF("Shader_DrawChains");
  1584. // Draw chains...
  1585. #ifdef USE_CONVARS
  1586. if ( !mat_forcedynamic.GetInt() && !g_pMaterialSystemConfig->bDrawFlat )
  1587. #else
  1588. if( 1 )
  1589. #endif
  1590. {
  1591. if ( g_VBAllocTracker )
  1592. g_VBAllocTracker->TrackMeshAllocations( "Shader_DrawChainsStatic" );
  1593. Shader_DrawChainsStatic( pRenderContext, pRenderList->m_SortList, nSortGroup, DepthMode );
  1594. }
  1595. else
  1596. {
  1597. if ( g_VBAllocTracker )
  1598. g_VBAllocTracker->TrackMeshAllocations( "Shader_DrawChainsDynamic" );
  1599. Shader_DrawChainsDynamic( pRenderContext, pRenderList->m_SortList, nSortGroup, DepthMode );
  1600. }
  1601. if ( g_VBAllocTracker )
  1602. g_VBAllocTracker->TrackMeshAllocations( NULL );
  1603. if ( !r_hidepaintedsurfaces.GetBool() )
  1604. {
  1605. pRenderContext->SetRenderingPaint( true );
  1606. PIXEVENT( pRenderContext, "Paint" );
  1607. for ( int i = 0; i < pRenderList->m_PaintedSurfaces[ nSortGroup ].Count(); i++ )
  1608. {
  1609. SurfaceHandle_t surfID = pRenderList->m_PaintedSurfaces[ nSortGroup ][i];
  1610. #ifdef DBGFLAG_ASSERT
  1611. bool bSurfacePainted = ( MSurf_Flags( surfID ) & SURFDRAW_PAINTED ) != 0;
  1612. Assert( bSurfacePainted );
  1613. #endif
  1614. IMaterial *pMaterial = MSurf_TexInfo( surfID )->material;
  1615. pRenderContext->Bind( pMaterial, NULL );
  1616. Shader_SetChainLightmapState( pRenderContext, surfID );
  1617. Shader_DrawSurfaceDynamic( pRenderContext, surfID );
  1618. }
  1619. pRenderContext->SetRenderingPaint( false );
  1620. }
  1621. if ( DepthMode != DEPTH_MODE_NORMAL ) // Skip debug stuff in shadow depth map
  1622. return;
  1623. #ifndef _PS3
  1624. #ifdef USE_CONVARS
  1625. if ( g_ShaderDebug.anydebug )
  1626. {
  1627. const CMSurfaceSortList &sortList = pRenderList->m_SortList;
  1628. // Debugging information
  1629. MSL_FOREACH_GROUP_BEGIN(sortList, nSortGroup, group )
  1630. {
  1631. CUtlVector<msurface2_t *> surfList;
  1632. sortList.GetSurfaceListForGroup( surfList, group );
  1633. DrawDebugInformation( pRenderContext, surfList.Base(), surfList.Count() );
  1634. }
  1635. MSL_FOREACH_GROUP_END()
  1636. // displacements
  1637. const CMSurfaceSortList &dispSortList = pRenderList->m_DispSortList;
  1638. MSL_FOREACH_GROUP_BEGIN(dispSortList, nSortGroup, group )
  1639. {
  1640. CUtlVector<msurface2_t *> surfList;
  1641. dispSortList.GetSurfaceListForGroup( surfList, group );
  1642. DispInfo_RenderListDebug( pRenderContext, surfList.Base(), surfList.Count() );
  1643. }
  1644. MSL_FOREACH_GROUP_END()
  1645. }
  1646. #endif
  1647. #endif
  1648. }
  1649. //-----------------------------------------------------------------------------
  1650. // Draws all of the opaque displacement surfaces queued up previously
  1651. //-----------------------------------------------------------------------------
  1652. static void Shader_DrawDispChain( IMatRenderContext *pRenderContext, int nSortGroup, const CMSurfaceSortList &list, unsigned long flags, ERenderDepthMode_t DepthMode )
  1653. {
  1654. VPROF_BUDGET( "Shader_DrawDispChain", VPROF_BUDGETGROUP_DISPLACEMENT_RENDERING );
  1655. int count = 0;
  1656. msurface2_t **pList;
  1657. MSL_FOREACH_GROUP_BEGIN( list, nSortGroup, group )
  1658. {
  1659. count += group.surfaceCount;
  1660. }
  1661. MSL_FOREACH_GROUP_END()
  1662. if (count)
  1663. {
  1664. pList = (msurface2_t **)stackalloc( count * sizeof(msurface2_t *));
  1665. int i = 0;
  1666. MSL_FOREACH_GROUP_BEGIN( list, nSortGroup, group )
  1667. {
  1668. MSL_FOREACH_SURFACE_IN_GROUP_BEGIN(list,group,surfID)
  1669. {
  1670. pList[i] = surfID;
  1671. ++i;
  1672. }
  1673. MSL_FOREACH_SURFACE_IN_GROUP_END()
  1674. }
  1675. MSL_FOREACH_GROUP_END()
  1676. Assert(i==count);
  1677. // draw displacments, batch decals
  1678. DispInfo_RenderListWorld( pRenderContext, nSortGroup, pList, count, g_EngineRenderer->ViewGetCurrent().m_bOrtho, flags, DepthMode );
  1679. stackfree(pList);
  1680. }
  1681. }
  1682. //-----------------------------------------------------------------------------
  1683. // Draws all decals of the opaque displacement surfaces queued up previously
  1684. //-----------------------------------------------------------------------------
  1685. void Shader_DrawDispChainDecalsAndOverlays( IMatRenderContext *pRenderContext, int nSortGroup, const CMSurfaceSortList &list, unsigned long flags )
  1686. {
  1687. VPROF_BUDGET( "Shader_DrawDispChain", VPROF_BUDGETGROUP_DISPLACEMENT_RENDERING );
  1688. int count = 0;
  1689. msurface2_t **pList;
  1690. MSL_FOREACH_GROUP_BEGIN( list, nSortGroup, group )
  1691. {
  1692. count += group.surfaceCount;
  1693. }
  1694. MSL_FOREACH_GROUP_END()
  1695. if (count)
  1696. {
  1697. pList = (msurface2_t **)stackalloc( count * sizeof(msurface2_t *));
  1698. int i = 0;
  1699. MSL_FOREACH_GROUP_BEGIN( list, nSortGroup, group )
  1700. {
  1701. MSL_FOREACH_SURFACE_IN_GROUP_BEGIN(list,group,surfID)
  1702. {
  1703. pList[i] = surfID;
  1704. ++i;
  1705. }
  1706. MSL_FOREACH_SURFACE_IN_GROUP_END()
  1707. }
  1708. MSL_FOREACH_GROUP_END()
  1709. Assert(i==count);
  1710. // draw displacments, batch decals
  1711. DispInfo_RenderListDecalsAndOverlays( pRenderContext, nSortGroup, pList, count, g_EngineRenderer->ViewGetCurrent().m_bOrtho, flags );
  1712. stackfree(pList);
  1713. }
  1714. }
  1715. static void Shader_BuildDynamicLightmaps( CWorldRenderList *pRenderList )
  1716. {
  1717. VPROF( "Shader_BuildDynamicLightmaps" );
  1718. R_DLightStartView();
  1719. // Build all lightmaps for opaque surfaces
  1720. for ( int nSortGroup = 0; nSortGroup < MAX_MAT_SORT_GROUPS; ++nSortGroup)
  1721. {
  1722. for ( int i = pRenderList->m_DlightSurfaces[nSortGroup].Count()-1; i >= 0; --i )
  1723. {
  1724. R_CheckForLightmapUpdates( pRenderList->m_DlightSurfaces[nSortGroup].Element(i), 0 );
  1725. }
  1726. }
  1727. R_DLightEndView();
  1728. }
  1729. //-----------------------------------------------------------------------------
  1730. // Compute if we're in or out of a fog volume
  1731. //-----------------------------------------------------------------------------
  1732. static void ComputeFogVolumeInfo( FogVolumeInfo_t *pFogVolume, const Vector& currentViewOrigin )
  1733. {
  1734. pFogVolume->m_InFogVolume = false;
  1735. int leafID = CM_PointLeafnum( currentViewOrigin );
  1736. if( leafID < 0 || leafID >= host_state.worldbrush->numleafs )
  1737. return;
  1738. mleaf_t* pLeaf = &host_state.worldbrush->leafs[leafID];
  1739. pFogVolume->m_FogVolumeID = pLeaf->leafWaterDataID;
  1740. if( pFogVolume->m_FogVolumeID == -1 )
  1741. return;
  1742. pFogVolume->m_InFogVolume = true;
  1743. mleafwaterdata_t* pLeafWaterData = &host_state.worldbrush->leafwaterdata[pLeaf->leafWaterDataID];
  1744. if( pLeafWaterData->surfaceTexInfoID == -1 )
  1745. {
  1746. // Should this ever happen?????
  1747. pFogVolume->m_FogEnabled = false;
  1748. return;
  1749. }
  1750. mtexinfo_t* pTexInfo = &host_state.worldbrush->texinfo[pLeafWaterData->surfaceTexInfoID];
  1751. IMaterial* pMaterial = pTexInfo->material;
  1752. if( pMaterial )
  1753. {
  1754. IMaterialVar* pFogColorVar = pMaterial->FindVar( "$fogcolor", NULL );
  1755. IMaterialVar* pFogEnableVar = pMaterial->FindVar( "$fogenable", NULL );
  1756. IMaterialVar* pFogStartVar = pMaterial->FindVar( "$fogstart", NULL );
  1757. IMaterialVar* pFogEndVar = pMaterial->FindVar( "$fogend", NULL );
  1758. pFogVolume->m_FogEnabled = pFogEnableVar->GetIntValue() ? true : false;
  1759. pFogColorVar->GetVecValue( pFogVolume->m_FogColor, 3 );
  1760. pFogVolume->m_FogStart = -pFogStartVar->GetFloatValue();
  1761. pFogVolume->m_FogEnd = -pFogEndVar->GetFloatValue();
  1762. pFogVolume->m_FogSurfaceZ = pLeafWaterData->surfaceZ;
  1763. pFogVolume->m_FogMinZ = pLeafWaterData->minZ;
  1764. pFogVolume->m_FogMode = MATERIAL_FOG_LINEAR;
  1765. }
  1766. else
  1767. {
  1768. static bool bComplained = false;
  1769. if( !bComplained )
  1770. {
  1771. Warning( "***Water vmt missing . . check console for missing materials!***\n" );
  1772. bComplained = true;
  1773. }
  1774. pFogVolume->m_FogEnabled = false;
  1775. }
  1776. }
  1777. //-----------------------------------------------------------------------------
  1778. // Resets a world render list
  1779. //-----------------------------------------------------------------------------
  1780. void ResetWorldRenderList( CWorldRenderList *pRenderList )
  1781. {
  1782. if ( pRenderList )
  1783. {
  1784. pRenderList->Reset();
  1785. }
  1786. }
  1787. //-----------------------------------------------------------------------------
  1788. // Call this before rendering; it clears out the lists of stuff to render
  1789. //-----------------------------------------------------------------------------
  1790. void Shader_WorldBegin( CWorldRenderList *pRenderList )
  1791. {
  1792. // Cache the convars so we don't keep accessing them...
  1793. s_ShaderConvars.m_bDrawWorld = r_drawworld.GetBool();
  1794. s_ShaderConvars.m_nDrawLeaf = r_drawleaf.GetInt();
  1795. s_ShaderConvars.m_bDrawFuncDetail = r_drawfuncdetail.GetBool();
  1796. ResetWorldRenderList( pRenderList );
  1797. // Clear out the decal list
  1798. DecalSurfacesInit( false );
  1799. // Clear out the render lists of overlays
  1800. OverlayMgr()->ClearRenderLists();
  1801. // Clear out the render lists of shadows
  1802. g_pShadowMgr->ClearShadowRenderList( );
  1803. }
  1804. void Shader_GetSurfVertexAndIndexCount( SurfaceHandle_t surfaceHandle, int *pVertexCount, int *pIndexCount )
  1805. {
  1806. *pVertexCount = *pIndexCount = 0;
  1807. if ( SurfaceHasPrims( surfaceHandle ) )
  1808. {
  1809. mprimitive_t *pPrim = &host_state.worldbrush->primitives[MSurf_FirstPrimID( surfaceHandle )];
  1810. // I don't understand why the vertCount would be 0 here, but that's what the old code says
  1811. if ( pPrim->vertCount == 0 )
  1812. {
  1813. *pVertexCount = MSurf_VertCount( surfaceHandle );
  1814. *pIndexCount = pPrim->indexCount;
  1815. }
  1816. }
  1817. else
  1818. {
  1819. // Triangle strip
  1820. *pVertexCount = MSurf_VertCount( surfaceHandle );
  1821. *pIndexCount = ( *pVertexCount - 2 ) * 3;
  1822. }
  1823. }
  1824. // This was moved out to a separate function to work around a VS2010 PC-only code-gen bug
  1825. static void Shader_WorldZFillSurfChain_SinglePrimitive( SurfaceHandle_t surfaceHandle, CMeshBuilder &meshBuilder, int &nStartVert )
  1826. {
  1827. mvertex_t *pWorldVerts = host_state.worldbrush->vertexes;
  1828. mprimitive_t *pPrim = &host_state.worldbrush->primitives[MSurf_FirstPrimID( surfaceHandle )];
  1829. if ( pPrim->vertCount == 0 )
  1830. {
  1831. int firstVert = MSurf_FirstVertIndex( surfaceHandle );
  1832. for ( int i = 0; i < MSurf_VertCount(surfaceHandle); i++ )
  1833. {
  1834. int vertIndex = host_state.worldbrush->vertindices[firstVert + i];
  1835. meshBuilder.Position3fv( pWorldVerts[vertIndex].position.Base() );
  1836. meshBuilder.AdvanceVertex();
  1837. }
  1838. for ( int primIndex = 0; primIndex < pPrim->indexCount; primIndex++ )
  1839. {
  1840. meshBuilder.FastIndex( host_state.worldbrush->primindices[pPrim->firstIndex + primIndex] + nStartVert );
  1841. }
  1842. }
  1843. }
  1844. //-----------------------------------------------------------------------------
  1845. // Performs the z-fill
  1846. //-----------------------------------------------------------------------------
  1847. static void Shader_WorldZFillSurfChain_Single( SurfaceHandle_t surfaceHandle, CMeshBuilder &meshBuilder, int &nStartVert )
  1848. {
  1849. mvertex_t *pWorldVerts = host_state.worldbrush->vertexes;
  1850. int nSurfTriangleCount = MSurf_VertCount( surfaceHandle ) - 2;
  1851. unsigned short *pVertIndex = &(host_state.worldbrush->vertindices[MSurf_FirstVertIndex( surfaceHandle )]);
  1852. // add surface to this batch
  1853. if ( SurfaceHasPrims(surfaceHandle) )
  1854. {
  1855. Shader_WorldZFillSurfChain_SinglePrimitive( surfaceHandle, meshBuilder, nStartVert );
  1856. }
  1857. else
  1858. {
  1859. switch (nSurfTriangleCount)
  1860. {
  1861. case 1:
  1862. meshBuilder.Position3fv( pWorldVerts[*pVertIndex++].position.Base() );
  1863. meshBuilder.AdvanceVertex();
  1864. meshBuilder.Position3fv( pWorldVerts[*pVertIndex++].position.Base() );
  1865. meshBuilder.AdvanceVertex();
  1866. meshBuilder.Position3fv( pWorldVerts[*pVertIndex++].position.Base() );
  1867. meshBuilder.AdvanceVertex();
  1868. meshBuilder.FastIndex( nStartVert );
  1869. meshBuilder.FastIndex( nStartVert + 1 );
  1870. meshBuilder.FastIndex( nStartVert + 2 );
  1871. break;
  1872. case 2:
  1873. meshBuilder.Position3fv( pWorldVerts[*pVertIndex++].position.Base() );
  1874. meshBuilder.AdvanceVertex();
  1875. meshBuilder.Position3fv( pWorldVerts[*pVertIndex++].position.Base() );
  1876. meshBuilder.AdvanceVertex();
  1877. meshBuilder.Position3fv( pWorldVerts[*pVertIndex++].position.Base() );
  1878. meshBuilder.AdvanceVertex();
  1879. meshBuilder.Position3fv( pWorldVerts[*pVertIndex++].position.Base() );
  1880. meshBuilder.AdvanceVertex();
  1881. meshBuilder.FastIndex( nStartVert );
  1882. meshBuilder.FastIndex( nStartVert + 1 );
  1883. meshBuilder.FastIndex( nStartVert + 2 );
  1884. meshBuilder.FastIndex( nStartVert );
  1885. meshBuilder.FastIndex( nStartVert + 2 );
  1886. meshBuilder.FastIndex( nStartVert + 3 );
  1887. break;
  1888. default:
  1889. {
  1890. for ( unsigned short v = 0; v < nSurfTriangleCount; ++v )
  1891. {
  1892. meshBuilder.Position3fv( pWorldVerts[*pVertIndex++].position.Base() );
  1893. meshBuilder.AdvanceVertex();
  1894. meshBuilder.FastIndex( nStartVert );
  1895. meshBuilder.FastIndex( nStartVert + v + 1 );
  1896. meshBuilder.FastIndex( nStartVert + v + 2 );
  1897. }
  1898. meshBuilder.Position3fv( pWorldVerts[*pVertIndex++].position.Base() );
  1899. meshBuilder.AdvanceVertex();
  1900. meshBuilder.Position3fv( pWorldVerts[*pVertIndex++].position.Base() );
  1901. meshBuilder.AdvanceVertex();
  1902. }
  1903. break;
  1904. }
  1905. }
  1906. nStartVert += nSurfTriangleCount + 2;
  1907. }
  1908. static const int s_DrawWorldListsToSortGroup[MAX_MAT_SORT_GROUPS] =
  1909. {
  1910. MAT_SORT_GROUP_STRICTLY_ABOVEWATER,
  1911. MAT_SORT_GROUP_STRICTLY_UNDERWATER,
  1912. MAT_SORT_GROUP_INTERSECTS_WATER_SURFACE,
  1913. MAT_SORT_GROUP_WATERSURFACE,
  1914. };
  1915. static ConVar r_flashlightrendermodels( "r_flashlightrendermodels", "1" );
  1916. // NOTE: This is a modified copy of Shader_DrawChainsStatic()
  1917. static void Shader_DrawDepthFillChainsStatic( IMatRenderContext *pRenderContext, const CMSurfaceSortList &sortList, int nSortGroup, unsigned long flags )
  1918. {
  1919. CUtlVectorFixed<vertexformatlist_t, MAX_VERTEX_FORMAT_CHANGES> meshList;
  1920. int meshMap[MAX_VERTEX_FORMAT_CHANGES];
  1921. CUtlVectorFixedGrowable<batchlist_t, 512> batchList;
  1922. bool bWarn = true;
  1923. CMeshBuilder meshBuilder;
  1924. CUtlVector<const surfacesortgroup_t *> alphatestedGroups;
  1925. const CUtlVector<surfacesortgroup_t *> &groupList = sortList.GetSortList(nSortGroup);
  1926. int count = groupList.Count();
  1927. int i, listIndex = 0;
  1928. IMaterial *pDrawMaterial;
  1929. if ( flags & DRAWWORLDLISTS_DRAW_SSAO )
  1930. {
  1931. pDrawMaterial = g_pMaterialSSAODepthWrite[ 0 ][ 1 ];
  1932. }
  1933. else
  1934. {
  1935. pDrawMaterial = g_pMaterialDepthWrite[ 0 ][ 1 ];
  1936. }
  1937. int nMaxIndices = pRenderContext->GetMaxIndicesToRender();
  1938. while ( listIndex < count )
  1939. {
  1940. const surfacesortgroup_t &group = *groupList[listIndex];
  1941. SurfaceHandle_t surfID = sortList.GetSurfaceAtHead(group);
  1942. int sortID = MSurf_MaterialSortID( surfID );
  1943. IMaterial *pMaterial = MSurf_TexInfo( surfID )->material;
  1944. if ( (MSurf_Flags(surfID) & SURFDRAW_WATERSURFACE) || !g_DepthMeshForSortID[sortID] || pMaterial->IsTranslucent() )
  1945. {
  1946. listIndex++;
  1947. continue;
  1948. }
  1949. if ( pMaterial->IsAlphaTested() )
  1950. {
  1951. listIndex++;
  1952. alphatestedGroups.AddToTail( &group );
  1953. continue;
  1954. }
  1955. IMesh *pBuildMesh = pRenderContext->GetDynamicMesh( false, g_DepthMeshForSortID[sortID] );
  1956. meshBuilder.Begin( pBuildMesh, MATERIAL_TRIANGLES, 0, nMaxIndices );
  1957. IMesh *pLastMesh = NULL;
  1958. int indexCount = 0;
  1959. int meshIndex = -1;
  1960. for ( ; listIndex < count; listIndex++ )
  1961. {
  1962. const surfacesortgroup_t &group = *groupList[listIndex];
  1963. surfID = sortList.GetSurfaceAtHead(group);
  1964. Assert( IS_SURF_VALID( surfID ) );
  1965. Assert( group.triangleCount > 0 );
  1966. int numIndex = group.triangleCount * 3;
  1967. if ( indexCount + numIndex > nMaxIndices )
  1968. {
  1969. if ( numIndex > nMaxIndices )
  1970. {
  1971. DevMsg("Too many faces with the same material in scene! Material: %s, num indices %d (max: %d)\n", pDrawMaterial ? pDrawMaterial->GetName() : "null", numIndex, nMaxIndices );
  1972. break;
  1973. }
  1974. pLastMesh = NULL;
  1975. break;
  1976. }
  1977. sortID = MSurf_MaterialSortID( surfID );
  1978. if ( g_DepthMeshForSortID[sortID] != pLastMesh )
  1979. {
  1980. if( meshList.Count() < MAX_VERTEX_FORMAT_CHANGES - 1 )
  1981. {
  1982. meshIndex = meshList.AddToTail();
  1983. meshList[meshIndex].numbatches = 0;
  1984. meshList[meshIndex].firstbatch = batchList.Count();
  1985. pLastMesh = g_DepthMeshForSortID[sortID];
  1986. Assert( pLastMesh );
  1987. meshList[meshIndex].pMesh = pLastMesh;
  1988. }
  1989. else
  1990. {
  1991. if ( bWarn )
  1992. {
  1993. DevWarning( 2, "Too many vertex format changes in frame, whole world not rendered\n" );
  1994. bWarn = false;
  1995. }
  1996. continue;
  1997. }
  1998. }
  1999. int batchIndex = batchList.AddToTail();
  2000. batchlist_t &batch = batchList[batchIndex];
  2001. batch.firstIndex = indexCount;
  2002. batch.surfID = surfID;
  2003. batch.numIndex = numIndex;
  2004. Assert( indexCount + batch.numIndex < nMaxIndices );
  2005. indexCount += batch.numIndex;
  2006. meshList[meshIndex].numbatches++;
  2007. MSL_FOREACH_SURFACE_IN_GROUP_BEGIN(sortList, group, surfID)
  2008. {
  2009. if ( MSurf_Flags( surfID ) == 0 )
  2010. continue;
  2011. BuildDepthFillIndicesForWorldSurface( meshBuilder, surfID, host_state.worldbrush );
  2012. }
  2013. MSL_FOREACH_SURFACE_IN_GROUP_END()
  2014. }
  2015. // close out the index buffer
  2016. meshBuilder.End( false, false );
  2017. int meshTotal = meshList.Count();
  2018. // HACKHACK: Crappy little bubble sort
  2019. // UNDONE: Make the traversal happen so that they are already sorted when you get here.
  2020. // NOTE: Profiled in a fairly complex map. This is not even costing 0.01ms / frame!
  2021. for ( i = 0; i < meshTotal; i++ )
  2022. {
  2023. meshMap[i] = i;
  2024. }
  2025. bool swapped = true;
  2026. while ( swapped )
  2027. {
  2028. swapped = false;
  2029. for ( i = 1; i < meshTotal; i++ )
  2030. {
  2031. if ( meshList[meshMap[i]].pMesh < meshList[meshMap[i-1]].pMesh )
  2032. {
  2033. int tmp = meshMap[i-1];
  2034. meshMap[i-1] = meshMap[i];
  2035. meshMap[i] = tmp;
  2036. swapped = true;
  2037. }
  2038. }
  2039. }
  2040. pRenderContext->BeginBatch( pBuildMesh );
  2041. for ( int m = 0; m < meshTotal; m++ )
  2042. {
  2043. vertexformatlist_t &mesh = meshList[meshMap[m]];
  2044. Assert( mesh.pMesh && pBuildMesh );
  2045. pRenderContext->BindBatch( mesh.pMesh, pDrawMaterial );
  2046. for ( int b = 0; b < mesh.numbatches; b++ )
  2047. {
  2048. batchlist_t &batch = batchList[b+mesh.firstbatch];
  2049. pRenderContext->Bind( pDrawMaterial, NULL );
  2050. pRenderContext->DrawBatch( MATERIAL_TRIANGLES, batch.firstIndex, batch.numIndex );
  2051. }
  2052. }
  2053. pRenderContext->EndBatch();
  2054. // if we get here and pLast mesh is NULL and we rendered somthing, we need to loop
  2055. if ( pLastMesh || !meshTotal )
  2056. break;
  2057. meshList.RemoveAll();
  2058. batchList.RemoveAll();
  2059. }
  2060. // Now draw the alpha-tested groups we stored away earlier
  2061. ERenderDepthMode_t DepthMode;
  2062. if ( flags & DRAWWORLDLISTS_DRAW_SSAO )
  2063. {
  2064. DepthMode = DEPTH_MODE_SSA0;
  2065. }
  2066. else
  2067. {
  2068. DepthMode = DEPTH_MODE_SHADOW;
  2069. }
  2070. for ( int i = 0; i < alphatestedGroups.Count(); i++ )
  2071. {
  2072. Shader_DrawDynamicChain( pRenderContext, sortList, *alphatestedGroups[i], DepthMode );
  2073. }
  2074. }
  2075. static void Shader_WorldShadowDepthFillStaticVB( IMatRenderContext *pRenderContext, CWorldRenderList *pRenderList, unsigned long flags )
  2076. {
  2077. int g;
  2078. const CMSurfaceSortList &sortList = pRenderList->m_SortList;
  2079. for ( g = 0; g < MAX_MAT_SORT_GROUPS; ++g )
  2080. {
  2081. if ( ( flags & ( 1 << g ) ) == 0 )
  2082. continue;
  2083. int nSortGroup = s_DrawWorldListsToSortGroup[g];
  2084. Shader_DrawDepthFillChainsStatic( pRenderContext, sortList, nSortGroup, flags );
  2085. if ( ( flags & DRAWWORLDLISTS_DRAW_SKIP_DISPLACEMENTS ) == 0 )
  2086. {
  2087. // Draws opaque displacement surfaces along with shadows, overlays, flashlights, etc.
  2088. Shader_DrawDispChain( pRenderContext, nSortGroup, pRenderList->m_DispSortList, flags, DEPTH_MODE_SHADOW );
  2089. }
  2090. }
  2091. }
  2092. //-----------------------------------------------------------------------------
  2093. // Performs the shadow depth texture fill
  2094. //-----------------------------------------------------------------------------
  2095. static void Shader_WorldShadowDepthFill( IMatRenderContext *pRenderContext, CWorldRenderList *pRenderList, unsigned long flags )
  2096. {
  2097. if ( r_csm_static_vb.GetBool() )
  2098. {
  2099. Shader_WorldShadowDepthFillStaticVB( pRenderContext, pRenderList, flags );
  2100. return;
  2101. }
  2102. // First, count the number of vertices + indices
  2103. int nVertexCount = 0;
  2104. int nIndexCount = 0;
  2105. ERenderDepthMode_t DepthMode = DEPTH_MODE_SHADOW;
  2106. if ( flags & DRAWWORLDLISTS_DRAW_SSAO )
  2107. {
  2108. DepthMode = DEPTH_MODE_SSA0;
  2109. }
  2110. int g;
  2111. CUtlVector<const surfacesortgroup_t *> alphatestedGroups;
  2112. const CMSurfaceSortList &sortList = pRenderList->m_SortList;
  2113. for ( g = 0; g < MAX_MAT_SORT_GROUPS; ++g )
  2114. {
  2115. if ( ( flags & ( 1 << g ) ) == 0 )
  2116. continue;
  2117. int nSortGroup = s_DrawWorldListsToSortGroup[g];
  2118. MSL_FOREACH_GROUP_BEGIN(sortList, nSortGroup, group )
  2119. {
  2120. SurfaceHandle_t surfID = sortList.GetSurfaceAtHead(group);
  2121. if ( MSurf_Flags( surfID ) & SURFDRAW_WATERSURFACE )
  2122. continue;
  2123. IMaterial *pMaterial = MSurf_TexInfo( surfID )->material;
  2124. if( pMaterial->IsTranslucent() )
  2125. continue;
  2126. if ( pMaterial->IsAlphaTested() )
  2127. {
  2128. alphatestedGroups.AddToTail( &group );
  2129. continue;
  2130. }
  2131. nVertexCount += group.vertexCount;
  2132. nIndexCount += group.triangleCount*3;
  2133. }
  2134. MSL_FOREACH_GROUP_END()
  2135. if ( ( flags & DRAWWORLDLISTS_DRAW_SKIP_DISPLACEMENTS ) == 0 )
  2136. {
  2137. // Draws opaque displacement surfaces along with shadows, overlays, flashlights, etc.
  2138. Shader_DrawDispChain( pRenderContext, nSortGroup, pRenderList->m_DispSortList, flags, DepthMode );
  2139. }
  2140. }
  2141. if ( nVertexCount == 0 )
  2142. return;
  2143. //this bind needs to be before the GetDynamic Mesh call, changes the vertex size. tmauer.
  2144. IMaterial *pDrawMaterial;
  2145. if ( DepthMode == DEPTH_MODE_SHADOW )
  2146. {
  2147. pDrawMaterial = g_pMaterialDepthWrite[ 0 ][ 1 ];
  2148. }
  2149. else
  2150. {
  2151. pDrawMaterial = g_pMaterialSSAODepthWrite[ 0 ][ 1 ];
  2152. }
  2153. pRenderContext->Bind( pDrawMaterial );
  2154. IMesh *pMesh = pRenderContext->GetDynamicMesh( false );
  2155. int nMaxIndices = pRenderContext->GetMaxIndicesToRender();
  2156. int nMaxVertices = pRenderContext->GetMaxVerticesToRender( pDrawMaterial ); // opaque, nocull
  2157. // nBatchIndexCount and nBatchVertexCount are the number of indices and vertices we can fit in this batch
  2158. // Each batch must have fewer than nMaxIndices and nMaxVertices or the material system will fail
  2159. int nBatchIndexCount = MIN( nIndexCount, nMaxIndices );
  2160. int nBatchVertexCount = MIN( nVertexCount, nMaxVertices );
  2161. CMeshBuilder meshBuilder;
  2162. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nBatchVertexCount, nBatchIndexCount );
  2163. int nStartVert = 0;
  2164. for ( g = 0; g < MAX_MAT_SORT_GROUPS; ++g )
  2165. {
  2166. if ( ( flags & ( 1 << g ) ) == 0 )
  2167. continue;
  2168. int nSortGroup = s_DrawWorldListsToSortGroup[g];
  2169. MSL_FOREACH_GROUP_BEGIN(sortList, nSortGroup, group )
  2170. {
  2171. SurfaceHandle_t surfID = sortList.GetSurfaceAtHead(group);
  2172. // Check to see if we can add this list to the current batch...
  2173. if ( ( group.triangleCount == 0 ) || ( group.vertexCount == 0 ) )
  2174. continue;
  2175. IMaterial *pMaterial = MSurf_TexInfo( surfID )->material;
  2176. // Opaque only on this loop
  2177. if( pMaterial->IsTranslucent() || pMaterial->IsAlphaTested() )
  2178. continue;
  2179. MSL_FOREACH_SURFACE_IN_GROUP_BEGIN(sortList, group, nSurfID)
  2180. {
  2181. // Draw all surfaces except for water surfaces since it may move up or down to fixup water transitions.
  2182. if ( MSurf_Flags( nSurfID ) == 0 || ( MSurf_Flags( nSurfID ) & SURFDRAW_WATERSURFACE ) != 0 )
  2183. continue;
  2184. int nSurfaceVertexCount, nSurfaceIndexCount;
  2185. Shader_GetSurfVertexAndIndexCount( nSurfID, &nSurfaceVertexCount, &nSurfaceIndexCount );
  2186. if ( nSurfaceVertexCount > nMaxVertices || nSurfaceIndexCount > nMaxIndices )
  2187. {
  2188. // Too many vertices/indices in a batch, no simple way to split the batch
  2189. Error( "Too many vertices (%d, max: %d) or indices (%d, max: %d) in surface.\n", nSurfaceVertexCount, nMaxVertices, nSurfaceIndexCount, nMaxIndices );
  2190. continue;
  2191. }
  2192. if ( nBatchIndexCount < nSurfaceIndexCount || nBatchVertexCount < nSurfaceVertexCount )
  2193. {
  2194. // Surface doesn't fit, flush the current batch.
  2195. meshBuilder.End();
  2196. pMesh->Draw();
  2197. nBatchIndexCount = MIN( nIndexCount, nMaxIndices );
  2198. nBatchVertexCount = MIN( nVertexCount, nMaxVertices );
  2199. pMesh = pRenderContext->GetDynamicMesh( false );
  2200. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nBatchVertexCount, nBatchIndexCount );
  2201. nStartVert = 0;
  2202. }
  2203. Shader_WorldZFillSurfChain_Single( nSurfID, meshBuilder, nStartVert );
  2204. nBatchIndexCount -= nSurfaceIndexCount;
  2205. nBatchVertexCount -= nSurfaceVertexCount;
  2206. nIndexCount -= nSurfaceIndexCount;
  2207. nVertexCount -= nSurfaceVertexCount;
  2208. }
  2209. MSL_FOREACH_SURFACE_IN_GROUP_END()
  2210. }
  2211. MSL_FOREACH_GROUP_END()
  2212. }
  2213. meshBuilder.End();
  2214. pMesh->Draw();
  2215. // Now draw the alpha-tested groups we stored away earlier
  2216. for ( int i = 0; i < alphatestedGroups.Count(); i++ )
  2217. {
  2218. Shader_DrawDynamicChain( pRenderContext, sortList, *alphatestedGroups[i], DepthMode );
  2219. }
  2220. }
  2221. struct WorldShadowMeshInfo_t
  2222. {
  2223. IMesh *m_pMesh;
  2224. CCopyableUtlVectorFixed< const surfacesortgroup_t *, 1024 > m_Groups;
  2225. };
  2226. // Minimize the number of draw calls - try to have one draw call per shadow mesh (cf g_Meshes build in WorldStaticMeshCreate)
  2227. static void Shader_WorldShadowDepthFillFast( IMatRenderContext *pRenderContext, CWorldRenderList *pRenderList, unsigned long flags )
  2228. {
  2229. // Draws opaque displacement surfaces along with shadows, overlays, flashlights, etc.
  2230. if ( ( flags & DRAWWORLDLISTS_DRAW_SKIP_DISPLACEMENTS ) == 0 )
  2231. {
  2232. for ( int g = 0; g < MAX_MAT_SORT_GROUPS; ++g )
  2233. {
  2234. if ( ( flags & ( 1 << g ) ) == 0 )
  2235. continue;
  2236. int nSortGroup = s_DrawWorldListsToSortGroup[g];
  2237. ERenderDepthMode_t DepthMode = ( flags & DRAWWORLDLISTS_DRAW_SSAO ) ? DEPTH_MODE_SSA0 : DEPTH_MODE_SHADOW;
  2238. Shader_DrawDispChain( pRenderContext, nSortGroup, pRenderList->m_DispSortList, flags, DepthMode );
  2239. }
  2240. }
  2241. //this bind needs to be before the GetDynamic Mesh call, changes the vertex size. tmauer.
  2242. IMaterial *pDrawMaterial;
  2243. if ( flags & DRAWWORLDLISTS_DRAW_SSAO )
  2244. {
  2245. pDrawMaterial = g_pMaterialSSAODepthWrite[ 0 ][ 1 ];
  2246. }
  2247. else
  2248. {
  2249. pDrawMaterial = g_pMaterialDepthWrite[ 0 ][ 1 ];
  2250. }
  2251. pRenderContext->Bind( pDrawMaterial );
  2252. int nMaxIndices = pRenderContext->GetMaxIndicesToRender();
  2253. CUtlVectorFixedGrowable< const surfacesortgroup_t *, 1024 > alphatestedGroups;
  2254. CUtlVectorFixedGrowable< WorldShadowMeshInfo_t, 32 > meshinfos;
  2255. const CMSurfaceSortList &sortList = pRenderList->m_SortList;
  2256. for ( int g = 0; g < MAX_MAT_SORT_GROUPS; ++g )
  2257. {
  2258. if ( ( flags & ( 1 << g ) ) == 0 )
  2259. continue;
  2260. int nSortGroup = s_DrawWorldListsToSortGroup[g];
  2261. MSL_FOREACH_GROUP_BEGIN(sortList, nSortGroup, group )
  2262. {
  2263. // Don't bother with empty groups
  2264. if ( ( group.triangleCount == 0 ) || ( group.vertexCount == 0 ) )
  2265. continue;
  2266. SurfaceHandle_t surfID = sortList.GetSurfaceAtHead(group);
  2267. int nFlags = MSurf_Flags( surfID );
  2268. IMaterial *pMaterial = MSurf_TexInfo( surfID )->material;
  2269. int sortID = MSurf_MaterialSortID( surfID );
  2270. IMesh* pMesh = g_DepthMeshForSortID[sortID];
  2271. if ( ( nFlags & SURFDRAW_WATERSURFACE ) || !pMesh || pMaterial->IsTranslucent() )
  2272. {
  2273. continue;
  2274. }
  2275. if ( pMaterial->IsAlphaTested() )
  2276. {
  2277. alphatestedGroups.AddToTail( &group );
  2278. continue;
  2279. }
  2280. // Sort group per mesh
  2281. // (Search by iterating over the vector (since the vector contains very few element - replace with a map if it becomes a bottleneck))
  2282. bool bFound = false;
  2283. for ( int i = 0; i < meshinfos.Count(); ++i )
  2284. {
  2285. if ( meshinfos[i].m_pMesh == pMesh )
  2286. {
  2287. meshinfos[i].m_Groups.AddToTail( &group );
  2288. bFound = true;
  2289. }
  2290. }
  2291. if ( !bFound )
  2292. {
  2293. meshinfos.AddToTail();
  2294. meshinfos.Tail().m_pMesh = pMesh;
  2295. meshinfos.Tail().m_Groups.AddToTail( &group );
  2296. }
  2297. }
  2298. MSL_FOREACH_GROUP_END()
  2299. CMeshBuilder meshBuilder;
  2300. for ( int i = 0; i < meshinfos.Count(); i++ )
  2301. {
  2302. WorldShadowMeshInfo_t& meshinfo = meshinfos[i];
  2303. IMesh *pBuildMesh = pRenderContext->GetDynamicMesh( false );
  2304. meshBuilder.Begin( pBuildMesh, MATERIAL_TRIANGLES, 0, nMaxIndices );
  2305. int nIndexCount = 0;
  2306. int nBatchIndexCount = nMaxIndices;
  2307. for ( int j = 0; j < meshinfo.m_Groups.Count(); ++j )
  2308. {
  2309. const surfacesortgroup_t &group = *meshinfo.m_Groups[j];
  2310. int nGroupIndexCount = group.triangleCount*3;
  2311. const SurfaceHandle_t surfID = sortList.GetSurfaceAtHead(group);
  2312. NOTE_UNUSED( surfID );
  2313. Assert( IS_SURF_VALID( surfID ) );
  2314. bool bSplitPerSurface = ( nGroupIndexCount > nMaxIndices );
  2315. if ( !bSplitPerSurface )
  2316. {
  2317. // Is there room enough for these surfaces?
  2318. if ( nBatchIndexCount < nGroupIndexCount )
  2319. {
  2320. // Surfaces don't fit, flush the current batch.
  2321. meshBuilder.End( false, false );
  2322. pRenderContext->BeginBatch( pBuildMesh );
  2323. pRenderContext->BindBatch( meshinfo.m_pMesh, pDrawMaterial );
  2324. pRenderContext->Bind( pDrawMaterial, NULL );
  2325. pRenderContext->DrawBatch( MATERIAL_TRIANGLES, 0, nIndexCount );
  2326. pRenderContext->EndBatch();
  2327. nBatchIndexCount = nMaxIndices;
  2328. nIndexCount = 0;
  2329. pBuildMesh = pRenderContext->GetDynamicMesh( false );
  2330. meshBuilder.Begin( pBuildMesh, MATERIAL_TRIANGLES, 0, nMaxIndices );
  2331. }
  2332. nBatchIndexCount -= nGroupIndexCount;
  2333. nIndexCount += nGroupIndexCount;
  2334. }
  2335. MSL_FOREACH_SURFACE_IN_GROUP_BEGIN(sortList, group, surfID)
  2336. {
  2337. if ( MSurf_Flags( surfID ) == 0 )
  2338. continue;
  2339. if ( bSplitPerSurface )
  2340. {
  2341. int nSurfaceVertexCount, nSurfaceIndexCount;
  2342. Shader_GetSurfVertexAndIndexCount( surfID, &nSurfaceVertexCount, &nSurfaceIndexCount );
  2343. // Is there room enough for this surface?
  2344. if ( nBatchIndexCount < nSurfaceIndexCount )
  2345. {
  2346. // Surfaces don't fit, flush the current batch.
  2347. meshBuilder.End( false, false );
  2348. pRenderContext->BeginBatch( pBuildMesh );
  2349. pRenderContext->BindBatch( meshinfo.m_pMesh, pDrawMaterial );
  2350. pRenderContext->Bind( pDrawMaterial, NULL );
  2351. pRenderContext->DrawBatch( MATERIAL_TRIANGLES, 0, nIndexCount );
  2352. pRenderContext->EndBatch();
  2353. nBatchIndexCount = nMaxIndices;
  2354. nIndexCount = 0;
  2355. pBuildMesh = pRenderContext->GetDynamicMesh( false );
  2356. meshBuilder.Begin( pBuildMesh, MATERIAL_TRIANGLES, 0, nMaxIndices );
  2357. }
  2358. nBatchIndexCount -= nSurfaceIndexCount;
  2359. nIndexCount += nSurfaceIndexCount;
  2360. }
  2361. BuildDepthFillIndicesForWorldSurface( meshBuilder, surfID, host_state.worldbrush );
  2362. }
  2363. MSL_FOREACH_SURFACE_IN_GROUP_END()
  2364. }
  2365. meshBuilder.End( false, false );
  2366. pRenderContext->BeginBatch( pBuildMesh );
  2367. pRenderContext->BindBatch( meshinfo.m_pMesh, pDrawMaterial );
  2368. pRenderContext->Bind( pDrawMaterial, NULL );
  2369. pRenderContext->DrawBatch( MATERIAL_TRIANGLES, 0, nIndexCount );
  2370. pRenderContext->EndBatch();
  2371. meshinfo.m_Groups.RemoveAll();
  2372. }
  2373. meshinfos.RemoveAll();
  2374. }
  2375. // Now draw the alpha-tested groups we stored away earlier
  2376. ERenderDepthMode_t DepthMode = DEPTH_MODE_SHADOW;
  2377. if ( flags & DRAWWORLDLISTS_DRAW_SSAO )
  2378. {
  2379. DepthMode = DEPTH_MODE_SSA0;
  2380. }
  2381. for ( int i = 0; i < alphatestedGroups.Count(); i++ )
  2382. {
  2383. Shader_DrawDynamicChain( pRenderContext, sortList, *alphatestedGroups[i], DepthMode );
  2384. }
  2385. }
  2386. //-----------------------------------------------------------------------------
  2387. // Performs the shadow depth texture fill
  2388. //-----------------------------------------------------------------------------
  2389. static void Shader_WorldShadowDepthFillX360( IMatRenderContext *pRenderContext, CWorldRenderList *pRenderList, unsigned long flags )
  2390. {
  2391. PIXEVENT( pRenderContext, "Shader_WorldShadowDepthFillX360()" );
  2392. // FIXME: Batch this up with fast path style rendering!
  2393. // Draws opaque displacement surfaces along with shadows, overlays, flashlights, etc.
  2394. for ( int g = 0; g < MAX_MAT_SORT_GROUPS; ++g )
  2395. {
  2396. if ( ( flags & ( 1 << g ) ) == 0 )
  2397. continue;
  2398. int nSortGroup = s_DrawWorldListsToSortGroup[g];
  2399. Shader_DrawDispChain( pRenderContext, nSortGroup, pRenderList->m_DispSortList, flags, DEPTH_MODE_SHADOW );
  2400. }
  2401. // nBatchIndexCount is the number of indices we can fit in this batch
  2402. int nMaxIndices = pRenderContext->GetMaxIndicesToRender();
  2403. // First, count the number of indices and instances
  2404. int nInstanceCount = 0;
  2405. int nIndexCount = 0;
  2406. CUtlVectorFixedGrowable< const surfacesortgroup_t *, 1024 > alphatestedGroups;
  2407. CUtlVectorFixedGrowable< const surfacesortgroup_t *, 1024 > groups;
  2408. CUtlVectorFixedGrowable< const surfacesortgroup_t *, 128 > groupsBlowingIndexBufferLimit;
  2409. const CMSurfaceSortList &sortList = pRenderList->m_SortList;
  2410. for ( int g = 0; g < MAX_MAT_SORT_GROUPS; ++g )
  2411. {
  2412. if ( ( flags & ( 1 << g ) ) == 0 )
  2413. continue;
  2414. int nSortGroup = s_DrawWorldListsToSortGroup[g];
  2415. MSL_FOREACH_GROUP_BEGIN( sortList, nSortGroup, group )
  2416. {
  2417. // Don't bother with empty groups
  2418. if ( ( group.triangleCount == 0 ) || ( group.vertexCount == 0 ) )
  2419. continue;
  2420. SurfaceHandle_t surfID = sortList.GetSurfaceAtHead(group);
  2421. int nFlags = MSurf_Flags( surfID );
  2422. if ( nFlags & ( SURFDRAW_WATERSURFACE | SURFDRAW_TRANS ) )
  2423. continue;
  2424. if ( nFlags & SURFDRAW_ALPHATEST )
  2425. {
  2426. alphatestedGroups.AddToTail( &group );
  2427. continue;
  2428. }
  2429. groups.AddToTail( &group );
  2430. int nGroupIndexCount = group.triangleCount * 3;
  2431. nInstanceCount += nGroupIndexCount / nMaxIndices;
  2432. nInstanceCount += ( nGroupIndexCount % nMaxIndices ) ? 1 : 0;
  2433. nIndexCount += nGroupIndexCount;
  2434. }
  2435. MSL_FOREACH_GROUP_END()
  2436. }
  2437. // Now draw the alpha-tested groups we stored away earlier
  2438. IMaterial *pDrawMaterial = g_pMaterialDepthWrite[ 0 ][ 1 ];
  2439. ERenderDepthMode_t DepthMode = DEPTH_MODE_SHADOW;
  2440. if ( flags & DRAWWORLDLISTS_DRAW_SSAO )
  2441. {
  2442. pDrawMaterial = g_pMaterialSSAODepthWrite[ 0 ][ 1 ];
  2443. DepthMode = DEPTH_MODE_SSA0;
  2444. }
  2445. for ( int i = 0; i < alphatestedGroups.Count(); i++ )
  2446. {
  2447. Shader_DrawDynamicChain( pRenderContext, sortList, *alphatestedGroups[ i ], DepthMode );
  2448. }
  2449. if ( nIndexCount == 0 )
  2450. return;
  2451. // nBatchIndexCount is the number of indices we can fit in this batch int nMaxIndices = pRenderContext->GetMaxIndicesToRender();
  2452. int nBatchIndexCount = MIN( nIndexCount, nMaxIndices );
  2453. pRenderContext->Bind( pDrawMaterial );
  2454. IIndexBuffer *pBuildIndexBuffer = pRenderContext->GetDynamicIndexBuffer();
  2455. CIndexBuilder indexBuilder( pBuildIndexBuffer, MATERIAL_INDEX_FORMAT_16BIT );
  2456. indexBuilder.Lock( nBatchIndexCount, 0 );
  2457. int nIndexOffset = indexBuilder.Offset() / sizeof(uint16);
  2458. int nCurrInstanceCount = 0;
  2459. CMatRenderData< MeshInstanceData_t > meshInstanceData( pRenderContext, nInstanceCount );
  2460. MeshInstanceData_t *pMeshInstances = meshInstanceData.Base();
  2461. if ( !pMeshInstances )
  2462. return;
  2463. int nCount = groups.Count();
  2464. for ( int g = 0; g < nCount; ++g )
  2465. {
  2466. const surfacesortgroup_t &group = *(groups[g]);
  2467. SurfaceHandle_t nSurfID = sortList.GetSurfaceAtHead( group );
  2468. int nSortID = MSurf_MaterialSortID( nSurfID );
  2469. int nCurrIndexCount = group.triangleCount*3;
  2470. if ( nCurrIndexCount > nMaxIndices )
  2471. {
  2472. //Warning( "Too many indices\n" );
  2473. groupsBlowingIndexBufferLimit.AddToTail( &group );
  2474. continue;
  2475. }
  2476. // Is there room enough for these surfaces?
  2477. if ( nBatchIndexCount < nCurrIndexCount )
  2478. {
  2479. // Nope, fire off the current batch...
  2480. indexBuilder.Unlock();
  2481. pRenderContext->DrawInstances( nCurrInstanceCount, pMeshInstances );
  2482. nBatchIndexCount = MIN( nIndexCount, nMaxIndices );
  2483. indexBuilder.Lock( nBatchIndexCount, 0 );
  2484. pMeshInstances += nCurrInstanceCount;
  2485. nInstanceCount -= nCurrInstanceCount;
  2486. nCurrInstanceCount = 0;
  2487. nIndexOffset = indexBuilder.Offset() / sizeof(uint16);
  2488. }
  2489. nBatchIndexCount -= nCurrIndexCount;
  2490. nIndexCount -= nCurrIndexCount;
  2491. Assert( nCurrInstanceCount < nInstanceCount );
  2492. MeshInstanceData_t &currInstance = pMeshInstances[nCurrInstanceCount++];
  2493. memset( &currInstance, 0, sizeof(MeshInstanceData_t) );
  2494. currInstance.m_nPrimType = MATERIAL_TRIANGLES;
  2495. currInstance.m_pIndexBuffer = pBuildIndexBuffer;
  2496. currInstance.m_pVertexBuffer = g_WorldStaticMeshes[ nSortID ];
  2497. currInstance.m_nIndexOffset = indexBuilder.IndexCount();
  2498. currInstance.m_DiffuseModulation.Init( 1.0f, 1.0f, 1.0f, 1.0f );
  2499. MSL_FOREACH_SURFACE_IN_GROUP_BEGIN( sortList, group, nSurfID )
  2500. {
  2501. BuildIndicesForWorldSurface( indexBuilder, nSurfID, host_state.worldbrush );
  2502. }
  2503. MSL_FOREACH_SURFACE_IN_GROUP_END()
  2504. currInstance.m_nIndexCount = indexBuilder.IndexCount() - currInstance.m_nIndexOffset;
  2505. currInstance.m_nIndexOffset += nIndexOffset;
  2506. currInstance.m_nLightmapPageId = MATERIAL_SYSTEM_LIGHTMAP_PAGE_INVALID;
  2507. }
  2508. indexBuilder.Unlock();
  2509. pRenderContext->DrawInstances( nCurrInstanceCount, pMeshInstances );
  2510. pMeshInstances += nCurrInstanceCount;
  2511. nInstanceCount -= nCurrInstanceCount;
  2512. nCurrInstanceCount = 0;
  2513. nIndexOffset = indexBuilder.Offset() / sizeof(uint16);
  2514. nCount = groupsBlowingIndexBufferLimit.Count();
  2515. for ( int g = 0; g < nCount; ++g )
  2516. {
  2517. const surfacesortgroup_t &group = *(groupsBlowingIndexBufferLimit[g]);
  2518. SurfaceHandle_t nSurfID = sortList.GetSurfaceAtHead( group );
  2519. int nSortID = MSurf_MaterialSortID( nSurfID );
  2520. // Start a new instance for this group
  2521. nBatchIndexCount = MIN( nIndexCount, nMaxIndices );
  2522. indexBuilder.Lock( nBatchIndexCount, 0 );
  2523. MeshInstanceData_t *pCurrInstance = pMeshInstances;
  2524. memset( pCurrInstance, 0, sizeof(MeshInstanceData_t) );
  2525. pCurrInstance->m_nPrimType = MATERIAL_TRIANGLES;
  2526. pCurrInstance->m_pIndexBuffer = pBuildIndexBuffer;
  2527. pCurrInstance->m_pVertexBuffer = g_WorldStaticMeshes[ nSortID ];
  2528. pCurrInstance->m_nIndexOffset = indexBuilder.IndexCount();
  2529. pCurrInstance->m_DiffuseModulation.Init( 1.0f, 1.0f, 1.0f, 1.0f );
  2530. pCurrInstance->m_nLightmapPageId = MATERIAL_SYSTEM_LIGHTMAP_PAGE_INVALID;
  2531. MSL_FOREACH_SURFACE_IN_GROUP_BEGIN( sortList, group, nSurfID )
  2532. {
  2533. int nSurfIndexCount = GetIndexCountForWorldSurface( nSurfID );
  2534. // Is there room enough this surface?
  2535. if ( nBatchIndexCount < nSurfIndexCount )
  2536. {
  2537. // Nope, fire off the current batch...
  2538. int nNumIndicesInIndexBuilder = indexBuilder.IndexCount();
  2539. pCurrInstance->m_nIndexCount = nNumIndicesInIndexBuilder - pCurrInstance->m_nIndexOffset;
  2540. indexBuilder.Unlock();
  2541. pRenderContext->DrawInstances( 1, pMeshInstances );
  2542. // Start a new batch
  2543. nIndexCount -= nNumIndicesInIndexBuilder;
  2544. nBatchIndexCount = MIN( nIndexCount, nMaxIndices );
  2545. indexBuilder.Lock( nBatchIndexCount, 0 );
  2546. pMeshInstances++;
  2547. nInstanceCount--;
  2548. // Start a new instance for the remaining surfaces of this group
  2549. pCurrInstance = pMeshInstances;
  2550. memset( pCurrInstance, 0, sizeof(MeshInstanceData_t) );
  2551. pCurrInstance->m_nPrimType = MATERIAL_TRIANGLES;
  2552. pCurrInstance->m_pIndexBuffer = pBuildIndexBuffer;
  2553. pCurrInstance->m_pVertexBuffer = g_WorldStaticMeshes[ nSortID ];
  2554. pCurrInstance->m_nIndexOffset = indexBuilder.IndexCount();
  2555. pCurrInstance->m_DiffuseModulation.Init( 1.0f, 1.0f, 1.0f, 1.0f );
  2556. pCurrInstance->m_nLightmapPageId = MATERIAL_SYSTEM_LIGHTMAP_PAGE_INVALID;
  2557. }
  2558. BuildIndicesForWorldSurface( indexBuilder, nSurfID, host_state.worldbrush );
  2559. nBatchIndexCount -= nSurfIndexCount;
  2560. }
  2561. MSL_FOREACH_SURFACE_IN_GROUP_END()
  2562. // submit the instance
  2563. int nNumIndicesInIndexBuilder = indexBuilder.IndexCount();
  2564. pCurrInstance->m_nIndexCount = nNumIndicesInIndexBuilder - pCurrInstance->m_nIndexOffset;
  2565. indexBuilder.Unlock();
  2566. pRenderContext->DrawInstances( 1, pMeshInstances );
  2567. // Start a new batch
  2568. nIndexCount -= nNumIndicesInIndexBuilder;
  2569. pMeshInstances++;
  2570. nInstanceCount--;
  2571. }
  2572. Assert( nIndexCount == 0 );
  2573. Assert( nInstanceCount == 0 );
  2574. meshInstanceData.Release();
  2575. }
  2576. //-----------------------------------------------------------------------------
  2577. // Performs the z-fill
  2578. //-----------------------------------------------------------------------------
  2579. static void Shader_WorldZFill( IMatRenderContext *pRenderContext, CWorldRenderList *pRenderList, unsigned long flags )
  2580. {
  2581. // First, count the number of vertices + indices
  2582. int nVertexCount = 0;
  2583. int nIndexCount = 0;
  2584. int g;
  2585. const CMSurfaceSortList &sortList = pRenderList->m_SortList;
  2586. #ifdef _X360
  2587. bool bFastZRejectDisplacements = s_bFastZRejectDisplacements || ( r_fastzrejectdisp.GetInt() != 0 );
  2588. #endif
  2589. for ( g = 0; g < MAX_MAT_SORT_GROUPS; ++g )
  2590. {
  2591. if ( ( flags & ( 1 << g ) ) == 0 )
  2592. continue;
  2593. int nSortGroup = s_DrawWorldListsToSortGroup[g];
  2594. MSL_FOREACH_GROUP_BEGIN(sortList, nSortGroup, group )
  2595. {
  2596. SurfaceHandle_t surfID = sortList.GetSurfaceAtHead(group);
  2597. IMaterial *pMaterial = MSurf_TexInfo( surfID )->material;
  2598. if( pMaterial->IsAlphaTested() || pMaterial->IsTranslucent() )
  2599. {
  2600. continue;
  2601. }
  2602. nVertexCount += group.vertexCountNoDetail;
  2603. nIndexCount += group.indexCountNoDetail;
  2604. }
  2605. MSL_FOREACH_GROUP_END()
  2606. #ifdef _X360
  2607. // Draws opaque displacement surfaces along with shadows, overlays, flashlights, etc.
  2608. // NOTE: This only makes sense on the 360, since the extra batches aren't
  2609. // worth it on the PC (I think!)
  2610. if ( bFastZRejectDisplacements )
  2611. {
  2612. Shader_DrawDispChain( pRenderContext, nSortGroup, pRenderList->m_DispSortList, flags, true );
  2613. }
  2614. #endif
  2615. }
  2616. if ( nVertexCount == 0 )
  2617. return;
  2618. pRenderContext->Bind( g_pMaterialWriteZ );
  2619. IMesh *pMesh = pRenderContext->GetDynamicMesh( false );
  2620. int nMaxIndices = pRenderContext->GetMaxIndicesToRender();
  2621. int nMaxVertices = pRenderContext->GetMaxVerticesToRender( g_pMaterialWriteZ );
  2622. // nBatchIndexCount and nBatchVertexCount are the number of indices and vertices we can fit in this batch
  2623. // Each batch must have fewe than nMaxIndices and nMaxVertices or the material system will fail
  2624. int nBatchIndexCount = MIN( nIndexCount, nMaxIndices );
  2625. int nBatchVertexCount = MIN( nVertexCount, nMaxVertices );
  2626. CMeshBuilder meshBuilder;
  2627. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nBatchVertexCount, nBatchIndexCount );
  2628. int nStartVert = 0;
  2629. for ( g = 0; g < MAX_MAT_SORT_GROUPS; ++g )
  2630. {
  2631. if ( ( flags & ( 1 << g ) ) == 0 )
  2632. continue;
  2633. int nSortGroup = s_DrawWorldListsToSortGroup[g];
  2634. MSL_FOREACH_GROUP_BEGIN(sortList, nSortGroup, group )
  2635. {
  2636. SurfaceHandle_t surfID = sortList.GetSurfaceAtHead(group);
  2637. // Check to see if we can add this list to the current batch...
  2638. if ( ( group.triangleCount == 0 ) || ( group.vertexCount == 0 ) )
  2639. continue;
  2640. IMaterial *pMaterial = MSurf_TexInfo( surfID )->material;
  2641. if( pMaterial->IsAlphaTested() || pMaterial->IsTranslucent() )
  2642. continue;
  2643. MSL_FOREACH_SURFACE_IN_GROUP_BEGIN(sortList, group, nSurfID)
  2644. {
  2645. // Only draw surfaces on nodes (i.e. no detail surfaces)
  2646. // Skip water surfaces since it may move up or down to fixup water transitions.
  2647. if ( ( MSurf_Flags( nSurfID ) & SURFDRAW_NODE ) == 0 || ( MSurf_Flags( nSurfID ) & SURFDRAW_WATERSURFACE ) != 0 )
  2648. continue;
  2649. int nSurfaceVertexCount, nSurfaceIndexCount;
  2650. Shader_GetSurfVertexAndIndexCount( nSurfID, &nSurfaceVertexCount, &nSurfaceIndexCount );
  2651. if ( nSurfaceVertexCount > nMaxVertices || nSurfaceIndexCount > nMaxIndices )
  2652. {
  2653. // Too many vertices/indices in a batch, no simple way to split the batch
  2654. Error( "Too many vertices (%d, max: %d) or indices (%d, max: %d) in surface.\n", nSurfaceVertexCount, nMaxVertices, nSurfaceIndexCount, nMaxIndices );
  2655. continue;
  2656. }
  2657. if ( nBatchIndexCount < nSurfaceIndexCount || nBatchVertexCount < nSurfaceVertexCount )
  2658. {
  2659. // Surface doesn't fit, flush the current batch.
  2660. meshBuilder.End();
  2661. pMesh->Draw();
  2662. nBatchIndexCount = MIN( nIndexCount, nMaxIndices );
  2663. nBatchVertexCount = MIN( nVertexCount, nMaxVertices );
  2664. pMesh = pRenderContext->GetDynamicMesh( false );
  2665. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nBatchVertexCount, nBatchIndexCount );
  2666. nStartVert = 0;
  2667. }
  2668. Shader_WorldZFillSurfChain_Single( nSurfID, meshBuilder, nStartVert );
  2669. nBatchIndexCount -= nSurfaceIndexCount;
  2670. nBatchVertexCount -= nSurfaceVertexCount;
  2671. nIndexCount -= nSurfaceIndexCount;
  2672. nVertexCount -= nSurfaceVertexCount;
  2673. }
  2674. MSL_FOREACH_SURFACE_IN_GROUP_END()
  2675. }
  2676. MSL_FOREACH_GROUP_END()
  2677. }
  2678. meshBuilder.End();
  2679. pMesh->Draw();
  2680. // FIXME: Do fast z reject on displacements!
  2681. }
  2682. extern model_t *g_pSimpleWorldModel;
  2683. extern model_t *g_pSimpleWorldModelWater;
  2684. void DrawSimpleWorldModel( unsigned long flags )
  2685. {
  2686. Assert( ( flags & ( DRAWWORLDLISTS_DRAW_SIMPLE_WORLD_MODEL | DRAWWORLDLISTS_DRAW_SIMPLE_WORLD_MODEL_WATER ) ) != 0 );
  2687. if ( ( ( flags & ( DRAWWORLDLISTS_DRAW_SIMPLE_WORLD_MODEL | DRAWWORLDLISTS_DRAW_SIMPLE_WORLD_MODEL_WATER ) ) == 0 ) )
  2688. {
  2689. return;
  2690. }
  2691. // early out if the models that we are trying to draw don't exist
  2692. if ( !( ( ( flags & DRAWWORLDLISTS_DRAW_SIMPLE_WORLD_MODEL ) && g_pSimpleWorldModel ) ||
  2693. ( ( flags & DRAWWORLDLISTS_DRAW_SIMPLE_WORLD_MODEL_WATER ) && g_pSimpleWorldModelWater ) ) )
  2694. {
  2695. return;
  2696. }
  2697. DrawModelInfo_t info;
  2698. info.m_Decals = STUDIORENDER_DECAL_INVALID;
  2699. info.m_Skin = 0;
  2700. info.m_Body = 0;
  2701. info.m_HitboxSet = 0;
  2702. info.m_pClientEntity = NULL;
  2703. info.m_Lod = 0;
  2704. info.m_pColorMeshes = NULL;
  2705. info.m_bStaticLighting = false;
  2706. info.m_LightingState.m_nLocalLightCount = 0;
  2707. info.m_LightingState.m_vecAmbientCube[0].Init( 1.0f, 1.0f, 1.0f );
  2708. info.m_LightingState.m_vecAmbientCube[1].Init( 1.0f, 1.0f, 1.0f );
  2709. info.m_LightingState.m_vecAmbientCube[2].Init( 1.0f, 1.0f, 1.0f );
  2710. info.m_LightingState.m_vecAmbientCube[3].Init( 1.0f, 1.0f, 1.0f );
  2711. info.m_LightingState.m_vecAmbientCube[4].Init( 1.0f, 1.0f, 1.0f );
  2712. info.m_LightingState.m_vecAmbientCube[5].Init( 1.0f, 1.0f, 1.0f );
  2713. matrix3x4_t modelToWorld;
  2714. modelToWorld.Init( Vector( 0.0f, -1.0f, 0.0f ), Vector( 1.0f, 0.0f, 0.0f ), Vector( 0.0f, 0.0f, 1.0f ), Vector( 0.0f, 0.0f, 0.0f ) );
  2715. CMatRenderContextPtr pRenderContext( materials );
  2716. #if defined( CSTRIKE15 )
  2717. if( !r_skybox_draw_last.GetBool() )
  2718. {
  2719. // Draw the skybox
  2720. if( flags & DRAWWORLDLISTS_DRAW_SKYBOX )
  2721. {
  2722. // [mariod] - leaving this check off as it breaks skybox rendering into reflection texture on some levels, TODO - map fixup?
  2723. // if( Map_VisForceFullSky() )
  2724. {
  2725. if( flags & DRAWWORLDLISTS_DRAW_CLIPSKYBOX )
  2726. {
  2727. R_DrawSkyBox( g_EngineRenderer->GetZFar() );
  2728. }
  2729. else
  2730. {
  2731. // Don't clip the skybox with height clip in this path.
  2732. MaterialHeightClipMode_t nClipMode = pRenderContext->GetHeightClipMode();
  2733. pRenderContext->SetHeightClipMode( MATERIAL_HEIGHTCLIPMODE_DISABLE );
  2734. R_DrawSkyBox( g_EngineRenderer->GetZFar() );
  2735. pRenderContext->SetHeightClipMode( nClipMode );
  2736. }
  2737. }
  2738. }
  2739. }
  2740. #endif
  2741. // Have to save and restore these matrices since DrawModelStaticProp seems to mod them.
  2742. pRenderContext->MatrixMode( MATERIAL_VIEW );
  2743. pRenderContext->PushMatrix();
  2744. pRenderContext->MatrixMode( MATERIAL_MODEL );
  2745. pRenderContext->PushMatrix();
  2746. g_pShadowMgr->PushSinglePassFlashlightStateEnabled( true );
  2747. if ( ( flags & DRAWWORLDLISTS_DRAW_SIMPLE_WORLD_MODEL ) && g_pSimpleWorldModel && !g_pMDLCache->IsErrorModel( g_pSimpleWorldModel->studio ) )
  2748. {
  2749. info.m_pStudioHdr = g_pMDLCache->GetStudioHdr( g_pSimpleWorldModel->studio );
  2750. info.m_pHardwareData = g_pMDLCache->GetHardwareData( g_pSimpleWorldModel->studio );
  2751. g_pStudioRender->DrawModelStaticProp( info, modelToWorld );
  2752. }
  2753. if ( ( flags & DRAWWORLDLISTS_DRAW_SIMPLE_WORLD_MODEL_WATER ) && g_pSimpleWorldModelWater && !g_pMDLCache->IsErrorModel( g_pSimpleWorldModelWater->studio ) )
  2754. {
  2755. info.m_pStudioHdr = g_pMDLCache->GetStudioHdr( g_pSimpleWorldModelWater->studio );
  2756. info.m_pHardwareData = g_pMDLCache->GetHardwareData( g_pSimpleWorldModelWater->studio );
  2757. g_pStudioRender->DrawModelStaticProp( info, modelToWorld );
  2758. }
  2759. g_pShadowMgr->PopSinglePassFlashlightStateEnabled();
  2760. pRenderContext->MatrixMode( MATERIAL_VIEW );
  2761. pRenderContext->PopMatrix();
  2762. pRenderContext->MatrixMode( MATERIAL_MODEL );
  2763. pRenderContext->PopMatrix();
  2764. OverlayMgr()->RenderAllUnlitOverlays( pRenderContext, MAT_SORT_GROUP_STRICTLY_ABOVEWATER );
  2765. #if defined( CSTRIKE15 )
  2766. if( r_skybox_draw_last.GetBool() )
  2767. {
  2768. // Draw the skybox
  2769. if( flags & DRAWWORLDLISTS_DRAW_SKYBOX )
  2770. {
  2771. // [mariod] - leaving this check off as it breaks skybox rendering into reflection texture on some levels, TODO - map fixup?
  2772. // if( Map_VisForceFullSky() )
  2773. {
  2774. if( flags & DRAWWORLDLISTS_DRAW_CLIPSKYBOX )
  2775. {
  2776. R_DrawSkyBox( g_EngineRenderer->GetZFar() );
  2777. }
  2778. else
  2779. {
  2780. // Don't clip the skybox with height clip in this path.
  2781. MaterialHeightClipMode_t nClipMode = pRenderContext->GetHeightClipMode();
  2782. pRenderContext->SetHeightClipMode( MATERIAL_HEIGHTCLIPMODE_DISABLE );
  2783. R_DrawSkyBox( g_EngineRenderer->GetZFar() );
  2784. pRenderContext->SetHeightClipMode( nClipMode );
  2785. }
  2786. }
  2787. }
  2788. }
  2789. #endif
  2790. }
  2791. //-----------------------------------------------------------------------------
  2792. // Call this after lists of stuff to render are made; it renders opaque surfaces
  2793. //-----------------------------------------------------------------------------
  2794. static void Shader_WorldEnd( IMatRenderContext *pRenderContext, CWorldRenderList *pRenderList, unsigned long flags, float waterZAdjust )
  2795. {
  2796. VPROF("Shader_WorldEnd");
  2797. if ( flags & ( DRAWWORLDLISTS_DRAW_SHADOWDEPTH | DRAWWORLDLISTS_DRAW_SSAO ) )
  2798. {
  2799. // NOTE: Implementations appear to want to be different on the PC + 360 here
  2800. if ( IsX360() )
  2801. {
  2802. Shader_WorldShadowDepthFillX360( pRenderContext, pRenderList, flags );
  2803. }
  2804. else if ( r_csm_fast_path.GetBool() )
  2805. {
  2806. Shader_WorldShadowDepthFillFast( pRenderContext, pRenderList, flags );
  2807. }
  2808. else
  2809. {
  2810. Shader_WorldShadowDepthFill( pRenderContext, pRenderList, flags );
  2811. }
  2812. return;
  2813. }
  2814. if ( !r_skybox_draw_last.GetBool() )
  2815. {
  2816. // Draw the skybox
  2817. if ( flags & DRAWWORLDLISTS_DRAW_SKYBOX )
  2818. {
  2819. if ( pRenderList->m_bSkyVisible || Map_VisForceFullSky() )
  2820. {
  2821. if( flags & DRAWWORLDLISTS_DRAW_CLIPSKYBOX )
  2822. {
  2823. R_DrawSkyBox( g_EngineRenderer->GetZFar() );
  2824. }
  2825. else
  2826. {
  2827. // Don't clip the skybox with height clip in this path.
  2828. MaterialHeightClipMode_t nClipMode = pRenderContext->GetHeightClipMode();
  2829. pRenderContext->SetHeightClipMode( MATERIAL_HEIGHTCLIPMODE_DISABLE );
  2830. R_DrawSkyBox( g_EngineRenderer->GetZFar() );
  2831. pRenderContext->SetHeightClipMode( nClipMode );
  2832. }
  2833. }
  2834. }
  2835. }
  2836. if ( !IsGameConsole() )
  2837. {
  2838. // X360 and PS3 now use a different fast z-reject pass (PS3 emulates X360 behavior)
  2839. // Perform the fast z-fill pass
  2840. bool bFastZReject = (r_fastzreject.GetInt() != 0);
  2841. if ( bFastZReject )
  2842. {
  2843. Shader_WorldZFill( pRenderContext, pRenderList, flags );
  2844. }
  2845. }
  2846. // Gotta draw each sort group
  2847. // Draw the fog volume first, if there is one, because it turns out
  2848. // that we only draw fog volumes if we're in the fog volume, which
  2849. // means it's closer. We want to render closer things first to get
  2850. // fast z-reject.
  2851. int i;
  2852. for ( i = MAX_MAT_SORT_GROUPS; --i >= 0; )
  2853. {
  2854. if ( !( flags & ( 1 << i ) ) )
  2855. continue;
  2856. PIXEVENT( pRenderContext, s_pMatSortGroupsString[ i ] );
  2857. int nSortGroup = s_DrawWorldListsToSortGroup[i];
  2858. if ( nSortGroup == MAT_SORT_GROUP_WATERSURFACE )
  2859. {
  2860. if ( waterZAdjust != 0.0f )
  2861. {
  2862. pRenderContext->MatrixMode( MATERIAL_MODEL );
  2863. pRenderContext->PushMatrix();
  2864. pRenderContext->LoadIdentity();
  2865. pRenderContext->Translate( 0.0f, 0.0f, waterZAdjust );
  2866. }
  2867. g_pShadowMgr->PushSinglePassFlashlightStateEnabled( true );
  2868. }
  2869. // Don't stencil or scissor the flashlight if we're rendering to an offscreen view
  2870. bool bFlashlightMask = !( (flags & DRAWWORLDLISTS_DRAW_REFRACTION ) || (flags & DRAWWORLDLISTS_DRAW_REFLECTION ));
  2871. // Set masking stencil bits for flashlights
  2872. g_pShadowMgr->SetFlashlightStencilMasks( bFlashlightMask );
  2873. // Draws opaque displacement surfaces along with shadows, overlays, flashlights, etc.
  2874. Shader_DrawDispChain( pRenderContext, nSortGroup, pRenderList->m_DispSortList, flags, DEPTH_MODE_NORMAL );
  2875. // Draws opaque non-displacement surfaces
  2876. // This also add shadows to pRenderList->m_ShadowHandles.
  2877. Shader_DrawChains( pRenderContext, pRenderList, nSortGroup, DEPTH_MODE_NORMAL );
  2878. if ( nSortGroup == MAT_SORT_GROUP_WATERSURFACE )
  2879. {
  2880. g_pShadowMgr->PopSinglePassFlashlightStateEnabled();
  2881. if ( waterZAdjust != 0.0f )
  2882. {
  2883. pRenderContext->MatrixMode( MATERIAL_MODEL );
  2884. pRenderContext->PopMatrix();
  2885. }
  2886. }
  2887. }
  2888. if ( r_skybox_draw_last.GetBool() )
  2889. {
  2890. // Draw the skybox
  2891. if ( flags & DRAWWORLDLISTS_DRAW_SKYBOX )
  2892. {
  2893. if ( pRenderList->m_bSkyVisible || Map_VisForceFullSky() )
  2894. {
  2895. if( flags & DRAWWORLDLISTS_DRAW_CLIPSKYBOX )
  2896. {
  2897. R_DrawSkyBox( g_EngineRenderer->GetZFar() );
  2898. }
  2899. else
  2900. {
  2901. // Don't clip the skybox with height clip in this path.
  2902. MaterialHeightClipMode_t nClipMode = pRenderContext->GetHeightClipMode();
  2903. pRenderContext->SetHeightClipMode( MATERIAL_HEIGHTCLIPMODE_DISABLE );
  2904. R_DrawSkyBox( g_EngineRenderer->GetZFar() );
  2905. pRenderContext->SetHeightClipMode( nClipMode );
  2906. }
  2907. }
  2908. }
  2909. }
  2910. }
  2911. //-----------------------------------------------------------------------------
  2912. // Call this after lists of stuff to render are made; it renders opaque surfaces
  2913. //-----------------------------------------------------------------------------
  2914. static void Shader_DrawWorldDecalsAndOverlays( IMatRenderContext *pRenderContext, CWorldRenderList *pRenderList, unsigned long flags, float waterZAdjust )
  2915. {
  2916. // Gotta draw each sort group
  2917. // Draw the fog volume first, if there is one, because it turns out
  2918. // that we only draw fog volumes if we're in the fog volume, which
  2919. // means it's closer. We want to render closer things first to get
  2920. // fast z-reject.
  2921. int i;
  2922. for ( i = MAX_MAT_SORT_GROUPS; --i >= 0; )
  2923. {
  2924. if ( !( flags & ( 1 << i ) ) )
  2925. continue;
  2926. PIXEVENT( pRenderContext, s_pMatSortGroupsString[ i ] );
  2927. int nSortGroup = s_DrawWorldListsToSortGroup[i];
  2928. if ( nSortGroup == MAT_SORT_GROUP_WATERSURFACE )
  2929. {
  2930. if ( waterZAdjust != 0.0f )
  2931. {
  2932. pRenderContext->MatrixMode( MATERIAL_MODEL );
  2933. pRenderContext->PushMatrix();
  2934. pRenderContext->LoadIdentity();
  2935. pRenderContext->Translate( 0.0f, 0.0f, waterZAdjust );
  2936. }
  2937. }
  2938. // FIXME: Implement this
  2939. // Draws opaque displacement surfaces along with shadows, overlays, flashlights, etc.
  2940. Shader_DrawDispChainDecalsAndOverlays( pRenderContext, nSortGroup, pRenderList->m_DispSortList, flags );
  2941. AddProjectedTextureDecalsToList( pRenderList, nSortGroup );
  2942. // Adds shadows to render lists
  2943. for ( int j = pRenderList->m_ShadowHandles[nSortGroup].Count()-1; j >= 0; --j )
  2944. {
  2945. g_pShadowMgr->AddShadowsOnSurfaceToRenderList( pRenderList->m_ShadowHandles[nSortGroup].Element(j) );
  2946. }
  2947. pRenderList->m_ShadowHandles[nSortGroup].RemoveAll();
  2948. // Don't stencil or scissor the flashlight if we're rendering to an offscreen view
  2949. bool bFlashlightMask = !( (flags & DRAWWORLDLISTS_DRAW_REFRACTION ) || (flags & DRAWWORLDLISTS_DRAW_REFLECTION ));
  2950. // Set masking stencil bits for flashlights
  2951. g_pShadowMgr->SetFlashlightStencilMasks( bFlashlightMask );
  2952. // Draw shadows and flashlights on world surfaces
  2953. g_pShadowMgr->RenderFlashlights( bFlashlightMask, false );
  2954. // Render the fragments from the surfaces + displacements.
  2955. // FIXME: Actually, this call is irrelevant (for displacements) because it's done from
  2956. // within DrawDispChain currently, but that should change.
  2957. // We need to split out the disp decal rendering from DrawDispChain
  2958. // and do it after overlays are rendered....
  2959. OverlayMgr()->RenderOverlays( pRenderContext, nSortGroup );
  2960. g_pShadowMgr->DrawFlashlightOverlays( pRenderContext, nSortGroup, bFlashlightMask );
  2961. OverlayMgr()->ClearRenderLists( nSortGroup );
  2962. // Draws decals lying on opaque non-displacement surfaces
  2963. DecalSurfaceDraw( pRenderContext, nSortGroup );
  2964. // Draw the flashlight lighting for the decals.
  2965. g_pShadowMgr->DrawFlashlightDecals( pRenderContext, nSortGroup, bFlashlightMask );
  2966. g_pShadowMgr->RenderFlashlights( bFlashlightMask, true );
  2967. // Retire decals on opaque world surfaces
  2968. R_DecalFlushDestroyList();
  2969. // Draw RTT shadows
  2970. g_pShadowMgr->RenderShadows( pRenderContext );
  2971. g_pShadowMgr->ClearShadowRenderList();
  2972. if ( nSortGroup == MAT_SORT_GROUP_WATERSURFACE && waterZAdjust != 0.0f )
  2973. {
  2974. pRenderContext->MatrixMode( MATERIAL_MODEL );
  2975. pRenderContext->PopMatrix();
  2976. }
  2977. }
  2978. }
  2979. //-----------------------------------------------------------------------------
  2980. // Renders translucent surfaces
  2981. //-----------------------------------------------------------------------------
  2982. bool Shader_LeafContainsTranslucentSurfaces( IWorldRenderList *pRenderListIn, int sortIndex, unsigned long flags )
  2983. {
  2984. CWorldRenderList *pRenderList = assert_cast<CWorldRenderList *>(pRenderListIn);
  2985. if ( pRenderList->m_leaves[sortIndex].translucentSurfaceCount > 0 )
  2986. {
  2987. return true;
  2988. }
  2989. return false;
  2990. }
  2991. struct transsurfacebatch_t
  2992. {
  2993. int firstSurface;
  2994. int surfaceCount;
  2995. IMaterial *pMaterial;
  2996. int sortID;
  2997. int triangleCount;
  2998. void AddSurface( SurfaceHandle_t surfID )
  2999. {
  3000. surfaceCount++;
  3001. triangleCount += (MSurf_VertCount( surfID )-2);
  3002. }
  3003. };
  3004. void Shader_DrawTranslucentSurfaces( IMatRenderContext *pRenderContext, IWorldRenderList *pRenderListIn, int *pSortList, int sortCount, unsigned long flags )
  3005. {
  3006. if ( !r_drawtranslucentworld.GetBool() )
  3007. return;
  3008. CWorldRenderList *pRenderList = assert_cast<CWorldRenderList *>(pRenderListIn);
  3009. bool skipLight = false;
  3010. if ( g_pMaterialSystemConfig->nFullbright == 1 )
  3011. {
  3012. pRenderContext->BindLightmapPage( MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP );
  3013. skipLight = true;
  3014. }
  3015. CUtlVectorFixedGrowable<msurface2_t *, 16> surfaceList;
  3016. CUtlVectorFixedGrowable<msurface2_t *, 16> decalSurfaceList;
  3017. CUtlVectorFixedGrowable<msurface2_t *, 16> flashlightSurfaceList;
  3018. CUtlVectorFixedGrowable<msurface2_t *, 16> dispList;
  3019. CUtlVectorFixedGrowable<transsurfacebatch_t,16> batches;
  3020. transsurfacebatch_t *pLastBatch = NULL;
  3021. bool bFlashlightMask = !( (flags & DRAWWORLDLISTS_DRAW_REFRACTION ) || (flags & DRAWWORLDLISTS_DRAW_REFLECTION ));
  3022. bool bHasDisp = false;
  3023. for ( int i = 0, mask = 1; i < MAX_MAT_SORT_GROUPS; i++, mask<<=1 )
  3024. {
  3025. if ( !(flags & mask) )
  3026. continue;
  3027. for ( int leaf = 0; leaf < sortCount; leaf++ )
  3028. {
  3029. int sortIndex = pSortList[leaf];
  3030. int surfaceIndexStart = pRenderList->m_leaves[sortIndex].firstTranslucentSurface;
  3031. int nextTranslucentSurface = surfaceIndexStart + pRenderList->m_leaves[sortIndex].translucentSurfaceCount;
  3032. for ( int si = nextTranslucentSurface-1; si >= surfaceIndexStart; --si )
  3033. {
  3034. int sortGroup = MSurf_SortGroup(pRenderList->m_AlphaSurfaces[si]);
  3035. if ( sortGroup != i )
  3036. continue;
  3037. SurfaceHandle_t surfID = pRenderList->m_AlphaSurfaces[si];
  3038. if ( surfID->pDispInfo )
  3039. {
  3040. bHasDisp = true;
  3041. }
  3042. else
  3043. {
  3044. int sortID = MSurf_MaterialSortID(surfID);
  3045. if ( !pLastBatch || sortID != pLastBatch->sortID )
  3046. {
  3047. int batchIndex = batches.AddToTail();
  3048. pLastBatch = &batches[batchIndex];
  3049. pLastBatch->firstSurface = surfaceList.Count();
  3050. pLastBatch->surfaceCount = 0;
  3051. pLastBatch->pMaterial = MSurf_TexInfo( surfID )->material;
  3052. pLastBatch->sortID = sortID;
  3053. pLastBatch->triangleCount = 0;
  3054. }
  3055. pLastBatch->AddSurface( surfID );
  3056. surfaceList.AddToTail(surfID);
  3057. if ( MSurf_ShadowDecals(surfID) != SHADOW_DECAL_HANDLE_INVALID )
  3058. {
  3059. flashlightSurfaceList.AddToTail(surfID);
  3060. }
  3061. if ( SurfaceHasDecals(surfID) || MSurf_OverlayFragmentList(surfID) != OVERLAY_FRAGMENT_INVALID )
  3062. {
  3063. decalSurfaceList.AddToTail(surfID);
  3064. }
  3065. }
  3066. }
  3067. }
  3068. }
  3069. for ( int i = 0; i < batches.Count(); i++ )
  3070. {
  3071. transsurfacebatch_t *pBatch = &batches[i];
  3072. SurfaceHandle_t surfID = surfaceList[pBatch->firstSurface];
  3073. pRenderContext->Bind( MSurf_TexInfo( surfID )->material );
  3074. Assert( MSurf_MaterialSortID( surfID ) >= 0 && MSurf_MaterialSortID( surfID ) < g_WorldStaticMeshes.Count() );
  3075. if ( !skipLight )
  3076. {
  3077. int nLightmapPageId = materialSortInfoArray[MSurf_MaterialSortID( surfID )].lightmapPageID;
  3078. pRenderContext->BindLightmapPage( nLightmapPageId );
  3079. }
  3080. Shader_DrawSurfaceListStatic( pRenderContext, &surfaceList[pBatch->firstSurface], pBatch->surfaceCount, pBatch->triangleCount );
  3081. }
  3082. for ( int i = 0; i < decalSurfaceList.Count(); i++ )
  3083. {
  3084. SurfaceHandle_t surfID = decalSurfaceList[i];
  3085. int sortGroup = MSurf_SortGroup(surfID);
  3086. if ( MSurf_OverlayFragmentList(surfID) != OVERLAY_FRAGMENT_INVALID )
  3087. {
  3088. // Draw overlays on the surface.
  3089. OverlayMgr()->AddFragmentListToRenderList( sortGroup, MSurf_OverlayFragmentList( surfID ), false );
  3090. OverlayMgr()->RenderOverlays( pRenderContext, sortGroup );
  3091. // Draw flashlight overlays
  3092. g_pShadowMgr->DrawFlashlightOverlays( pRenderContext, sortGroup, bFlashlightMask );
  3093. OverlayMgr()->ClearRenderLists( sortGroup );
  3094. }
  3095. // Draw decals on the surface
  3096. if ( SurfaceHasDecals(surfID) )
  3097. {
  3098. DrawDecalsOnSingleSurface( pRenderContext, surfID );
  3099. }
  3100. }
  3101. if ( flashlightSurfaceList.Count() )
  3102. {
  3103. for ( int i = 0; i < flashlightSurfaceList.Count(); i++ )
  3104. {
  3105. SurfaceHandle_t surfID = flashlightSurfaceList[i];
  3106. ShadowDecalHandle_t decalHandle = MSurf_ShadowDecals( surfID );
  3107. if (decalHandle != SHADOW_DECAL_HANDLE_INVALID)
  3108. {
  3109. g_pShadowMgr->AddShadowsOnSurfaceToRenderList( decalHandle );
  3110. }
  3111. }
  3112. g_pShadowMgr->RenderFlashlights( bFlashlightMask, false );
  3113. if ( decalSurfaceList.Count() )
  3114. {
  3115. g_pShadowMgr->DrawFlashlightDecalsOnSurfaceList( pRenderContext, flashlightSurfaceList.Base(), flashlightSurfaceList.Count(), bFlashlightMask );
  3116. }
  3117. // draw shadows
  3118. g_pShadowMgr->RenderShadows( pRenderContext );
  3119. g_pShadowMgr->ClearShadowRenderList();
  3120. }
  3121. // Draw wireframe, etc information
  3122. DrawDebugInformation( pRenderContext, surfaceList.Base(), surfaceList.Count() );
  3123. if ( bHasDisp )
  3124. {
  3125. for ( int i = 0, mask = 1; i < MAX_MAT_SORT_GROUPS; i++, mask<<=1 )
  3126. {
  3127. if ( !(flags & mask) )
  3128. continue;
  3129. for ( int leaf = 0; leaf < sortCount; leaf++ )
  3130. {
  3131. int sortIndex = pSortList[leaf];
  3132. int surfaceIndexStart = pRenderList->m_leaves[sortIndex].firstTranslucentSurface;
  3133. int nextTranslucentSurface = surfaceIndexStart + pRenderList->m_leaves[sortIndex].translucentSurfaceCount;
  3134. dispList.RemoveAll();
  3135. for ( int si = nextTranslucentSurface-1; si >= surfaceIndexStart; --si )
  3136. {
  3137. int sortGroup = MSurf_SortGroup(pRenderList->m_AlphaSurfaces[si]);
  3138. if ( sortGroup != i )
  3139. continue;
  3140. SurfaceHandle_t surfID = pRenderList->m_AlphaSurfaces[si];
  3141. if ( surfID->pDispInfo )
  3142. {
  3143. dispList.AddToTail(surfID);
  3144. }
  3145. }
  3146. if ( dispList.Count() )
  3147. {
  3148. // Now draw the translucent displacements; we need to do these *after* the
  3149. // non-displacement surfaces because most likely the displacement will always
  3150. // be in front (or at least not behind) the non-displacement translucent surfaces
  3151. // that exist in the same leaf.
  3152. // Draws translucent displacement surfaces
  3153. DispInfo_RenderListWorld( pRenderContext, i, dispList.Base(), dispList.Count(), g_EngineRenderer->ViewGetCurrent().m_bOrtho, flags, DEPTH_MODE_NORMAL );
  3154. DispInfo_RenderListDecalsAndOverlays( pRenderContext, i, dispList.Base(), dispList.Count(), g_EngineRenderer->ViewGetCurrent().m_bOrtho, flags );
  3155. }
  3156. }
  3157. }
  3158. }
  3159. }
  3160. //=============================================================
  3161. //
  3162. // WORLD MODEL
  3163. //
  3164. //=============================================================
  3165. #if !defined(_PS3)
  3166. static void FASTCALL R_DrawSurface( CWorldRenderList *pRenderList, SurfaceHandle_t surfID )
  3167. {
  3168. ASSERT_SURF_VALID( surfID );
  3169. Assert( !SurfaceHasDispInfo( surfID ) );
  3170. if ( MSurf_Flags( surfID ) & SURFDRAW_SKY )
  3171. {
  3172. pRenderList->m_bSkyVisible = true;
  3173. }
  3174. else if( MSurf_Flags( surfID ) & SURFDRAW_TRANS )
  3175. {
  3176. Shader_TranslucentWorldSurface( pRenderList, surfID );
  3177. }
  3178. else
  3179. {
  3180. Shader_WorldSurface( pRenderList, surfID );
  3181. }
  3182. }
  3183. #endif
  3184. //-----------------------------------------------------------------------------
  3185. // Draws displacements in a leaf
  3186. //-----------------------------------------------------------------------------
  3187. #if !defined(_PS3)
  3188. static inline void DrawDisplacementsInLeaf( CWorldRenderList *pRenderList, mleaf_t* pLeaf )
  3189. {
  3190. // add displacement surfaces
  3191. if (!pLeaf->dispCount)
  3192. return;
  3193. CVisitedSurfs &visitedSurfs = pRenderList->m_VisitedSurfs;
  3194. for ( int i = 0; i < pLeaf->dispCount; i++ )
  3195. {
  3196. CDispInfo *pDispInfo = static_cast<CDispInfo *>(MLeaf_Disaplcement( pLeaf, i ));
  3197. // NOTE: We're not using the displacement's touched method here
  3198. // because we're just using the parent surface's visframe in the
  3199. // surface add methods below...
  3200. SurfaceHandle_t parentSurfID = pDispInfo->m_ParentSurfID;
  3201. // already processed this frame? Then don't do it again!
  3202. if ( visitedSurfs.VisitSurface( parentSurfID ) )
  3203. {
  3204. if ( g_Frustum.CullBox( pDispInfo->m_BBoxMin, pDispInfo->m_BBoxMax ) )
  3205. continue;
  3206. if ( MSurf_Flags( parentSurfID ) & SURFDRAW_TRANS)
  3207. {
  3208. Shader_TranslucentDisplacementSurface( pRenderList, parentSurfID );
  3209. }
  3210. else
  3211. {
  3212. Shader_DisplacementSurface( pRenderList, parentSurfID );
  3213. }
  3214. }
  3215. }
  3216. }
  3217. #else
  3218. static uint32 s_Disp_ParentSurfID_offset;
  3219. static uint32 s_Disp_BB_offset;
  3220. inline void MLeaf_Displacement_BBs( mleaf_t *pLeaf, int index, Vector* pBBoxMin, Vector* pBBoxMax, SurfaceHandle_t *pParentSurfID)
  3221. {
  3222. int dispIndex = host_state.worldbrush->m_pDispInfoReferences[pLeaf->dispListStart+index];
  3223. CDispArray *pArray = static_cast<CDispArray*>( host_state.worldbrush->hDispInfos );
  3224. uint8* pInfo = (uint8*)(pArray->m_pDispInfos + dispIndex );
  3225. *pParentSurfID = *((SurfaceHandle_t*)(pInfo + s_Disp_ParentSurfID_offset));
  3226. Vector* pSrcVector = (Vector*)(pInfo + s_Disp_BB_offset);
  3227. *pBBoxMin = pSrcVector[0];
  3228. *pBBoxMax = pSrcVector[1];
  3229. }
  3230. #define GET_OFFSET(type, field) ((uint32)&(((type *)0)->field))
  3231. static inline void DrawDisplacementsInLeaf( CWorldRenderList *pRenderList, mleaf_t* pLeaf )
  3232. {
  3233. // add displacement surfaces
  3234. if (!pLeaf->dispCount)
  3235. return;
  3236. s_Disp_ParentSurfID_offset = GET_OFFSET(CDispInfo, m_ParentSurfID);
  3237. s_Disp_BB_offset = GET_OFFSET(CDispInfo, m_BBoxMin);
  3238. CVisitedSurfs &visitedSurfs = pRenderList->m_VisitedSurfs;
  3239. for ( int i = 0; i < pLeaf->dispCount; i++ )
  3240. {
  3241. // CDispInfo *pDispInfo = static_cast<CDispInfo *>(MLeaf_Disaplcement( pLeaf, i ));
  3242. //
  3243. SurfaceHandle_t parentSurfID;
  3244. Vector bbMin;
  3245. Vector bbMax;
  3246. MLeaf_Displacement_BBs(pLeaf, i, &bbMin, &bbMax, &parentSurfID);
  3247. // if (bbMin != pDispInfo->m_BBoxMin) DebuggerBreak();
  3248. // if (bbMax != pDispInfo->m_BBoxMax) DebuggerBreak();
  3249. // if (parentSurfID != pDispInfo->m_ParentSurfID) DebuggerBreak();
  3250. // NOTE: We're not using the displacement's touched method here
  3251. // because we're just using the parent surface's visframe in the
  3252. // surface add methods below...
  3253. // already processed this frame? Then don't do it again!
  3254. if ( visitedSurfs.VisitSurface( parentSurfID ) )
  3255. {
  3256. if ( g_Frustum.CullBox( bbMin, bbMax ) )
  3257. continue;
  3258. if ( MSurf_Flags( parentSurfID ) & SURFDRAW_TRANS)
  3259. {
  3260. Shader_TranslucentDisplacementSurface( pRenderList, parentSurfID );
  3261. }
  3262. else
  3263. {
  3264. Shader_DisplacementSurface( pRenderList, parentSurfID );
  3265. }
  3266. }
  3267. }
  3268. }
  3269. #endif
  3270. int LeafToIndex( mleaf_t* pLeaf );
  3271. //-----------------------------------------------------------------------------
  3272. // Updates visibility + alpha lists
  3273. //-----------------------------------------------------------------------------
  3274. static inline void UpdateVisibleLeafLists( CWorldRenderList *pRenderList, mleaf_t* pLeaf )
  3275. {
  3276. // Consistency check...
  3277. MEM_ALLOC_CREDIT();
  3278. // Add this leaf to the list of visible leafs
  3279. int nLeafIndex = LeafToIndex( pLeaf );
  3280. WorldListLeafData_t * RESTRICT pData = &pRenderList->m_leaves[pRenderList->m_leaves.AddToTail()];
  3281. pData->leafIndex = nLeafIndex;
  3282. pData->waterData = pLeaf->leafWaterDataID;
  3283. pData->firstTranslucentSurface = pRenderList->m_AlphaSurfaces.Count();
  3284. pData->translucentSurfaceCount = 0;
  3285. if ( pLeaf->leafWaterDataID != -1 )
  3286. {
  3287. pRenderList->m_bWaterVisible = true;
  3288. }
  3289. }
  3290. static ConVar r_frustumcullworld( "r_frustumcullworld", "1" );
  3291. //-----------------------------------------------------------------------------
  3292. // Set up fog for a particular leaf
  3293. //-----------------------------------------------------------------------------
  3294. #define INVALID_WATER_HEIGHT 1000000.0f
  3295. static inline float R_GetWaterHeight( int nFogVolume )
  3296. {
  3297. if( nFogVolume < 0 || nFogVolume > host_state.worldbrush->numleafwaterdata )
  3298. return INVALID_WATER_HEIGHT;
  3299. mleafwaterdata_t* pLeafWaterData = &host_state.worldbrush->leafwaterdata[nFogVolume];
  3300. return pLeafWaterData->surfaceZ;
  3301. }
  3302. IMaterial *R_GetFogVolumeMaterial( int nFogVolume, bool bEyeInFogVolume )
  3303. {
  3304. if( nFogVolume < 0 || nFogVolume > host_state.worldbrush->numleafwaterdata )
  3305. return NULL;
  3306. mleafwaterdata_t* pLeafWaterData = &host_state.worldbrush->leafwaterdata[nFogVolume];
  3307. mtexinfo_t* pTexInfo = &host_state.worldbrush->texinfo[pLeafWaterData->surfaceTexInfoID];
  3308. IMaterial* pMaterial = pTexInfo->material;
  3309. if( bEyeInFogVolume )
  3310. {
  3311. IMaterialVar *pVar = pMaterial->FindVar( "$bottommaterial", NULL );
  3312. if( pVar )
  3313. {
  3314. const char *pMaterialName = pVar->GetStringValue();
  3315. if( pMaterialName )
  3316. {
  3317. pMaterial = materials->FindMaterial( pMaterialName, TEXTURE_GROUP_OTHER );
  3318. }
  3319. }
  3320. }
  3321. return pMaterial;
  3322. }
  3323. void R_SetFogVolumeState( int fogVolume, bool useHeightFog )
  3324. {
  3325. // useHeightFog == eye out of water
  3326. // !useHeightFog == eye in water
  3327. IMaterial *pMaterial = R_GetFogVolumeMaterial( fogVolume, !useHeightFog );
  3328. mleafwaterdata_t* pLeafWaterData = &host_state.worldbrush->leafwaterdata[fogVolume];
  3329. IMaterialVar* pFogColorVar = pMaterial->FindVar( "$fogcolor", NULL );
  3330. IMaterialVar* pFogEnableVar = pMaterial->FindVar( "$fogenable", NULL );
  3331. IMaterialVar* pFogStartVar = pMaterial->FindVar( "$fogstart", NULL );
  3332. IMaterialVar* pFogEndVar = pMaterial->FindVar( "$fogend", NULL );
  3333. CMatRenderContextPtr pRenderContext( materials );
  3334. if( pMaterial && pFogEnableVar->GetIntValueFast() && fog_enable_water_fog.GetBool() )
  3335. {
  3336. pRenderContext->SetFogZ( pLeafWaterData->surfaceZ );
  3337. if( useHeightFog )
  3338. {
  3339. pRenderContext->FogMode( MATERIAL_FOG_LINEAR_BELOW_FOG_Z );
  3340. }
  3341. else
  3342. {
  3343. pRenderContext->FogMode( MATERIAL_FOG_LINEAR );
  3344. }
  3345. float fogColor[3];
  3346. pFogColorVar->GetVecValueFast( fogColor, 3 );
  3347. pRenderContext->FogColor3fv( fogColor );
  3348. pRenderContext->FogStart( pFogStartVar->GetFloatValueFast() );
  3349. pRenderContext->FogEnd( pFogEndVar->GetFloatValueFast() );
  3350. pRenderContext->FogMaxDensity( 1.0 );
  3351. }
  3352. else
  3353. {
  3354. pRenderContext->FogMode( MATERIAL_FOG_NONE );
  3355. }
  3356. }
  3357. //-----------------------------------------------------------------------------
  3358. // Job for building the world rendering list
  3359. //-----------------------------------------------------------------------------
  3360. class CBuildWorldListsJob : public CJob
  3361. {
  3362. public:
  3363. CBuildWorldListsJob(
  3364. CWorldRenderList *pRenderList,
  3365. WorldListInfo_t* pInfo,
  3366. bool bShadowDepth,
  3367. const Vector& currentViewOrigin,
  3368. int visFrameCount,
  3369. bool bDrawTopView,
  3370. bool bTopViewNoBackfaceCulling,
  3371. bool bTopViewNoVisCheck,
  3372. const Vector2D& orthographicCenter,
  3373. const Vector2D& orthographicHalfDiagonal,
  3374. const CVolumeCuller* pTopViewVolumeCuller,
  3375. const Frustum_t* pFrustum,
  3376. const CUtlVector< Frustum_t, CUtlMemoryAligned< Frustum_t,16 > >* pAeraFrustum,
  3377. unsigned char* pRenderAreaBits,
  3378. bool bViewerInSolidSpace,
  3379. const Vector& modelOrigin );
  3380. private:
  3381. virtual JobStatus_t DoExecute();
  3382. void R_RecursiveWorldNode( CWorldRenderList *pRenderList, mnode_t *node );
  3383. // Fast path for rendering top-views
  3384. void R_RenderWorldTopView( CWorldRenderList *pRenderList, mnode_t *node );
  3385. void R_BuildWorldListNoCull( CWorldRenderList *pRenderList, mnode_t *node );
  3386. inline bool R_CullNode( mnode_t *pNode );
  3387. inline bool R_CullNodeTopView( mnode_t *pNode );
  3388. void R_DrawLeaf( CWorldRenderList *pRenderList, mleaf_t *pleaf );
  3389. void R_DrawTopViewLeaf( CWorldRenderList *pRenderList, mleaf_t *pleaf );
  3390. void R_DrawLeafNoCull( CWorldRenderList *pRenderList, mleaf_t *pleaf );
  3391. void R_DrawSurfaceNoCull( CWorldRenderList *pRenderList, SurfaceHandle_t surfID );
  3392. void DrawDisplacementsInLeaf( CWorldRenderList *pRenderList, mleaf_t* pLeaf );
  3393. void Shader_WorldSurface( CWorldRenderList *pRenderList, SurfaceHandle_t surfID );
  3394. void Shader_WorldSurfaceNoCull( CWorldRenderList *pRenderList, SurfaceHandle_t surfID );
  3395. CWorldRenderList* m_pRenderList;
  3396. WorldListInfo_t* m_pWorldListInfo;
  3397. bool m_bShadowDepth;
  3398. Vector m_currentViewOrigin;
  3399. int m_visFrameCount;
  3400. bool m_bDrawTopView;
  3401. bool m_bTopViewNoBackfaceCulling;
  3402. bool m_bTopViewNoVisCheck;
  3403. Vector2D m_OrthographicCenter;
  3404. Vector2D m_OrthographicHalfDiagonal;
  3405. const CVolumeCuller* m_pTopViewVolumeCuller; // No need to copy the data as it is
  3406. // already cached in CConcurrentViewBuilder volume culler cache
  3407. const Frustum_t* m_pFrustum;
  3408. const CUtlVector< Frustum_t, CUtlMemoryAligned< Frustum_t,16 > >* m_pAreaFrustum;
  3409. unsigned char m_RenderAreaBits[32];
  3410. bool m_bViewerInSolidSpace;
  3411. Vector m_modelOrigin;
  3412. };
  3413. CBuildWorldListsJob::CBuildWorldListsJob(
  3414. CWorldRenderList *pRenderList,
  3415. WorldListInfo_t* pInfo,
  3416. bool bShadowDepth,
  3417. const Vector& currentViewOrigin,
  3418. int visFrameCount,
  3419. bool bDrawTopView,
  3420. bool bTopViewNoBackfaceCulling,
  3421. bool bTopViewNoVisCheck,
  3422. const Vector2D& orthographicCenter,
  3423. const Vector2D& orthographicHalfDiagonal,
  3424. const CVolumeCuller* pTopViewVolumeCuller,
  3425. const Frustum_t* pFrustum,
  3426. const CUtlVector< Frustum_t, CUtlMemoryAligned< Frustum_t,16 > >* pAeraFrustum,
  3427. unsigned char* pRenderAreaBits,
  3428. bool bViewerInSolidSpace,
  3429. const Vector& modelOrigin )
  3430. :
  3431. m_pRenderList( pRenderList ),
  3432. m_pWorldListInfo( pInfo ),
  3433. m_bShadowDepth( bShadowDepth ),
  3434. m_currentViewOrigin( currentViewOrigin ),
  3435. m_visFrameCount(visFrameCount),
  3436. m_bDrawTopView( bDrawTopView ),
  3437. m_bTopViewNoBackfaceCulling( bTopViewNoBackfaceCulling ),
  3438. m_bTopViewNoVisCheck( bTopViewNoVisCheck ),
  3439. m_OrthographicCenter( orthographicCenter ),
  3440. m_OrthographicHalfDiagonal( orthographicHalfDiagonal ),
  3441. m_pTopViewVolumeCuller( pTopViewVolumeCuller ),
  3442. m_pFrustum( pFrustum ),
  3443. m_bViewerInSolidSpace( bViewerInSolidSpace ),
  3444. m_modelOrigin( modelOrigin )
  3445. {
  3446. m_pAreaFrustum = pAeraFrustum;
  3447. memcpy( m_RenderAreaBits, pRenderAreaBits, sizeof(m_RenderAreaBits) );
  3448. }
  3449. JobStatus_t CBuildWorldListsJob::DoExecute()
  3450. {
  3451. if ( !m_bDrawTopView )
  3452. {
  3453. if ( m_bShadowDepth )
  3454. {
  3455. R_BuildWorldListNoCull( m_pRenderList, host_state.worldbrush->nodes );
  3456. }
  3457. else
  3458. {
  3459. R_RecursiveWorldNode( m_pRenderList, host_state.worldbrush->nodes );
  3460. }
  3461. }
  3462. else
  3463. {
  3464. R_RenderWorldTopView( m_pRenderList, host_state.worldbrush->nodes );
  3465. }
  3466. m_pRenderList->CountTranslucentSurfaces();
  3467. // Return the back-to-front leaf ordering
  3468. if ( m_pWorldListInfo )
  3469. {
  3470. // Compute fog volume info for rendering
  3471. if ( !m_bShadowDepth )
  3472. {
  3473. FogVolumeInfo_t fogInfo;
  3474. ComputeFogVolumeInfo( &fogInfo, m_currentViewOrigin );
  3475. if( fogInfo.m_InFogVolume )
  3476. {
  3477. m_pWorldListInfo->m_ViewFogVolume = MAT_SORT_GROUP_STRICTLY_UNDERWATER;
  3478. }
  3479. else
  3480. {
  3481. m_pWorldListInfo->m_ViewFogVolume = MAT_SORT_GROUP_STRICTLY_ABOVEWATER;
  3482. }
  3483. }
  3484. else
  3485. {
  3486. m_pWorldListInfo->m_ViewFogVolume = MAT_SORT_GROUP_STRICTLY_ABOVEWATER;
  3487. }
  3488. m_pWorldListInfo->m_LeafCount = m_pRenderList->m_leaves.Count();
  3489. m_pWorldListInfo->m_pLeafDataList = m_pRenderList->m_leaves.Base();
  3490. m_pWorldListInfo->m_bHasWater = m_pRenderList->m_bWaterVisible;
  3491. }
  3492. return JOB_OK;
  3493. }
  3494. //-----------------------------------------------------------------------------
  3495. // Purpose: recurse on the BSP tree, calling the surface visitor
  3496. // Input : *node - BSP node
  3497. //-----------------------------------------------------------------------------
  3498. void CBuildWorldListsJob::R_RecursiveWorldNode( CWorldRenderList *pRenderList, mnode_t *node )
  3499. {
  3500. int side;
  3501. cplane_t *plane;
  3502. float dot;
  3503. while (true)
  3504. {
  3505. #if defined( _X360 ) || defined( _PS3 )
  3506. PREFETCH_128(node->plane,0);
  3507. #endif
  3508. // no polygons in solid nodes
  3509. if (node->contents == CONTENTS_SOLID)
  3510. return; // solid
  3511. // Check PVS signature
  3512. //if (node->visframe != m_visFrameCount) // original, causes flicker in rare circumstances, race condition if view m > view n pvs setup (viscache) overwrites this var in main mem
  3513. if (node->visframe < m_visFrameCount) // to protect against race condition, may rarely give false positive - simpler for those rare frames where it occurs rather than locking or duping this member per view
  3514. return;
  3515. // Cull against the screen frustum or the appropriate area's frustum.
  3516. if (node->contents >= -1)
  3517. {
  3518. if ( R_CullNode( node ) )
  3519. return;
  3520. }
  3521. // if a leaf node, draw stuff
  3522. if (node->contents >= 0)
  3523. {
  3524. R_DrawLeaf( pRenderList, (mleaf_t *)node );
  3525. return;
  3526. }
  3527. #if defined( _X360 ) || defined( _PS3 )
  3528. PREFETCH_128(node->children[0],0);
  3529. PREFETCH_128(node->children[1],0);
  3530. PREFETCH_128(node->children[0],offsetof(mnode_t,plane));
  3531. PREFETCH_128(node->children[1],offsetof(mnode_t,plane));
  3532. #endif
  3533. // node is just a decision point, so go down the appropriate sides
  3534. // find which side of the node we are on
  3535. plane = node->plane;
  3536. if ( plane->type <= PLANE_Z )
  3537. {
  3538. dot = m_modelOrigin[plane->type] - plane->dist;
  3539. }
  3540. else
  3541. {
  3542. dot = DotProduct (m_modelOrigin, plane->normal) - plane->dist;
  3543. }
  3544. // recurse down the children, closer side first.
  3545. // We have to do this because we need to find if the surfaces at this node
  3546. // exist in any visible leaves closer to the camera than the node is. If so,
  3547. // their r_surfacevisframe is set to indicate that we need to render them
  3548. // at this node.
  3549. side = dot >= 0 ? 0 : 1;
  3550. // Recurse down the side closer to the camera
  3551. R_RecursiveWorldNode (pRenderList, node->children[side] );
  3552. // draw stuff on the node
  3553. SurfaceHandle_t surfID = SurfaceHandleFromIndex( node->firstsurface );
  3554. int i = MSurf_Index( surfID );
  3555. int nLastSurface = i + node->numsurfaces;
  3556. CVisitedSurfs &visitedSurfs = pRenderList->m_VisitedSurfs;
  3557. for ( ; i < nLastSurface; ++i, ++surfID )
  3558. {
  3559. // Only render things at this node that have previously been marked as visible
  3560. if ( !visitedSurfs.VisitedSurface( i ) )
  3561. continue;
  3562. // Don't add surfaces that have displacement
  3563. // UNDONE: Don't emit these at nodes in vbsp!
  3564. // UNDONE: Emit them at the end of the surface list
  3565. Assert( !SurfaceHasDispInfo( surfID ) );
  3566. // If a surface is marked to draw at a node, then it's not a func_detail.
  3567. // Only func_detail render at leaves. In the case of normal world surfaces,
  3568. // we only want to render them if they intersect a visible leaf.
  3569. uint32 nFlags = MSurf_Flags( surfID );
  3570. Assert( nFlags & SURFDRAW_NODE );
  3571. Assert( !(nFlags & SURFDRAW_NODRAW) );
  3572. if ( !(nFlags & SURFDRAW_UNDERWATER) && ( side ^ !!(nFlags & SURFDRAW_PLANEBACK)) )
  3573. continue; // wrong side
  3574. if ( nFlags & SURFDRAW_SKY )
  3575. {
  3576. pRenderList->m_bSkyVisible = true;
  3577. }
  3578. else if( nFlags & SURFDRAW_TRANS )
  3579. {
  3580. Shader_TranslucentWorldSurface( pRenderList, surfID );
  3581. }
  3582. else
  3583. {
  3584. Shader_WorldSurface( pRenderList, surfID );
  3585. }
  3586. }
  3587. // recurse down the side farther from the camera
  3588. // NOTE: With this while loop, this is identical to just calling
  3589. // R_RecursiveWorldNode (node->children[!side]);
  3590. node = node->children[!side];
  3591. }
  3592. }
  3593. //-----------------------------------------------------------------------------
  3594. // Fast path for rendering top-views
  3595. //-----------------------------------------------------------------------------
  3596. void CBuildWorldListsJob::R_RenderWorldTopView( CWorldRenderList *pRenderList, mnode_t *node )
  3597. {
  3598. CVisitedSurfs &visitedSurfs = pRenderList->m_VisitedSurfs;
  3599. do
  3600. {
  3601. // no polygons in solid nodes
  3602. if (node->contents == CONTENTS_SOLID)
  3603. return; // solid
  3604. // Check PVS signature
  3605. if ( !m_bTopViewNoVisCheck )
  3606. {
  3607. //if (node->visframe != m_visFrameCount) // original, causes flicker in rare circumstances, race condition if view m > view n pvs setup (viscache) overwrites this var in main mem
  3608. if (node->visframe < m_visFrameCount) // to protect against race condition, may rarely give false positive - simpler for those rare frames where it occurs rather than locking or duping this member per view
  3609. return;
  3610. }
  3611. // Cull against the screen frustum or the appropriate area's frustum.
  3612. if( R_CullNodeTopView( node ) )
  3613. return;
  3614. // if a leaf node, draw stuff
  3615. if (node->contents >= 0)
  3616. {
  3617. R_DrawTopViewLeaf( pRenderList, (mleaf_t *)node );
  3618. return;
  3619. }
  3620. #ifdef USE_CONVARS
  3621. if (s_ShaderConvars.m_bDrawWorld)
  3622. #endif
  3623. {
  3624. // draw stuff on the node
  3625. SurfaceHandle_t surfID = SurfaceHandleFromIndex( node->firstsurface );
  3626. for ( int i = 0; i < node->numsurfaces; i++, surfID++ )
  3627. {
  3628. if ( !visitedSurfs.VisitSurface( surfID ) )
  3629. continue;
  3630. // Don't add surfaces that have displacement
  3631. if ( SurfaceHasDispInfo( surfID ) )
  3632. continue;
  3633. // If a surface is marked to draw at a node, then it's not a func_detail.
  3634. // Only func_detail render at leaves. In the case of normal world surfaces,
  3635. // we only want to render them if they intersect a visible leaf.
  3636. Assert( (MSurf_Flags( surfID ) & SURFDRAW_NODE) );
  3637. if ( MSurf_Flags( surfID ) & (SURFDRAW_UNDERWATER|SURFDRAW_SKY) )
  3638. continue;
  3639. Assert( !(MSurf_Flags( surfID ) & SURFDRAW_NODRAW) );
  3640. if ( !m_bTopViewNoBackfaceCulling )
  3641. {
  3642. // Back face cull
  3643. if ( (MSurf_Flags( surfID ) & SURFDRAW_NOCULL) == 0 )
  3644. {
  3645. if (MSurf_Plane( surfID ).normal.z <= 0.0f)
  3646. continue;
  3647. }
  3648. }
  3649. // FIXME: For now, blow off translucent world polygons.
  3650. // Gotta solve the problem of how to render them all, unsorted,
  3651. // in a pass after the opaque world polygons, and before the
  3652. // translucent entities.
  3653. if ( !( MSurf_Flags( surfID ) & SURFDRAW_TRANS ) )
  3654. // if ( !surf->texinfo->material->IsTranslucent() )
  3655. Shader_WorldSurface( pRenderList, surfID );
  3656. }
  3657. }
  3658. // Recurse down both children, we don't care the order...
  3659. R_RenderWorldTopView ( pRenderList, node->children[0]);
  3660. node = node->children[1];
  3661. } while (node);
  3662. }
  3663. //-----------------------------------------------------------------------------
  3664. // Purpose: recurse on the BSP tree, calling the surface visitor
  3665. // Input : *node - BSP node
  3666. //-----------------------------------------------------------------------------
  3667. void CBuildWorldListsJob::R_BuildWorldListNoCull( CWorldRenderList *pRenderList, mnode_t *node )
  3668. {
  3669. int leafCount = 0;
  3670. const int NODELIST_MAX = 1024;
  3671. mleaf_t *leafList[NODELIST_MAX];
  3672. mnode_t *nodeList[NODELIST_MAX];
  3673. int nodeReadIndex = 0;
  3674. int nodeWriteIndex = 0;
  3675. while (true)
  3676. {
  3677. // no polygons in solid nodes
  3678. //if (node->contents != CONTENTS_SOLID && node->visframe == r_visframecount ) // original, causes flicer in rare circumstances, race condition if view m > view n pvs setup (viscache) overwrites this var in main mem
  3679. if (node->contents != CONTENTS_SOLID && node->visframe >= m_visFrameCount ) // to protect against race condition, may rarely give false positive - simpler for those rare frames where it occurs rather than locking or duping this member per view
  3680. {
  3681. if ( node->contents < -1 || !R_CullNode( node ) )
  3682. {
  3683. // if a leaf node, draw stuff
  3684. if (node->contents >= 0)
  3685. {
  3686. if ( leafCount < NODELIST_MAX )
  3687. {
  3688. leafList[leafCount++] = (mleaf_t *)node;
  3689. }
  3690. }
  3691. else
  3692. {
  3693. #if defined( _X360 ) || defined( _PS3 )
  3694. PREFETCH_128(node->children[0],0);
  3695. PREFETCH_128(node->children[1],0);
  3696. #endif
  3697. // node is just a decision point, so go down the appropriate sides
  3698. nodeList[nodeWriteIndex] = node->children[0];
  3699. nodeWriteIndex = (nodeWriteIndex+1) & (NODELIST_MAX-1);
  3700. // check for overflow of the ring buffer
  3701. Assert(nodeWriteIndex != nodeReadIndex);
  3702. node = node->children[1];
  3703. continue;
  3704. }
  3705. }
  3706. }
  3707. if ( nodeReadIndex == nodeWriteIndex )
  3708. break;
  3709. node = nodeList[nodeReadIndex];
  3710. nodeReadIndex = (nodeReadIndex+1) & (NODELIST_MAX-1);
  3711. }
  3712. for ( int i = 0; i < leafCount; i++ )
  3713. {
  3714. R_DrawLeafNoCull( pRenderList, leafList[i] );
  3715. }
  3716. }
  3717. //-----------------------------------------------------------------------------
  3718. // culls a node to the frustum or area frustum
  3719. //-----------------------------------------------------------------------------
  3720. bool CBuildWorldListsJob::R_CullNode( mnode_t *pNode )
  3721. {
  3722. if ( !m_bViewerInSolidSpace && pNode->area > 0 )
  3723. {
  3724. // First make sure its whole area is even visible.
  3725. //if( !R_IsAreaVisible( pNode->area ) )
  3726. if ( ( m_RenderAreaBits[pNode->area>>3] & GetBitForBitnum(pNode->area&7) ) == 0 )
  3727. return true;
  3728. return CullNodeSIMD( m_pAreaFrustum->Element( pNode->area ), pNode );
  3729. }
  3730. return CullNodeSIMD( *m_pFrustum, pNode );
  3731. }
  3732. bool CBuildWorldListsJob::R_CullNodeTopView( mnode_t *pNode )
  3733. {
  3734. if ( m_pTopViewVolumeCuller )
  3735. {
  3736. return !m_pTopViewVolumeCuller->CheckBoxCenterHalfDiagonal( pNode->m_vecCenter, pNode->m_vecHalfDiagonal );
  3737. }
  3738. Vector2D delta, size;
  3739. Vector2DSubtract( pNode->m_vecCenter.AsVector2D(), m_OrthographicCenter, delta );
  3740. Vector2DAdd( pNode->m_vecHalfDiagonal.AsVector2D(), m_OrthographicHalfDiagonal, size );
  3741. return ( FloatMakePositive( delta.x ) > size.x ) ||
  3742. ( FloatMakePositive( delta.y ) > size.y );
  3743. }
  3744. //-----------------------------------------------------------------------------
  3745. // Draws all displacements + surfaces in a leaf
  3746. //-----------------------------------------------------------------------------
  3747. void CBuildWorldListsJob::R_DrawLeaf( CWorldRenderList *pRenderList, mleaf_t *pleaf )
  3748. {
  3749. SurfaceHandle_t *pSurfID = &host_state.worldbrush->marksurfaces[pleaf->firstmarksurface];
  3750. #if defined( _X360 ) || defined( _PS3 )
  3751. PREFETCH_128(pSurfID,0);
  3752. #endif
  3753. // Add this leaf to the list of visible leaves
  3754. UpdateVisibleLeafLists( pRenderList, pleaf );
  3755. // Debugging to only draw at a particular leaf
  3756. #ifdef USE_CONVARS
  3757. if ( (s_ShaderConvars.m_nDrawLeaf >= 0) && (s_ShaderConvars.m_nDrawLeaf != LeafToIndex(pleaf)) )
  3758. return;
  3759. #endif
  3760. // add displacement surfaces
  3761. DrawDisplacementsInLeaf( pRenderList, pleaf );
  3762. #ifdef USE_CONVARS
  3763. if( !s_ShaderConvars.m_bDrawWorld )
  3764. return;
  3765. #endif
  3766. // Add non-displacement surfaces
  3767. #if defined( _X360 ) || defined( _PS3 )
  3768. int count = MIN(pleaf->nummarksurfaces, 7);
  3769. for ( int i = 0; i < count; ++i )
  3770. {
  3771. PREFETCH_128(pSurfID[i],0);
  3772. }
  3773. #endif
  3774. int i;
  3775. int nSurfaceCount = pleaf->nummarknodesurfaces;
  3776. CVisitedSurfs &visitedSurfs = pRenderList->m_VisitedSurfs;
  3777. for ( i = 0; i < nSurfaceCount; ++i )
  3778. {
  3779. SurfaceHandle_t surfID = pSurfID[i];
  3780. ASSERT_SURF_VALID( surfID );
  3781. // there are never any displacements or nodraws in the leaf list
  3782. Assert( !(MSurf_Flags( surfID ) & SURFDRAW_NODRAW) );
  3783. Assert( (MSurf_Flags( surfID ) & SURFDRAW_NODE) );
  3784. Assert( !SurfaceHasDispInfo(surfID) );
  3785. // mark this one to be drawn at the node
  3786. visitedSurfs.MarkSurfaceVisited( surfID );
  3787. #if defined( _X360 ) || defined( _PS3 )
  3788. PREFETCH_128(pSurfID[i+7],0);
  3789. #endif
  3790. }
  3791. #ifdef USE_CONVARS
  3792. if( !s_ShaderConvars.m_bDrawFuncDetail )
  3793. return;
  3794. #endif
  3795. for ( ; i < pleaf->nummarksurfaces; i++ )
  3796. {
  3797. SurfaceHandle_t surfID = pSurfID[i];
  3798. #if defined( _X360 )// || defined( _PS3 )
  3799. PREFETCH_128(surfID->plane,0);
  3800. PREFETCH_128(pSurfID[i+7],0);
  3801. #endif
  3802. // Don't process the same surface twice
  3803. if ( !visitedSurfs.VisitSurface( surfID ) )
  3804. continue;
  3805. uint32 flags = surfID->flags;
  3806. Assert( !(flags & SURFDRAW_NODE) );
  3807. // Back face cull; only func_detail are drawn here
  3808. if ( (flags & SURFDRAW_NOCULL) == 0 )
  3809. {
  3810. #if !defined(_PS3)
  3811. if ( (DotProduct(surfID->plane->normal, m_modelOrigin) - surfID->plane->dist ) < BACKFACE_EPSILON )
  3812. continue;
  3813. #else
  3814. if ( (DotProduct(surfID->m_plane.normal, m_modelOrigin) - surfID->m_plane.dist ) < BACKFACE_EPSILON )
  3815. continue;
  3816. #endif
  3817. }
  3818. int sortGroup = (flags & SURFDRAW_SORTGROUP_MASK) >> SURFDRAW_SORTGROUP_SHIFT;
  3819. if ( flags & (SURFDRAW_HASLIGHTSYTLES|SURFDRAW_HASDLIGHT) )
  3820. {
  3821. pRenderList->m_DlightSurfaces[sortGroup].AddToTail( surfID );
  3822. }
  3823. if ( flags & SURFDRAW_PAINTED )
  3824. {
  3825. pRenderList->m_PaintedSurfaces->AddToTail( surfID );
  3826. }
  3827. if( flags & SURFDRAW_TRANS )
  3828. {
  3829. pRenderList->m_AlphaSurfaces.AddToTail(surfID);
  3830. }
  3831. else
  3832. {
  3833. // Add decals on non-displacement surfaces
  3834. if( SurfaceHasDecals( surfID ) )
  3835. {
  3836. pRenderList->QueueDecalSurf( surfID, sortGroup );
  3837. }
  3838. int nMaterialSortID = MSurf_MaterialSortID( surfID );
  3839. pRenderList->m_SortList.AddSurfaceToTail( surfID, sortGroup, nMaterialSortID );
  3840. }
  3841. }
  3842. }
  3843. //-----------------------------------------------------------------------------
  3844. // Draws all displacements + surfaces in a leaf
  3845. //-----------------------------------------------------------------------------
  3846. void CBuildWorldListsJob::R_DrawTopViewLeaf( CWorldRenderList *pRenderList, mleaf_t *pleaf )
  3847. {
  3848. // Add this leaf to the list of visible leaves
  3849. UpdateVisibleLeafLists( pRenderList, pleaf );
  3850. // add displacement surfaces
  3851. DrawDisplacementsInLeaf( pRenderList, pleaf );
  3852. #ifdef USE_CONVARS
  3853. if( !s_ShaderConvars.m_bDrawWorld )
  3854. return;
  3855. #endif
  3856. // Add non-displacement surfaces
  3857. SurfaceHandle_t *pHandle = &host_state.worldbrush->marksurfaces[pleaf->firstmarksurface];
  3858. CVisitedSurfs &visitedSurfs = pRenderList->m_VisitedSurfs;
  3859. for ( int i = 0; i < pleaf->nummarksurfaces; i++ )
  3860. {
  3861. SurfaceHandle_t surfID = pHandle[i];
  3862. // Mark this surface as being in a visible leaf this frame. If this
  3863. // surface is meant to be drawn at a node (SURFDRAW_NODE),
  3864. // then it will be drawn in the recursive code down below.
  3865. if ( !visitedSurfs.VisitSurface( surfID ) )
  3866. continue;
  3867. // Don't add surfaces that have displacement; they are handled above
  3868. // In fact, don't even set the vis frame; we need it unset for translucent
  3869. // displacement code
  3870. if ( SurfaceHasDispInfo(surfID) )
  3871. continue;
  3872. if ( MSurf_Flags( surfID ) & SURFDRAW_NODE )
  3873. continue;
  3874. Assert( !(MSurf_Flags( surfID ) & SURFDRAW_NODRAW) );
  3875. if ( !m_bTopViewNoBackfaceCulling )
  3876. {
  3877. // Back face cull; only func_detail are drawn here
  3878. if ( (MSurf_Flags( surfID ) & SURFDRAW_NOCULL) == 0 )
  3879. {
  3880. if (MSurf_Plane( surfID ).normal.z <= 0.0f)
  3881. continue;
  3882. }
  3883. }
  3884. // FIXME: For now, blow off translucent world polygons.
  3885. // Gotta solve the problem of how to render them all, unsorted,
  3886. // in a pass after the opaque world polygons, and before the
  3887. // translucent entities.
  3888. if ( !( MSurf_Flags( surfID ) & SURFDRAW_TRANS ))
  3889. // if ( !surf->texinfo->material->IsTranslucent() )
  3890. Shader_WorldSurface( pRenderList, surfID );
  3891. }
  3892. }
  3893. void CBuildWorldListsJob::R_DrawLeafNoCull( CWorldRenderList *pRenderList, mleaf_t *pleaf )
  3894. {
  3895. // Add this leaf to the list of visible leaves
  3896. UpdateVisibleLeafLists( pRenderList, pleaf );
  3897. // add displacement surfaces
  3898. DrawDisplacementsInLeaf( pRenderList, pleaf );
  3899. int i;
  3900. SurfaceHandle_t *pSurfID = &host_state.worldbrush->marksurfaces[pleaf->firstmarksurface];
  3901. CVisitedSurfs &visitedSurfs = pRenderList->m_VisitedSurfs;
  3902. for ( i = 0; i < pleaf->nummarksurfaces; i++ )
  3903. {
  3904. SurfaceHandle_t surfID = pSurfID[i];
  3905. // Don't process the same surface twice
  3906. if ( !visitedSurfs.VisitSurface( surfID ) )
  3907. continue;
  3908. R_DrawSurfaceNoCull( pRenderList, surfID );
  3909. }
  3910. }
  3911. // The NoCull flavor of this function calls functions which optimize for shadow depth map rendering
  3912. void CBuildWorldListsJob::R_DrawSurfaceNoCull( CWorldRenderList *pRenderList, SurfaceHandle_t surfID )
  3913. {
  3914. ASSERT_SURF_VALID( surfID );
  3915. if( !(MSurf_Flags( surfID ) & SURFDRAW_TRANS) && !(MSurf_Flags( surfID ) & SURFDRAW_SKY) )
  3916. {
  3917. Shader_WorldSurfaceNoCull( pRenderList, surfID );
  3918. }
  3919. }
  3920. void CBuildWorldListsJob::DrawDisplacementsInLeaf( CWorldRenderList *pRenderList, mleaf_t* pLeaf )
  3921. {
  3922. // add displacement surfaces
  3923. if (!pLeaf->dispCount)
  3924. return;
  3925. CVisitedSurfs &visitedSurfs = pRenderList->m_VisitedSurfs;
  3926. for ( int i = 0; i < pLeaf->dispCount; i++ )
  3927. {
  3928. CDispInfo *pDispInfo = static_cast<CDispInfo *>(MLeaf_Disaplcement( pLeaf, i ));
  3929. // NOTE: We're not using the displacement's touched method here
  3930. // because we're just using the parent surface's visframe in the
  3931. // surface add methods below...
  3932. SurfaceHandle_t parentSurfID = pDispInfo->m_ParentSurfID;
  3933. // already processed this frame? Then don't do it again!
  3934. if ( visitedSurfs.VisitSurface( parentSurfID ) )
  3935. {
  3936. if ( m_pFrustum->CullBox( pDispInfo->m_BBoxMin, pDispInfo->m_BBoxMax ) )
  3937. continue;
  3938. if ( MSurf_Flags( parentSurfID ) & SURFDRAW_TRANS)
  3939. {
  3940. Shader_TranslucentDisplacementSurface( pRenderList, parentSurfID );
  3941. }
  3942. else
  3943. {
  3944. Shader_DisplacementSurface( pRenderList, parentSurfID );
  3945. }
  3946. }
  3947. }
  3948. }
  3949. void CBuildWorldListsJob::Shader_WorldSurface( CWorldRenderList *pRenderList, SurfaceHandle_t surfID )
  3950. {
  3951. // Hook it into the list of surfaces to render with this material
  3952. // Do it in a way that generates a front-to-back ordering for fast z reject
  3953. Assert( !SurfaceHasDispInfo( surfID ) );
  3954. // Each surface is in exactly one group
  3955. int nSortGroup = MSurf_SortGroup( surfID );
  3956. // Add decals on non-displacement surfaces
  3957. if( SurfaceHasDecals( surfID ) )
  3958. {
  3959. pRenderList->QueueDecalSurf( surfID, nSortGroup );
  3960. }
  3961. int nMaterialSortID = MSurf_MaterialSortID( surfID );
  3962. if ( MSurf_Flags( surfID ) & (SURFDRAW_HASLIGHTSYTLES|SURFDRAW_HASDLIGHT) )
  3963. {
  3964. pRenderList->m_DlightSurfaces[nSortGroup].AddToTail( surfID );
  3965. }
  3966. if ( MSurf_Flags( surfID ) & SURFDRAW_PAINTED )
  3967. {
  3968. pRenderList->m_PaintedSurfaces[nSortGroup].AddToTail( surfID );
  3969. }
  3970. pRenderList->m_SortList.AddSurfaceToTail( surfID, nSortGroup, nMaterialSortID );
  3971. }
  3972. // The NoCull flavor of this function optimizes for shadow depth map rendering
  3973. // No decal work, dlights or material sorting, for example
  3974. void CBuildWorldListsJob::Shader_WorldSurfaceNoCull( CWorldRenderList *pRenderList, SurfaceHandle_t surfID )
  3975. {
  3976. // Hook it into the list of surfaces to render with this material
  3977. // Do it in a way that generates a front-to-back ordering for fast z reject
  3978. Assert( !SurfaceHasDispInfo( surfID ) );
  3979. // Each surface is in exactly one group
  3980. int nSortGroup = MSurf_SortGroup( surfID );
  3981. int nMaterialSortID = MSurf_MaterialSortID( surfID );
  3982. pRenderList->m_SortList.AddSurfaceToTail( surfID, nSortGroup, nMaterialSortID );
  3983. }
  3984. //-----------------------------------------------------------------------------
  3985. // Main entry points for starting + ending rendering the world
  3986. //-----------------------------------------------------------------------------
  3987. void R_BuildWorldLists( IWorldRenderList *pRenderListIn, WorldListInfo_t* pInfo,
  3988. int iForceViewLeaf, const VisOverrideData_t* pVisData, bool bShadowDepth /* = false */, float *pWaterReflectionHeight )
  3989. {
  3990. CWorldRenderList *pRenderList = assert_cast<CWorldRenderList *>(pRenderListIn);
  3991. // Safety measure just in case. I haven't seen that we need this, but...
  3992. if ( g_LostVideoMemory )
  3993. {
  3994. if (pInfo)
  3995. {
  3996. pInfo->m_ViewFogVolume = MAT_SORT_GROUP_STRICTLY_ABOVEWATER;
  3997. pInfo->m_LeafCount = 0;
  3998. pInfo->m_pLeafDataList = pRenderList->m_leaves.Base();
  3999. pInfo->m_bHasWater = pRenderList->m_bWaterVisible;
  4000. }
  4001. return;
  4002. }
  4003. VPROF( "R_BuildWorldLists" );
  4004. SNPROF( "R_BuildWorldLists" );
  4005. VectorCopy( g_EngineRenderer->ViewOrigin(), modelorg );
  4006. Shader_WorldBegin( pRenderList );
  4007. #if defined( _PS3 )
  4008. extern IBaseClientDLL *g_ClientDLL;
  4009. extern CUtlVector< Frustum_t > g_AreaFrustum;
  4010. extern unsigned char g_RenderAreaBits[32];
  4011. extern bool g_bViewerInSolidSpace;
  4012. if( r_PS3_SPU_buildworldlists.GetInt() && g_ClientDLL->IsSPUBuildWRJobsOn() )
  4013. {
  4014. // Run BuildWorldLists on SPU
  4015. // this goes hand-in-hand with building renderables on SPU and runs the job in parallel while the PPU continues
  4016. // a sync point is required while drawing and entry into here assumes 2 passes over the rendering
  4017. // lists are built during the 1st pass, drawn during the 2nd (where/when the jobs started in pass 1 are synced)
  4018. Frustum_t *pgFrustum, *pgAreaFrustum;
  4019. unsigned char *pgRenderAreaBits;
  4020. void *pVC = NULL;
  4021. SNPROF("R_BuildWorldLists_SPUpath");
  4022. if ( !r_drawtopview )
  4023. {
  4024. R_SetupAreaBits( iForceViewLeaf, pVisData, pWaterReflectionHeight );
  4025. }
  4026. g_ClientDLL->CacheFrustumData( &g_Frustum, g_AreaFrustum.Base(), g_RenderAreaBits, g_AreaFrustum.Count(), g_bViewerInSolidSpace );
  4027. if( s_pTopViewVolumeCuller )
  4028. {
  4029. pVC = g_ClientDLL->GetBuildViewVolumeCuller();
  4030. }
  4031. pgFrustum = g_ClientDLL->GetBuildViewFrustum();
  4032. pgAreaFrustum = g_ClientDLL->GetBuildViewAreaFrustum();
  4033. pgRenderAreaBits = g_ClientDLL->GetBuildViewRenderAreaBits();
  4034. int buildViewID = g_ClientDLL->GetBuildViewID();
  4035. job_buildworldlists::JobParams_t* pParam = job_buildworldlists::GetJobParams( &g_buildWorldListsJobDescriptor[ buildViewID ] );
  4036. pRenderList->EnsureCapacityForSPU( AlignValue( materials->GetNumSortIDs(), 16 ), host_state.worldbrush->numsurfaces );
  4037. pRenderList->FillOutputParamsForSPU( &g_buildWorldListsDMAOutData[ buildViewID ] );
  4038. g_pBuildWorldListsJob->BuildWorldLists_SPU( pParam, &g_buildWorldListsDMAOutData[ buildViewID ],
  4039. r_drawtopview, pVC/*(void *)s_pTopViewVolumeCuller*/, s_OrthographicCenter.Base(), s_OrthographicHalfDiagonal.Base(), r_bTopViewNoBackfaceCulling, r_bTopViewNoVisCheck,
  4040. bShadowDepth, pInfo, pRenderList->m_leaves.Base(), g_ClientDLL->GetDrawFlags(),
  4041. pgFrustum, pgAreaFrustum, pgRenderAreaBits,
  4042. buildViewID );
  4043. }
  4044. else
  4045. #endif
  4046. {
  4047. extern IBaseClientDLL *g_ClientDLL;
  4048. extern CUtlVector< Frustum_t, CUtlMemoryAligned< Frustum_t,16 > > g_AreaFrustum;
  4049. extern unsigned char g_RenderAreaBits[32];
  4050. extern bool g_bViewerInSolidSpace;
  4051. if ( !r_drawtopview )
  4052. {
  4053. R_SetupAreaBits( iForceViewLeaf, pVisData, pWaterReflectionHeight );
  4054. }
  4055. g_ClientDLL->CacheFrustumData( g_Frustum, g_AreaFrustum );
  4056. // TODO get frustum, aera frustums volume culler from g_viewBuilder
  4057. CBuildWorldListsJob* pJob = new CBuildWorldListsJob(
  4058. pRenderList,
  4059. pInfo,
  4060. bShadowDepth,
  4061. CurrentViewOrigin(),
  4062. r_visframecount,
  4063. r_drawtopview,
  4064. r_bTopViewNoBackfaceCulling,
  4065. r_bTopViewNoVisCheck,
  4066. s_OrthographicCenter,
  4067. s_OrthographicHalfDiagonal,
  4068. s_pTopViewVolumeCuller,
  4069. g_ClientDLL->GetBuildViewFrustum(),
  4070. g_ClientDLL->GetBuildViewAeraFrustums(),
  4071. g_RenderAreaBits,
  4072. g_bViewerInSolidSpace,
  4073. modelorg );
  4074. g_ClientDLL->QueueBuildWorldListJob( pJob );
  4075. pJob->Release();
  4076. }
  4077. }
  4078. //-----------------------------------------------------------------------------
  4079. // Call this before rendering; it clears out the lists of stuff to render
  4080. //-----------------------------------------------------------------------------
  4081. void Shader_WorldBegin_Pass2( CWorldRenderList *pRenderList )
  4082. {
  4083. // Clear out the decal list
  4084. DecalSurfacesInit( false );
  4085. // Clear out the render lists of overlays
  4086. // OverlayMgr()->ClearRenderLists();
  4087. // Clear out the render lists of shadows
  4088. // g_pShadowMgr->ClearShadowRenderList( );
  4089. }
  4090. #if defined(_PS3)
  4091. void R_BuildWorldLists_PS3_Epilogue( IWorldRenderList *pRenderListIn, WorldListInfo_t* pInfo, bool bShadowDepth )
  4092. {
  4093. CWorldRenderList *pRenderList = assert_cast<CWorldRenderList *>(pRenderListIn);
  4094. // if doing 2 pass, this epilogue will be on 2nd pass
  4095. // => need to call a lite version of Shader_WorldBegin that does away with resetting the world lists
  4096. Shader_WorldBegin_Pass2( pRenderList );
  4097. // Don't bother in topview?
  4098. if ( !r_drawtopview && !bShadowDepth )
  4099. {
  4100. // epilogue - add decal surfs
  4101. pRenderList->AddSPUDecalSurfs();
  4102. // This builds all lightmaps, including those for translucent surfaces
  4103. Shader_BuildDynamicLightmaps( pRenderList );
  4104. }
  4105. //
  4106. if ( pInfo )
  4107. {
  4108. // Compute fog volume info for rendering
  4109. if ( !bShadowDepth )
  4110. {
  4111. FogVolumeInfo_t fogInfo;
  4112. ComputeFogVolumeInfo( &fogInfo, CurrentViewOrigin() );
  4113. if( fogInfo.m_InFogVolume )
  4114. {
  4115. pInfo->m_ViewFogVolume = MAT_SORT_GROUP_STRICTLY_UNDERWATER;
  4116. }
  4117. else
  4118. {
  4119. pInfo->m_ViewFogVolume = MAT_SORT_GROUP_STRICTLY_ABOVEWATER;
  4120. }
  4121. }
  4122. else
  4123. {
  4124. pInfo->m_ViewFogVolume = MAT_SORT_GROUP_STRICTLY_ABOVEWATER;
  4125. }
  4126. }
  4127. // Msg("PPU LeafCount %d\n", pRenderList->m_leaves.Count());
  4128. }
  4129. #else
  4130. void R_BuildWorldLists_Epilogue( IWorldRenderList *pRenderListIn, WorldListInfo_t* pInfo, bool bShadowDepth )
  4131. {
  4132. CWorldRenderList *pRenderList = assert_cast<CWorldRenderList *>(pRenderListIn);
  4133. // if doing 2 pass, this epilogue will be on 2nd pass
  4134. // => need to call a lite version of Shader_WorldBegin that does away with resetting the world lists
  4135. Shader_WorldBegin_Pass2( pRenderList );
  4136. // Add decal
  4137. pRenderList->AddDecalSurfs();
  4138. // This builds all lightmaps, including those for translucent surfaces
  4139. // Don't bother in topview?
  4140. if ( !r_drawtopview && !bShadowDepth )
  4141. {
  4142. Shader_BuildDynamicLightmaps( pRenderList );
  4143. }
  4144. }
  4145. #endif
  4146. //-----------------------------------------------------------------------------
  4147. // Used to determine visible fog volumes
  4148. //-----------------------------------------------------------------------------
  4149. class CVisibleFogVolumeQuery
  4150. {
  4151. public:
  4152. void FindVisibleFogVolume( const Vector &vecViewPoint, const VisOverrideData_t *pVisOverrideData, int *pVisibleFogVolume, int *pVisibleFogVolumeLeaf );
  4153. private:
  4154. bool RecursiveGetVisibleFogVolume( mnode_t *node );
  4155. // Input
  4156. Vector m_vecSearchPoint;
  4157. // Output
  4158. int m_nVisibleFogVolume;
  4159. int m_nVisibleFogVolumeLeaf;
  4160. };
  4161. //-----------------------------------------------------------------------------
  4162. // Main entry point for the query
  4163. //-----------------------------------------------------------------------------
  4164. void CVisibleFogVolumeQuery::FindVisibleFogVolume( const Vector &vecViewPoint, const VisOverrideData_t *pVisOverrideData, int *pVisibleFogVolume, int *pVisibleFogVolumeLeaf )
  4165. {
  4166. R_SetupAreaBits( -1, pVisOverrideData );
  4167. m_vecSearchPoint = vecViewPoint;
  4168. m_nVisibleFogVolume = -1;
  4169. m_nVisibleFogVolumeLeaf = -1;
  4170. RecursiveGetVisibleFogVolume( host_state.worldbrush->nodes );
  4171. *pVisibleFogVolume = m_nVisibleFogVolume;
  4172. *pVisibleFogVolumeLeaf = m_nVisibleFogVolumeLeaf;
  4173. }
  4174. //-----------------------------------------------------------------------------
  4175. // return true to continue searching
  4176. //-----------------------------------------------------------------------------
  4177. bool CVisibleFogVolumeQuery::RecursiveGetVisibleFogVolume( mnode_t *node )
  4178. {
  4179. int side;
  4180. cplane_t *plane;
  4181. float dot;
  4182. // no polygons in solid nodes
  4183. if (node->contents == CONTENTS_SOLID)
  4184. return true; // solid
  4185. // Check PVS signature
  4186. if (node->visframe != r_visframecount)
  4187. return true;
  4188. // Cull against the screen frustum or the appropriate area's frustum.
  4189. if( R_CullNode( node ) )
  4190. return true;
  4191. // if a leaf node, check if we are in a fog volume and get outta here.
  4192. if (node->contents >= 0)
  4193. {
  4194. mleaf_t *pLeaf = (mleaf_t *)node;
  4195. // Don't return a leaf that's not filled with liquid
  4196. if ( pLeaf->leafWaterDataID == -1 )
  4197. return true;
  4198. // Never return SLIME as being visible, as it's opaque
  4199. if ( pLeaf->contents & CONTENTS_SLIME )
  4200. return true;
  4201. m_nVisibleFogVolume = pLeaf->leafWaterDataID;
  4202. m_nVisibleFogVolumeLeaf = pLeaf - host_state.worldbrush->leafs;
  4203. return false; // found it, so stop searching
  4204. }
  4205. // node is just a decision point, so go down the apropriate sides
  4206. // find which side of the node we are on
  4207. plane = node->plane;
  4208. if ( plane->type <= PLANE_Z )
  4209. {
  4210. dot = m_vecSearchPoint[plane->type] - plane->dist;
  4211. }
  4212. else
  4213. {
  4214. dot = DotProduct( m_vecSearchPoint, plane->normal ) - plane->dist;
  4215. }
  4216. // recurse down the children, closer side first.
  4217. // We have to do this because we need to find if the surfaces at this node
  4218. // exist in any visible leaves closer to the camera than the node is. If so,
  4219. // their r_surfacevisframe is set to indicate that we need to render them
  4220. // at this node.
  4221. side = (dot >= 0) ? 0 : 1;
  4222. // Recurse down the side closer to the camera
  4223. if( !RecursiveGetVisibleFogVolume (node->children[side]) )
  4224. return false;
  4225. // recurse down the side farther from the camera
  4226. return RecursiveGetVisibleFogVolume (node->children[!side]);
  4227. }
  4228. static void ClearFogInfo( VisibleFogVolumeInfo_t *pInfo )
  4229. {
  4230. pInfo->m_bEyeInFogVolume = false;
  4231. pInfo->m_nVisibleFogVolume = -1;
  4232. pInfo->m_nVisibleFogVolumeLeaf = -1;
  4233. pInfo->m_pFogVolumeMaterial = NULL;
  4234. pInfo->m_flWaterHeight = INVALID_WATER_HEIGHT;
  4235. }
  4236. ConVar fast_fogvolume("fast_fogvolume", "0");
  4237. //-----------------------------------------------------------------------------
  4238. // Main entry point from renderer to get the fog volume
  4239. //-----------------------------------------------------------------------------
  4240. void R_GetVisibleFogVolume( const Vector& vEyePoint, const VisOverrideData_t *pVisOverrideData, VisibleFogVolumeInfo_t *pInfo )
  4241. {
  4242. VPROF_BUDGET( "R_GetVisibleFogVolume", VPROF_BUDGETGROUP_WORLD_RENDERING );
  4243. if ( host_state.worldmodel->brush.pShared->numleafwaterdata == 0 )
  4244. {
  4245. ClearFogInfo( pInfo );
  4246. return;
  4247. }
  4248. int nLeafID = CM_PointLeafnum( vEyePoint );
  4249. mleaf_t* pLeaf = &host_state.worldbrush->leafs[nLeafID];
  4250. int nLeafContents = pLeaf->contents;
  4251. if ( pLeaf->leafWaterDataID != -1 )
  4252. {
  4253. Assert( nLeafContents & (CONTENTS_SLIME | CONTENTS_WATER) );
  4254. pInfo->m_bEyeInFogVolume = true;
  4255. pInfo->m_nVisibleFogVolume = pLeaf->leafWaterDataID;
  4256. pInfo->m_nVisibleFogVolumeLeaf = nLeafID;
  4257. pInfo->m_pFogVolumeMaterial = R_GetFogVolumeMaterial( pInfo->m_nVisibleFogVolume, true );
  4258. pInfo->m_flWaterHeight = R_GetWaterHeight( pInfo->m_nVisibleFogVolume );
  4259. }
  4260. else if ( nLeafContents & CONTENTS_TESTFOGVOLUME )
  4261. {
  4262. Assert( (nLeafContents & (CONTENTS_SLIME | CONTENTS_WATER)) == 0 );
  4263. if ( fast_fogvolume.GetBool() && host_state.worldbrush->numleafwaterdata == 1 )
  4264. {
  4265. pInfo->m_nVisibleFogVolume = 0;
  4266. pInfo->m_nVisibleFogVolumeLeaf = host_state.worldbrush->leafwaterdata[0].firstLeafIndex;
  4267. }
  4268. else
  4269. {
  4270. CVisibleFogVolumeQuery query;
  4271. query.FindVisibleFogVolume( vEyePoint, pVisOverrideData, &pInfo->m_nVisibleFogVolume, &pInfo->m_nVisibleFogVolumeLeaf );
  4272. }
  4273. pInfo->m_bEyeInFogVolume = false;
  4274. pInfo->m_pFogVolumeMaterial = R_GetFogVolumeMaterial( pInfo->m_nVisibleFogVolume, false );
  4275. pInfo->m_flWaterHeight = R_GetWaterHeight( pInfo->m_nVisibleFogVolume );
  4276. }
  4277. else
  4278. {
  4279. ClearFogInfo( pInfo );
  4280. }
  4281. if( host_state.worldbrush->m_LeafMinDistToWater )
  4282. {
  4283. pInfo->m_flDistanceToWater = ( float )host_state.worldbrush->m_LeafMinDistToWater[nLeafID];
  4284. }
  4285. else
  4286. {
  4287. pInfo->m_flDistanceToWater = 0.0f;
  4288. }
  4289. }
  4290. //-----------------------------------------------------------------------------
  4291. // Draws the list of surfaces build in the BuildWorldLists phase
  4292. //-----------------------------------------------------------------------------
  4293. // Uncomment this to allow code to draw wireframe over a particular surface for debugging
  4294. //#define DEBUG_SURF 1
  4295. #ifdef DEBUG_SURF
  4296. int g_DebugSurfIndex = -1;
  4297. #endif
  4298. void R_DrawWorldLists( IMatRenderContext *pRenderContext, IWorldRenderList *pRenderListIn, unsigned long flags, float waterZAdjust )
  4299. {
  4300. CWorldRenderList *pRenderList = assert_cast<CWorldRenderList *>(pRenderListIn);
  4301. if ( g_bTextMode || g_LostVideoMemory )
  4302. return;
  4303. VPROF("R_DrawWorldLists");
  4304. if ( flags & DRAWWORLDLISTS_DRAW_WORLD_GEOMETRY )
  4305. {
  4306. Shader_WorldEnd( pRenderContext, pRenderList, flags, waterZAdjust );
  4307. }
  4308. else if ( flags & ( DRAWWORLDLISTS_DRAW_SIMPLE_WORLD_MODEL | DRAWWORLDLISTS_DRAW_SIMPLE_WORLD_MODEL_WATER ) )
  4309. {
  4310. DrawSimpleWorldModel( flags );
  4311. }
  4312. if ( flags & DRAWWORLDLISTS_DRAW_DECALS_AND_OVERLAYS )
  4313. {
  4314. Shader_DrawWorldDecalsAndOverlays( pRenderContext, pRenderList, flags, waterZAdjust );
  4315. }
  4316. #ifdef DEBUG_SURF
  4317. {
  4318. VPROF("R_DrawWorldLists (DEBUG_SURF)");
  4319. if (g_pDebugSurf)
  4320. {
  4321. pRenderContext->Bind( g_materialWorldWireframe );
  4322. Shader_DrawSurfaceDynamic( pRenderContext, g_pDebugSurf );
  4323. }
  4324. }
  4325. #endif
  4326. }
  4327. //-----------------------------------------------------------------------------
  4328. // Counts the total number of indices needed to render a world list
  4329. //-----------------------------------------------------------------------------
  4330. int R_GetNumIndicesForWorldList( IWorldRenderList *pRenderListIn, unsigned long nFlags )
  4331. {
  4332. CWorldRenderList *pRenderList = assert_cast<CWorldRenderList *>( pRenderListIn );
  4333. int nNumIndices = 0;
  4334. for ( int g = 0; g < MAX_MAT_SORT_GROUPS; ++g )
  4335. {
  4336. if ( ( nFlags & ( 1 << g ) ) == 0 )
  4337. continue;
  4338. int nSortGroup = s_DrawWorldListsToSortGroup[ g ];
  4339. MSL_FOREACH_GROUP_BEGIN( pRenderList->m_SortList, nSortGroup, group )
  4340. {
  4341. nNumIndices += group.triangleCount * 3;
  4342. }
  4343. MSL_FOREACH_GROUP_END()
  4344. }
  4345. return nNumIndices;
  4346. }
  4347. void R_GetWorldListIndicesInfo( WorldListIndicesInfo_t * pInfoOut, IWorldRenderList *pRenderListIn, unsigned long nFlags )
  4348. {
  4349. CWorldRenderList *pRenderList = assert_cast<CWorldRenderList *>( pRenderListIn );
  4350. uint nTotalTriangles = 0, nMaxBatchTriangles = 0;
  4351. for ( int g = 0; g < MAX_MAT_SORT_GROUPS; ++g )
  4352. {
  4353. if ( ( nFlags & ( 1 << g ) ) == 0 )
  4354. continue;
  4355. int nSortGroup = s_DrawWorldListsToSortGroup[ g ];
  4356. MSL_FOREACH_GROUP_BEGIN( pRenderList->m_SortList, nSortGroup, group )
  4357. {
  4358. nTotalTriangles += group.triangleCount;
  4359. nMaxBatchTriangles = MAX( nMaxBatchTriangles, group.triangleCount );
  4360. }
  4361. MSL_FOREACH_GROUP_END()
  4362. }
  4363. pInfoOut->m_nMaxBatchIndices = nMaxBatchTriangles * 3;
  4364. pInfoOut->m_nTotalIndices = nTotalTriangles * 3;
  4365. }
  4366. //-----------------------------------------------------------------------------
  4367. // Purpose:
  4368. //-----------------------------------------------------------------------------
  4369. void R_SceneBegin( void )
  4370. {
  4371. ComputeDebugSettings();
  4372. }
  4373. void R_SceneEnd( void )
  4374. {
  4375. #if defined(_PS3)
  4376. R_FrameEndSPURSSync( 0 );
  4377. #endif
  4378. }
  4379. //-----------------------------------------------------------------------------
  4380. // Debugging code to draw the lightmap pages
  4381. //-----------------------------------------------------------------------------
  4382. void Shader_DrawLightmapPageSurface( SurfaceHandle_t surfID, float red, float green, float blue )
  4383. {
  4384. Vector2D lightCoords[32][4];
  4385. int bumpID, count;
  4386. if ( MSurf_Flags( surfID ) & SURFDRAW_BUMPLIGHT )
  4387. {
  4388. count = NUM_BUMP_VECTS + 1;
  4389. }
  4390. else
  4391. {
  4392. count = 1;
  4393. }
  4394. BuildMSurfaceVerts( host_state.worldbrush, surfID, NULL, NULL, lightCoords );
  4395. int lightmapPageWidth, lightmapPageHeight;
  4396. CMatRenderContextPtr pRenderContext( materials );
  4397. pRenderContext->Bind( g_materialWireframe );
  4398. materials->GetLightmapPageSize(
  4399. SortInfoToLightmapPage(MSurf_MaterialSortID( surfID )),
  4400. &lightmapPageWidth, &lightmapPageHeight );
  4401. for( bumpID = 0; bumpID < count; bumpID++ )
  4402. {
  4403. // assumes that we are already in ortho mode.
  4404. IMesh* pMesh = pRenderContext->GetDynamicMesh( );
  4405. CMeshBuilder meshBuilder;
  4406. meshBuilder.Begin( pMesh, MATERIAL_LINES, MSurf_VertCount( surfID ) );
  4407. int i;
  4408. for( i = 0; i < MSurf_VertCount( surfID ); i++ )
  4409. {
  4410. float x, y;
  4411. float *texCoord;
  4412. texCoord = &lightCoords[i][bumpID][0];
  4413. x = lightmapPageWidth * texCoord[0];
  4414. y = lightmapPageHeight * texCoord[1];
  4415. meshBuilder.Position3f( x, y, 0.0f );
  4416. meshBuilder.AdvanceVertex();
  4417. texCoord = &lightCoords[(i+1)%MSurf_VertCount( surfID )][bumpID][0];
  4418. x = lightmapPageWidth * texCoord[0];
  4419. y = lightmapPageHeight * texCoord[1];
  4420. meshBuilder.Position3f( x, y, 0.0f );
  4421. meshBuilder.AdvanceVertex();
  4422. }
  4423. meshBuilder.End();
  4424. pMesh->Draw();
  4425. }
  4426. }
  4427. void Shader_DrawLightmapPageChains( IWorldRenderList *pRenderListIn, int pageId )
  4428. {
  4429. CWorldRenderList *pRenderList = assert_cast<CWorldRenderList *>(pRenderListIn);
  4430. for (int j = 0; j < MAX_MAT_SORT_GROUPS; ++j)
  4431. {
  4432. MSL_FOREACH_GROUP_BEGIN( pRenderList->m_SortList, j, group )
  4433. {
  4434. SurfaceHandle_t surfID = pRenderList->m_SortList.GetSurfaceAtHead( group );
  4435. Assert(IS_SURF_VALID(surfID));
  4436. Assert( MSurf_MaterialSortID( surfID ) >= 0 && MSurf_MaterialSortID( surfID ) < g_WorldStaticMeshes.Count() );
  4437. if( materialSortInfoArray[MSurf_MaterialSortID( surfID ) ].lightmapPageID != pageId )
  4438. {
  4439. continue;
  4440. }
  4441. MSL_FOREACH_SURFACE_IN_GROUP_BEGIN( pRenderList->m_SortList, group, surfID )
  4442. {
  4443. Assert( !SurfaceHasDispInfo( surfID ) );
  4444. Shader_DrawLightmapPageSurface( surfID, 0.0f, 1.0f, 0.0f );
  4445. }
  4446. MSL_FOREACH_SURFACE_IN_GROUP_END()
  4447. }
  4448. MSL_FOREACH_GROUP_END()
  4449. // render displacement lightmap page info
  4450. MSL_FOREACH_SURFACE_BEGIN(pRenderList->m_DispSortList, j, surfID)
  4451. {
  4452. surfID->pDispInfo->RenderWireframeInLightmapPage( pageId );
  4453. }
  4454. MSL_FOREACH_SURFACE_END()
  4455. }
  4456. }
  4457. //-----------------------------------------------------------------------------
  4458. //
  4459. // All code related to brush model rendering
  4460. //
  4461. //-----------------------------------------------------------------------------
  4462. class CBrushSurface : public IBrushSurface
  4463. {
  4464. public:
  4465. CBrushSurface( SurfaceHandle_t surfID );
  4466. // Computes texture coordinates + lightmap coordinates given a world position
  4467. virtual void ComputeTextureCoordinate( const Vector& worldPos, Vector2D& texCoord );
  4468. virtual void ComputeLightmapCoordinate( const Vector& worldPos, Vector2D& lightmapCoord );
  4469. // Gets the vertex data for this surface
  4470. virtual int GetVertexCount() const;
  4471. virtual void GetVertexData( BrushVertex_t* pVerts );
  4472. // Gets at the material properties for this surface
  4473. virtual IMaterial* GetMaterial();
  4474. private:
  4475. SurfaceHandle_t m_SurfaceID;
  4476. SurfaceCtx_t m_Ctx;
  4477. };
  4478. //-----------------------------------------------------------------------------
  4479. // Constructor
  4480. //-----------------------------------------------------------------------------
  4481. CBrushSurface::CBrushSurface( SurfaceHandle_t surfID ) : m_SurfaceID(surfID)
  4482. {
  4483. Assert(IS_SURF_VALID(surfID));
  4484. SurfSetupSurfaceContext( m_Ctx, surfID );
  4485. }
  4486. //-----------------------------------------------------------------------------
  4487. // Computes texture coordinates + lightmap coordinates given a world position
  4488. //-----------------------------------------------------------------------------
  4489. void CBrushSurface::ComputeTextureCoordinate( const Vector& worldPos, Vector2D& texCoord )
  4490. {
  4491. SurfComputeTextureCoordinate( m_SurfaceID, worldPos, texCoord.Base() );
  4492. }
  4493. void CBrushSurface::ComputeLightmapCoordinate( const Vector& worldPos, Vector2D& lightmapCoord )
  4494. {
  4495. SurfComputeLightmapCoordinate( m_Ctx, m_SurfaceID, worldPos, lightmapCoord );
  4496. }
  4497. //-----------------------------------------------------------------------------
  4498. // Gets the vertex data for this surface
  4499. //-----------------------------------------------------------------------------
  4500. int CBrushSurface::GetVertexCount() const
  4501. {
  4502. if( !SurfaceHasPrims( m_SurfaceID ) )
  4503. {
  4504. // Create a temporary vertex array for the data...
  4505. return MSurf_VertCount( m_SurfaceID );
  4506. }
  4507. else
  4508. {
  4509. // not implemented yet
  4510. Assert(0);
  4511. return 0;
  4512. }
  4513. }
  4514. void CBrushSurface::GetVertexData( BrushVertex_t* pVerts )
  4515. {
  4516. Assert( pVerts );
  4517. if( !SurfaceHasPrims( m_SurfaceID ) )
  4518. {
  4519. // Fill in the vertex data
  4520. BuildBrushModelVertexArray( host_state.worldbrush, m_SurfaceID, pVerts );
  4521. }
  4522. else
  4523. {
  4524. // not implemented yet
  4525. Assert(0);
  4526. }
  4527. }
  4528. //-----------------------------------------------------------------------------
  4529. // Activates fast z reject for displacements
  4530. //-----------------------------------------------------------------------------
  4531. void R_FastZRejectDisplacements( bool bEnable )
  4532. {
  4533. s_bFastZRejectDisplacements = bEnable;
  4534. }
  4535. //-----------------------------------------------------------------------------
  4536. // Gets at the material properties for this surface
  4537. //-----------------------------------------------------------------------------
  4538. IMaterial* CBrushSurface::GetMaterial()
  4539. {
  4540. return MSurf_TexInfo( m_SurfaceID )->material;
  4541. }
  4542. //-----------------------------------------------------------------------------
  4543. // Installs a client-side renderer for brush models
  4544. //-----------------------------------------------------------------------------
  4545. void R_InstallBrushRenderOverride( IBrushRenderer* pBrushRenderer )
  4546. {
  4547. s_pBrushRenderOverride = pBrushRenderer;
  4548. }
  4549. //-----------------------------------------------------------------------------
  4550. // Here, we allow the client DLL to render brush surfaces however they'd like
  4551. // NOTE: This involves a vertex copy, so don't use this everywhere
  4552. //-----------------------------------------------------------------------------
  4553. bool Shader_DrawBrushSurfaceOverride( IMatRenderContext *pRenderContext, SurfaceHandle_t surfID, IClientEntity *baseentity )
  4554. {
  4555. // Set the lightmap state
  4556. Shader_SetChainLightmapState( pRenderContext, surfID );
  4557. CBrushSurface brushSurface( surfID );
  4558. return s_pBrushRenderOverride->RenderBrushModelSurface( baseentity, &brushSurface );
  4559. }
  4560. //-----------------------------------------------------------------------------
  4561. // Main method to draw brush surfaces
  4562. //-----------------------------------------------------------------------------
  4563. void Shader_BrushSurfaceOverride( IMatRenderContext *pRenderContext, SurfaceHandle_t surfID, model_t *model, IClientEntity *baseentity )
  4564. {
  4565. Assert(s_pBrushRenderOverride);
  4566. bool drawDecals = Shader_DrawBrushSurfaceOverride( pRenderContext, surfID, baseentity );
  4567. // fixme: need to get "allowDecals" from the material
  4568. // if ( g_BrushProperties.allowDecals && pSurf->pdecals )
  4569. if( SurfaceHasDecals( surfID ) && drawDecals )
  4570. {
  4571. DecalSurfaceAdd( surfID, BRUSHMODEL_DECAL_SORT_GROUP );
  4572. }
  4573. // Add overlay fragments to list.
  4574. // FIXME: A little code support is necessary to get overlays working on brush models
  4575. // OverlayMgr()->AddFragmentListToRenderList( MSurf_OverlayFragmentList( surfID ), false );
  4576. // Add shadows too....
  4577. ShadowDecalHandle_t decalHandle = MSurf_ShadowDecals( surfID );
  4578. if (decalHandle != SHADOW_DECAL_HANDLE_INVALID)
  4579. {
  4580. g_pShadowMgr->AddShadowsOnSurfaceToRenderList( decalHandle );
  4581. }
  4582. }
  4583. void R_Surface_LevelInit()
  4584. {
  4585. g_BrushBatchRenderer.LevelInit();
  4586. }
  4587. void R_Surface_LevelShutdown()
  4588. {
  4589. CWorldRenderList::PurgeAll();
  4590. #if defined(_PS3)
  4591. for( int lp = 0; lp < MAX_CONCURRENT_BUILDVIEWS; lp++ )
  4592. {
  4593. g_Pool_PS3[ lp ].Purge();
  4594. }
  4595. #endif
  4596. }
  4597. //-----------------------------------------------------------------------------
  4598. static void R_DrawBrushModel_Override( IMatRenderContext *pRenderContext, IClientEntity *baseentity, model_t *model )
  4599. {
  4600. VPROF( "R_DrawOpaqueBrushModel_Override" );
  4601. SurfaceHandle_t surfID = SurfaceHandleFromIndex( model->brush.firstmodelsurface, model->brush.pShared );
  4602. for (int i=0 ; i<model->brush.nummodelsurfaces ; i++, surfID++)
  4603. {
  4604. Assert( !(MSurf_Flags( surfID ) & SURFDRAW_NODRAW) );
  4605. Shader_BrushSurfaceOverride( pRenderContext, surfID, model, baseentity );
  4606. }
  4607. // now draw debug for each drawn surface
  4608. if ( g_ShaderDebug.anydebug )
  4609. {
  4610. CUtlVector<msurface2_t *> surfaceList;
  4611. surfID = SurfaceHandleFromIndex( model->brush.firstmodelsurface, model->brush.pShared );
  4612. for (int i=0 ; i<model->brush.nummodelsurfaces ; i++, surfID++)
  4613. {
  4614. surfaceList.AddToTail(surfID);
  4615. }
  4616. DrawDebugInformation( pRenderContext, surfaceList.Base(), surfaceList.Count() );
  4617. }
  4618. }
  4619. int R_MarkDlightsOnBrushModel( model_t *model, IClientRenderable *pRenderable )
  4620. {
  4621. int count = 0;
  4622. if ( g_bActiveDlights )
  4623. {
  4624. extern int R_MarkLights (dlight_t *light, int bit, mnode_t *node);
  4625. g_BrushToWorldMatrix.SetupMatrixOrgAngles( pRenderable->GetRenderOrigin(), pRenderable->GetRenderAngles() );
  4626. Vector saveOrigin;
  4627. for (int k=0 ; k<MAX_DLIGHTS ; k++)
  4628. {
  4629. if ((cl_dlights[k].die < GetBaseLocalClient().GetTime()) ||
  4630. (!cl_dlights[k].IsRadiusGreaterThanZero()))
  4631. continue;
  4632. VectorCopy( cl_dlights[k].origin, saveOrigin );
  4633. cl_dlights[k].origin = g_BrushToWorldMatrix.VMul4x3Transpose( saveOrigin );
  4634. mnode_t *node = model->brush.pShared->nodes + model->brush.firstnode;
  4635. if ( IsBoxIntersectingSphereExtents( node->m_vecCenter, node->m_vecHalfDiagonal, cl_dlights[k].origin, cl_dlights[k].GetRadius() ) )
  4636. {
  4637. count += R_MarkLights( &cl_dlights[k], 1<<k, node );
  4638. }
  4639. VectorCopy( saveOrigin, cl_dlights[k].origin );
  4640. }
  4641. if ( count )
  4642. {
  4643. model->flags |= MODELFLAG_HAS_DLIGHT;
  4644. }
  4645. g_BrushToWorldMatrix.Identity();
  4646. }
  4647. return count;
  4648. }
  4649. //-----------------------------------------------------------------------------
  4650. // Stuff to do right before and after brush model rendering
  4651. //-----------------------------------------------------------------------------
  4652. void Shader_BrushBegin( model_t *model, IClientEntity *baseentity /*=NULL*/ )
  4653. {
  4654. // Clear out the render list of decals
  4655. DecalSurfacesInit( true );
  4656. // Clear out the render lists of shadows
  4657. g_pShadowMgr->ClearShadowRenderList( );
  4658. }
  4659. void Shader_BrushEnd( IMatRenderContext *pRenderContext, VMatrix const* pBrushToWorld, model_t *model, bool bShadowDepth, IClientEntity *baseentity /* = NULL */ )
  4660. {
  4661. if ( bShadowDepth )
  4662. return;
  4663. DecalSurfaceDraw( pRenderContext, BRUSHMODEL_DECAL_SORT_GROUP, r_blend );
  4664. // draw the flashlight lighting for the decals on the brush.
  4665. g_pShadowMgr->DrawFlashlightDecals( pRenderContext, BRUSHMODEL_DECAL_SORT_GROUP, false, r_blend );
  4666. // Retire decals on opaque brushmodel surfaces
  4667. R_DecalFlushDestroyList();
  4668. // Draw all shadows on the brush
  4669. g_pShadowMgr->RenderProjectedTextures( pRenderContext, pBrushToWorld );
  4670. }
  4671. CBrushModelTransform::CBrushModelTransform( const Vector &origin, const QAngle &angles, IMatRenderContext *pRenderContext )
  4672. {
  4673. bool rotated = ( angles[0] || angles[1] || angles[2] );
  4674. m_bIdentity = (origin == vec3_origin) && (!rotated);
  4675. // Don't change state if we don't need to
  4676. if (!m_bIdentity)
  4677. {
  4678. m_savedModelorg = modelorg;
  4679. pRenderContext->MatrixMode( MATERIAL_MODEL );
  4680. pRenderContext->PushMatrix();
  4681. g_BrushToWorldMatrix.SetupMatrixOrgAngles( origin, angles );
  4682. pRenderContext->LoadMatrix( g_BrushToWorldMatrix );
  4683. modelorg = g_BrushToWorldMatrix.VMul4x3Transpose(g_EngineRenderer->ViewOrigin());
  4684. }
  4685. }
  4686. CBrushModelTransform::CBrushModelTransform( const matrix3x4a_t &matrix, IMatRenderContext *pRenderContext )
  4687. {
  4688. m_bIdentity = MatrixIsIdentity( matrix );
  4689. // Don't change state if we don't need to
  4690. if (!m_bIdentity)
  4691. {
  4692. m_savedModelorg = modelorg;
  4693. pRenderContext->MatrixMode( MATERIAL_MODEL );
  4694. pRenderContext->PushMatrix();
  4695. g_BrushToWorldMatrix.Init( matrix );
  4696. pRenderContext->LoadMatrix( g_BrushToWorldMatrix );
  4697. modelorg = g_BrushToWorldMatrix.VMul4x3Transpose(g_EngineRenderer->ViewOrigin());
  4698. }
  4699. }
  4700. CBrushModelTransform::~CBrushModelTransform()
  4701. {
  4702. if ( !m_bIdentity )
  4703. {
  4704. CMatRenderContextPtr pRenderContext( materials );
  4705. pRenderContext->MatrixMode( MATERIAL_MODEL );
  4706. pRenderContext->PopMatrix();
  4707. g_BrushToWorldMatrix.Identity();
  4708. modelorg = m_savedModelorg;
  4709. }
  4710. }
  4711. VMatrix *CBrushModelTransform::GetNonIdentityMatrix()
  4712. {
  4713. return m_bIdentity ? NULL : &g_BrushToWorldMatrix;
  4714. }
  4715. //-----------------------------------------------------------------------------
  4716. // Draws debug info for a brush model
  4717. //-----------------------------------------------------------------------------
  4718. void DrawDebugInformation( IMatRenderContext *pRenderContext, const matrix3x4a_t &brushToWorld, SurfaceHandle_t *pList, int listCount )
  4719. {
  4720. CBrushModelTransform transform( brushToWorld, pRenderContext );
  4721. DrawDebugInformation( pRenderContext, pList, listCount );
  4722. }
  4723. //-----------------------------------------------------------------------------
  4724. // Purpose: Draws a brush model using the global shader/surfaceVisitor
  4725. // Input : *e - entity to draw
  4726. // Output : void R_DrawBrushModel
  4727. //-----------------------------------------------------------------------------
  4728. void R_DrawBrushModel( IClientEntity *baseentity, model_t *model,
  4729. const matrix3x4a_t& brushModelToWorld, ERenderDepthMode_t DepthMode, bool bDrawOpaque, bool bDrawTranslucent )
  4730. {
  4731. VPROF( "R_DrawBrushModel" );
  4732. #ifdef USE_CONVARS
  4733. if ( !r_drawbrushmodels.GetInt() )
  4734. {
  4735. return;
  4736. }
  4737. bool bWireframe = false;
  4738. if ( r_drawbrushmodels.GetInt() == 2 )
  4739. {
  4740. // save and override
  4741. bWireframe = g_ShaderDebug.wireframe;
  4742. g_ShaderDebug.wireframe = true;
  4743. g_ShaderDebug.anydebug = true;
  4744. }
  4745. #endif
  4746. CMatRenderContextPtr pRenderContext( materials );
  4747. CBrushModelTransform brushTransform( brushModelToWorld, pRenderContext );
  4748. Assert(model->brush.firstmodelsurface != 0);
  4749. // Draw the puppy...
  4750. Shader_BrushBegin( model, baseentity );
  4751. if ( s_pBrushRenderOverride )
  4752. {
  4753. R_DrawBrushModel_Override( pRenderContext, baseentity, model );
  4754. }
  4755. else
  4756. {
  4757. if ( model->flags & MODELFLAG_TRANSLUCENT )
  4758. {
  4759. if ( DepthMode == DEPTH_MODE_NORMAL )
  4760. {
  4761. g_BrushBatchRenderer.DrawTranslucentBrushModel( pRenderContext, baseentity, model, DEPTH_MODE_NORMAL, bDrawOpaque, bDrawTranslucent );
  4762. }
  4763. }
  4764. else if ( bDrawOpaque )
  4765. {
  4766. g_BrushBatchRenderer.DrawOpaqueBrushModel( pRenderContext, baseentity, model, DepthMode );
  4767. }
  4768. }
  4769. Shader_BrushEnd( pRenderContext, brushTransform.GetNonIdentityMatrix(), model, DepthMode != DEPTH_MODE_NORMAL, baseentity );
  4770. #ifdef USE_CONVARS
  4771. if ( r_drawbrushmodels.GetInt() == 2 )
  4772. {
  4773. // restore
  4774. g_ShaderDebug.wireframe = bWireframe;
  4775. g_ShaderDebug.TestAnyDebug();
  4776. }
  4777. #endif
  4778. }
  4779. void R_DrawBrushModel( IClientEntity *baseentity, model_t *model,
  4780. const Vector& origin, const QAngle& angles, ERenderDepthMode_t DepthMode, bool bDrawOpaque, bool bDrawTranslucent )
  4781. {
  4782. matrix3x4a_t mat;
  4783. AngleMatrix( angles, origin, mat );
  4784. R_DrawBrushModel( baseentity, model, mat, DepthMode, bDrawOpaque, bDrawTranslucent );
  4785. }
  4786. //-----------------------------------------------------------------------------
  4787. // Purpose: Draws a brush model shadow for render-to-texture shadows
  4788. //-----------------------------------------------------------------------------
  4789. void R_DrawBrushModelShadow( IClientRenderable *pRenderable )
  4790. {
  4791. if( !r_drawbrushmodels.GetInt() )
  4792. return;
  4793. model_t *model = (model_t *)pRenderable->GetModel();
  4794. const Vector& origin = pRenderable->GetRenderOrigin();
  4795. QAngle const& angles = pRenderable->GetRenderAngles();
  4796. CMatRenderContextPtr pRenderContext( materials );
  4797. CBrushModelTransform brushTransform( origin, angles, pRenderContext );
  4798. g_BrushBatchRenderer.DrawBrushModelShadow( pRenderContext, model, pRenderable );
  4799. }
  4800. void R_DrawIdentityBrushModel( IWorldRenderList *pRenderListIn, model_t *model )
  4801. {
  4802. if ( !model )
  4803. return;
  4804. CWorldRenderList *pRenderList = assert_cast<CWorldRenderList *>(pRenderListIn);
  4805. SurfaceHandle_t surfID = SurfaceHandleFromIndex( model->brush.firstmodelsurface, model->brush.pShared );
  4806. for (int j=0 ; j<model->brush.nummodelsurfaces ; ++j, surfID++)
  4807. {
  4808. Assert( !(MSurf_Flags( surfID ) & SURFDRAW_NODRAW) );
  4809. // FIXME: Can't insert translucent stuff into the list
  4810. // of translucent surfaces because we don't know what leaf
  4811. // we're in. At the moment, the client doesn't add translucent
  4812. // brushes to the identity brush model list
  4813. // Assert ( (psurf->flags & SURFDRAW_TRANS ) == 0 );
  4814. // OPTIMIZE: Backface cull these guys?!?!?
  4815. if ( MSurf_Flags( surfID ) & SURFDRAW_TRANS)
  4816. // if ( psurf->texinfo->material->IsTranslucent() )
  4817. {
  4818. Shader_TranslucentWorldSurface( pRenderList, surfID );
  4819. }
  4820. else
  4821. {
  4822. Shader_WorldSurface( pRenderList, surfID );
  4823. }
  4824. }
  4825. }
  4826. //-----------------------------------------------------------------------------
  4827. // Draws arrays of brush models
  4828. //-----------------------------------------------------------------------------
  4829. void R_DrawBrushModelArray( IMatRenderContext* pRenderContext, int nCount,
  4830. const BrushArrayInstanceData_t *pInstanceData, int nModelTypeFlags )
  4831. {
  4832. // For now, we don't support translucency, as we can't re-order rendering
  4833. Assert( ( nModelTypeFlags & STUDIO_TRANSPARENCY ) == 0 );
  4834. if ( ( nModelTypeFlags & STUDIO_SHADOWDEPTHTEXTURE ) || ( nModelTypeFlags & STUDIO_SSAODEPTHTEXTURE ) )
  4835. {
  4836. g_BrushBatchRenderer.DrawBrushModelShadowArray( pRenderContext, nCount, pInstanceData, nModelTypeFlags );
  4837. return;
  4838. }
  4839. bool bDrawOpaque = false, bDrawTranslucent = false;
  4840. if ( nModelTypeFlags & STUDIO_TWOPASS )
  4841. {
  4842. bDrawTranslucent = ( nModelTypeFlags & STUDIO_TRANSPARENCY ) != 0;
  4843. bDrawOpaque = !bDrawTranslucent;
  4844. }
  4845. else
  4846. {
  4847. // Can't draw both opaque + translucent
  4848. Assert( 0 );
  4849. }
  4850. g_BrushBatchRenderer.DrawBrushModelArray( pRenderContext, nCount, pInstanceData );
  4851. }
  4852. #endif
  4853. //-----------------------------------------------------------------------------
  4854. // Converts leaf pointer to index
  4855. //-----------------------------------------------------------------------------
  4856. inline int LeafToIndex( mleaf_t* pLeaf )
  4857. {
  4858. return pLeaf - host_state.worldbrush->leafs;
  4859. }
  4860. //-----------------------------------------------------------------------------
  4861. // Structures to help out with enumeration
  4862. //-----------------------------------------------------------------------------
  4863. enum
  4864. {
  4865. // MUST be in upper 16 bits! Lower 16 are used to filter against mnode->flags
  4866. ENUM_SPHERE_TEST_X = 0x10000000,
  4867. ENUM_SPHERE_TEST_Y = 0x20000000,
  4868. ENUM_SPHERE_TEST_Z = 0x40000000,
  4869. ENUM_SPHERE_TEST_ALL = 0x70000000,
  4870. };
  4871. struct EnumLeafSphereInfo_t
  4872. {
  4873. Vector m_vecCenter;
  4874. float m_flRadius;
  4875. Vector m_vecBoxCenter;
  4876. Vector m_vecBoxHalfDiagonal;
  4877. ISpatialLeafEnumerator *m_pIterator;
  4878. intp m_nContext;
  4879. };
  4880. // NOTE: These leaf list routines only return non-solid leaves! Only use them for rendering-related queries!
  4881. #ifdef _X360
  4882. struct ListLeafBoxInfo_t
  4883. {
  4884. VectorAligned m_vecBoxMax;
  4885. VectorAligned m_vecBoxMin;
  4886. VectorAligned m_vecBoxCenter;
  4887. VectorAligned m_vecBoxHalfDiagonal;
  4888. };
  4889. static fltx4 AlignThatVector(const Vector &vc)
  4890. {
  4891. fltx4 out = __loadunalignedvector(vc.Base());
  4892. /*
  4893. out.x = vc.x;
  4894. out.y = vc.y;
  4895. out.z = vc.z;
  4896. */
  4897. // squelch the w component
  4898. return __vrlimi( out, __vzero(), 1, 0 );
  4899. }
  4900. static int ListLeafsInBox( mnode_t * RESTRICT node, ListLeafBoxInfo_t * RESTRICT pInfo, unsigned short * RESTRICT pList, int listMax )
  4901. {
  4902. int leafCount = 0;
  4903. const int NODELIST_MAX = 2048;
  4904. mnode_t *nodeList[NODELIST_MAX];
  4905. int nodeReadIndex = 0;
  4906. int nodeWriteIndex = 0;
  4907. while (1)
  4908. {
  4909. // no polygons in solid nodes (don't report these leaves either)
  4910. if (node->contents >= 0)
  4911. {
  4912. if (node->contents != CONTENTS_SOLID)
  4913. {
  4914. // if a leaf node, report it to the iterator...
  4915. if ( leafCount < listMax )
  4916. {
  4917. pList[leafCount++] = LeafToIndex( (mleaf_t *)node );
  4918. }
  4919. }
  4920. if ( nodeReadIndex == nodeWriteIndex )
  4921. return leafCount;
  4922. node = nodeList[nodeReadIndex];
  4923. nodeReadIndex = (nodeReadIndex+1) & (NODELIST_MAX-1);
  4924. }
  4925. else
  4926. {
  4927. // speculatively get the children into the cache
  4928. PREFETCH_128(node->children[0],0);
  4929. PREFETCH_128(node->children[1],0);
  4930. // constructing these here prevents LHS if we spill.
  4931. // it's not quite a quick enough operation to do extemporaneously.
  4932. fltx4 infoBoxCenter = LoadAlignedSIMD(pInfo->m_vecBoxCenter);
  4933. fltx4 infoBoxHalfDiagonal = LoadAlignedSIMD(pInfo->m_vecBoxHalfDiagonal);
  4934. Assert(IsBoxIntersectingBoxExtents(AlignThatVector(node->m_vecCenter), AlignThatVector(node->m_vecHalfDiagonal),
  4935. LoadAlignedSIMD(pInfo->m_vecBoxCenter), LoadAlignedSIMD(pInfo->m_vecBoxHalfDiagonal)) ==
  4936. IsBoxIntersectingBoxExtents((node->m_vecCenter), node->m_vecHalfDiagonal,
  4937. pInfo->m_vecBoxCenter, pInfo->m_vecBoxHalfDiagonal));
  4938. // rough cull...
  4939. if (IsBoxIntersectingBoxExtents(LoadAlignedSIMD(node->m_vecCenter), LoadAlignedSIMD(node->m_vecHalfDiagonal),
  4940. infoBoxCenter, infoBoxHalfDiagonal))
  4941. {
  4942. // Does the node plane split the box?
  4943. // find which side of the node we are on
  4944. cplane_t* RESTRICT plane = node->plane;
  4945. if ( plane->type <= PLANE_Z )
  4946. {
  4947. if (pInfo->m_vecBoxMax[plane->type] <= plane->dist)
  4948. {
  4949. node = node->children[1];
  4950. }
  4951. else if (pInfo->m_vecBoxMin[plane->type] >= plane->dist)
  4952. {
  4953. node = node->children[0];
  4954. }
  4955. else
  4956. {
  4957. // Here the box is split by the node
  4958. nodeList[nodeWriteIndex] = node->children[0];
  4959. nodeWriteIndex = (nodeWriteIndex+1) & (NODELIST_MAX-1);
  4960. // check for overflow of the ring buffer
  4961. Assert(nodeWriteIndex != nodeReadIndex);
  4962. node = node->children[1];
  4963. }
  4964. }
  4965. else
  4966. {
  4967. // take advantage of high throughput/high latency
  4968. fltx4 planeNormal = LoadUnaligned3SIMD( plane->normal.Base() );
  4969. fltx4 vecBoxMin = LoadAlignedSIMD(pInfo->m_vecBoxMin);
  4970. fltx4 vecBoxMax = LoadAlignedSIMD(pInfo->m_vecBoxMax);
  4971. fltx4 cornermin, cornermax;
  4972. // by now planeNormal is ready...
  4973. fltx4 control = XMVectorGreaterOrEqual( planeNormal, __vzero() );
  4974. // now control[i] = planeNormal[i] > 0 ? 0xFF : 0x00
  4975. cornermin = XMVectorSelect( vecBoxMax, vecBoxMin, control); // cornermin[i] = control[i] ? vecBoxMin[i] : vecBoxMax[i]
  4976. cornermax = XMVectorSelect( vecBoxMin, vecBoxMax, control);
  4977. // compute dot products
  4978. fltx4 dotCornerMax = __vmsum3fp(planeNormal, cornermax); // vsumfp ignores w component
  4979. fltx4 dotCornerMin = __vmsum3fp(planeNormal, cornermin);
  4980. fltx4 vPlaneDist = ReplicateX4(plane->dist);
  4981. UINT conditionRegister;
  4982. XMVectorGreaterR(&conditionRegister,vPlaneDist,dotCornerMax);
  4983. if (XMComparisonAllTrue(conditionRegister)) // plane->normal . cornermax <= plane->dist
  4984. {
  4985. node = node->children[1];
  4986. }
  4987. else
  4988. {
  4989. XMVectorGreaterOrEqualR(&conditionRegister,dotCornerMin,vPlaneDist);
  4990. if ( XMComparisonAllTrue(conditionRegister) )
  4991. {
  4992. node = node->children[0];
  4993. }
  4994. else
  4995. {
  4996. // Here the box is split by the node
  4997. nodeList[nodeWriteIndex] = node->children[0];
  4998. nodeWriteIndex = (nodeWriteIndex+1) & (NODELIST_MAX-1);
  4999. // check for overflow of the ring buffer
  5000. Assert(nodeWriteIndex != nodeReadIndex);
  5001. node = node->children[1];
  5002. }
  5003. }
  5004. }
  5005. }
  5006. else
  5007. {
  5008. if ( nodeReadIndex == nodeWriteIndex )
  5009. return leafCount;
  5010. node = nodeList[nodeReadIndex];
  5011. nodeReadIndex = (nodeReadIndex+1) & (NODELIST_MAX-1);
  5012. }
  5013. }
  5014. }
  5015. }
  5016. #else
  5017. static int ListLeafsInBox( mnode_t * RESTRICT node, const Vector &center, const Vector &extents, unsigned short * RESTRICT pList, int listMax )
  5018. {
  5019. int leafCount = 0;
  5020. const int NODELIST_MAX = 1024;
  5021. mnode_t *nodeList[NODELIST_MAX];
  5022. int nodeReadIndex = 0;
  5023. int nodeWriteIndex = 0;
  5024. while (1)
  5025. {
  5026. if (node->contents >= 0)
  5027. {
  5028. if (node->contents != CONTENTS_SOLID)
  5029. {
  5030. // if a leaf node, report it to the iterator...
  5031. if ( leafCount < listMax )
  5032. {
  5033. pList[leafCount++] = LeafToIndex( (mleaf_t *)node );
  5034. }
  5035. }
  5036. if ( nodeReadIndex == nodeWriteIndex )
  5037. return leafCount;
  5038. node = nodeList[nodeReadIndex];
  5039. nodeReadIndex = (nodeReadIndex+1) & (NODELIST_MAX-1);
  5040. }
  5041. else
  5042. {
  5043. const cplane_t *plane = node->plane;
  5044. // s = BoxOnPlaneSide (leaf_mins, leaf_maxs, plane);
  5045. // s = BOX_ON_PLANE_SIDE(*leaf_mins, *leaf_maxs, plane);
  5046. float d0 = DotProduct( plane->normal, center ) - plane->dist;
  5047. float d1 = DotProductAbs( plane->normal, extents );
  5048. if (d0 >= d1)
  5049. node = node->children[0];
  5050. else if (d0 < -d1)
  5051. node = node->children[1];
  5052. else
  5053. { // go down both
  5054. nodeList[nodeWriteIndex] = node->children[0];
  5055. nodeWriteIndex = (nodeWriteIndex+1) & (NODELIST_MAX-1);
  5056. // check for overflow of the ring buffer
  5057. Assert(nodeWriteIndex != nodeReadIndex);
  5058. node = node->children[1];
  5059. }
  5060. }
  5061. }
  5062. }
  5063. #endif
  5064. //-----------------------------------------------------------------------------
  5065. // Returns all leaves that lie within a spherical volume
  5066. //-----------------------------------------------------------------------------
  5067. template<bool bCheckFlags> bool EnumerateLeafInSphere_R( mnode_t *node, EnumLeafSphereInfo_t& info, int nTestFlags )
  5068. {
  5069. while (true)
  5070. {
  5071. // no polygons in solid nodes (don't report these leaves either)
  5072. if (node->contents == CONTENTS_SOLID)
  5073. return true; // solid
  5074. if (node->contents >= 0)
  5075. {
  5076. // leaf cull...
  5077. // NOTE: using nTestFlags here means that we may be passing in some
  5078. // leaves that don't actually intersect the sphere, but instead intersect
  5079. // the box that surrounds the sphere.
  5080. if (nTestFlags)
  5081. {
  5082. if (!IsBoxIntersectingSphereExtents (node->m_vecCenter, node->m_vecHalfDiagonal, info.m_vecCenter, info.m_flRadius))
  5083. return true;
  5084. }
  5085. // if a leaf node, report it to the iterator...
  5086. return info.m_pIterator->EnumerateLeaf( LeafToIndex( (mleaf_t *)node ), info.m_nContext );
  5087. }
  5088. else if (nTestFlags)
  5089. {
  5090. if (node->contents == -1)
  5091. {
  5092. if ( bCheckFlags )
  5093. {
  5094. if ( ( node->flags & ( nTestFlags ) ) == 0 ) // this is a WORD and
  5095. return true;
  5096. }
  5097. // faster cull...
  5098. if (nTestFlags & ENUM_SPHERE_TEST_X)
  5099. {
  5100. float flDelta = FloatMakePositive( node->m_vecCenter.x - info.m_vecBoxCenter.x );
  5101. float flSize = node->m_vecHalfDiagonal.x + info.m_vecBoxHalfDiagonal.x;
  5102. if ( flDelta > flSize )
  5103. return true;
  5104. // This checks for the node being completely inside the box...
  5105. if ( flDelta + node->m_vecHalfDiagonal.x < info.m_vecBoxHalfDiagonal.x )
  5106. nTestFlags &= ~ENUM_SPHERE_TEST_X;
  5107. }
  5108. if (nTestFlags & ENUM_SPHERE_TEST_Y)
  5109. {
  5110. float flDelta = FloatMakePositive( node->m_vecCenter.y - info.m_vecBoxCenter.y );
  5111. float flSize = node->m_vecHalfDiagonal.y + info.m_vecBoxHalfDiagonal.y;
  5112. if ( flDelta > flSize )
  5113. return true;
  5114. // This checks for the node being completely inside the box...
  5115. if ( flDelta + node->m_vecHalfDiagonal.y < info.m_vecBoxHalfDiagonal.y )
  5116. nTestFlags &= ~ENUM_SPHERE_TEST_Y;
  5117. }
  5118. if (nTestFlags & ENUM_SPHERE_TEST_Z)
  5119. {
  5120. float flDelta = FloatMakePositive( node->m_vecCenter.z - info.m_vecBoxCenter.z );
  5121. float flSize = node->m_vecHalfDiagonal.z + info.m_vecBoxHalfDiagonal.z;
  5122. if ( flDelta > flSize )
  5123. return true;
  5124. if ( flDelta + node->m_vecHalfDiagonal.z < info.m_vecBoxHalfDiagonal.z )
  5125. nTestFlags &= ~ENUM_SPHERE_TEST_Z;
  5126. }
  5127. }
  5128. else if (node->contents == -2)
  5129. {
  5130. // If the box is too small to bother with testing, then blat out the flags
  5131. nTestFlags &= ~( ENUM_SPHERE_TEST_ALL );
  5132. }
  5133. }
  5134. // Does the node plane split the sphere?
  5135. // find which side of the node we are on
  5136. float flNormalDotCenter;
  5137. cplane_t* plane = node->plane;
  5138. if ( plane->type <= PLANE_Z )
  5139. {
  5140. flNormalDotCenter = info.m_vecCenter[plane->type];
  5141. }
  5142. else
  5143. {
  5144. // Here, we've got a plane which is not axis aligned, so we gotta do more work
  5145. flNormalDotCenter = DotProduct( plane->normal, info.m_vecCenter );
  5146. }
  5147. if (flNormalDotCenter + info.m_flRadius <= plane->dist)
  5148. {
  5149. node = node->children[1];
  5150. }
  5151. else if (flNormalDotCenter - info.m_flRadius >= plane->dist)
  5152. {
  5153. node = node->children[0];
  5154. }
  5155. else
  5156. {
  5157. // Here the box is split by the node
  5158. if (!EnumerateLeafInSphere_R<bCheckFlags>( node->children[0], info, nTestFlags ))
  5159. return false;
  5160. node = node->children[1];
  5161. }
  5162. }
  5163. }
  5164. //-----------------------------------------------------------------------------
  5165. // Enumerate leaves along a non-extruded ray
  5166. //-----------------------------------------------------------------------------
  5167. static bool EnumerateLeavesAlongRay_R( mnode_t *node, Ray_t const& ray,
  5168. float start, float end, ISpatialLeafEnumerator* pEnum, intp context )
  5169. {
  5170. // no polygons in solid nodes (don't report these leaves either)
  5171. if (node->contents == CONTENTS_SOLID)
  5172. return true; // solid, keep recursing
  5173. // didn't hit anything
  5174. if (node->contents >= 0)
  5175. {
  5176. // if a leaf node, report it to the iterator...
  5177. return pEnum->EnumerateLeaf( LeafToIndex( (mleaf_t *)node ), context );
  5178. }
  5179. // Determine which side of the node plane our points are on
  5180. cplane_t* plane = node->plane;
  5181. float startDotN,deltaDotN;
  5182. if (plane->type <= PLANE_Z)
  5183. {
  5184. startDotN = ray.m_Start[plane->type];
  5185. deltaDotN = ray.m_Delta[plane->type];
  5186. }
  5187. else
  5188. {
  5189. startDotN = DotProduct( ray.m_Start, plane->normal );
  5190. deltaDotN = DotProduct( ray.m_Delta, plane->normal );
  5191. }
  5192. float front = startDotN + start * deltaDotN - plane->dist;
  5193. float back = startDotN + end * deltaDotN - plane->dist;
  5194. int side = front < 0;
  5195. // If they're both on the same side of the plane, don't bother to split
  5196. // just check the appropriate child
  5197. if ( (back < 0) == side )
  5198. {
  5199. return EnumerateLeavesAlongRay_R (node->children[side], ray, start, end, pEnum, context );
  5200. }
  5201. // calculate mid point
  5202. float frac = front / (front - back);
  5203. float mid = start * (1.0f - frac) + end * frac;
  5204. // go down front side
  5205. bool ok = EnumerateLeavesAlongRay_R (node->children[side], ray, start, mid, pEnum, context );
  5206. if (!ok)
  5207. return ok;
  5208. // go down back side
  5209. return EnumerateLeavesAlongRay_R (node->children[!side], ray, mid, end, pEnum, context );
  5210. }
  5211. //-----------------------------------------------------------------------------
  5212. // Enumerate leaves along a non-extruded ray
  5213. //-----------------------------------------------------------------------------
  5214. static bool EnumerateLeavesAlongExtrudedRay_R( mnode_t *node, Ray_t const& ray,
  5215. float start, float end, ISpatialLeafEnumerator* pEnum, intp context )
  5216. {
  5217. // no polygons in solid nodes (don't report these leaves either)
  5218. if (node->contents == CONTENTS_SOLID)
  5219. return true; // solid, keep recursing
  5220. // didn't hit anything
  5221. if (node->contents >= 0)
  5222. {
  5223. // if a leaf node, report it to the iterator...
  5224. return pEnum->EnumerateLeaf( LeafToIndex( (mleaf_t *)node ), context );
  5225. }
  5226. // Determine which side of the node plane our points are on
  5227. cplane_t* plane = node->plane;
  5228. //
  5229. float t1, t2, offset;
  5230. float startDotN,deltaDotN;
  5231. if (plane->type <= PLANE_Z)
  5232. {
  5233. startDotN = ray.m_Start[plane->type];
  5234. deltaDotN = ray.m_Delta[plane->type];
  5235. offset = ray.m_Extents[plane->type] + DIST_EPSILON;
  5236. }
  5237. else
  5238. {
  5239. startDotN = DotProduct( ray.m_Start, plane->normal );
  5240. deltaDotN = DotProduct( ray.m_Delta, plane->normal );
  5241. offset = fabs(ray.m_Extents[0]*plane->normal[0]) +
  5242. fabs(ray.m_Extents[1]*plane->normal[1]) +
  5243. fabs(ray.m_Extents[2]*plane->normal[2]) + DIST_EPSILON;
  5244. }
  5245. t1 = startDotN + start * deltaDotN - plane->dist;
  5246. t2 = startDotN + end * deltaDotN - plane->dist;
  5247. // If they're both on the same side of the plane (further than the trace
  5248. // extents), don't bother to split, just check the appropriate child
  5249. if (t1 > offset && t2 > offset )
  5250. // if (t1 >= offset && t2 >= offset)
  5251. {
  5252. return EnumerateLeavesAlongExtrudedRay_R( node->children[0], ray,
  5253. start, end, pEnum, context );
  5254. }
  5255. if (t1 < -offset && t2 < -offset)
  5256. {
  5257. return EnumerateLeavesAlongExtrudedRay_R( node->children[1], ray,
  5258. start, end, pEnum, context );
  5259. }
  5260. // For the segment of the line that we are going to use
  5261. // to test against the back side of the plane, we're going
  5262. // to use the part that goes from start to plane + extent
  5263. // (which causes it to extend somewhat into the front halfspace,
  5264. // since plane + extent is in the front halfspace).
  5265. // Similarly, front the segment which tests against the front side,
  5266. // we use the entire front side part of the ray + a portion of the ray that
  5267. // extends by -extents into the back side.
  5268. if (fabs(t1-t2) < DIST_EPSILON)
  5269. {
  5270. // Parallel case, send entire ray to both children...
  5271. bool ret = EnumerateLeavesAlongExtrudedRay_R( node->children[0],
  5272. ray, start, end, pEnum, context );
  5273. if (!ret)
  5274. return false;
  5275. return EnumerateLeavesAlongExtrudedRay_R( node->children[1],
  5276. ray, start, end, pEnum, context );
  5277. }
  5278. // Compute the two fractions...
  5279. // We need one at plane + extent and another at plane - extent.
  5280. // put the crosspoint DIST_EPSILON pixels on the near side
  5281. float idist, frac2, frac;
  5282. int side;
  5283. if (t1 < t2)
  5284. {
  5285. idist = 1.0/(t1-t2);
  5286. side = 1;
  5287. frac2 = (t1 + offset) * idist;
  5288. frac = (t1 - offset) * idist;
  5289. }
  5290. else if (t1 > t2)
  5291. {
  5292. idist = 1.0/(t1-t2);
  5293. side = 0;
  5294. frac2 = (t1 - offset) * idist;
  5295. frac = (t1 + offset) * idist;
  5296. }
  5297. else
  5298. {
  5299. side = 0;
  5300. frac = 1;
  5301. frac2 = 0;
  5302. }
  5303. // move up to the node
  5304. frac = clamp( frac, 0, 1 );
  5305. float midf = start + (end - start)*frac;
  5306. bool ret = EnumerateLeavesAlongExtrudedRay_R( node->children[side], ray, start, midf, pEnum, context );
  5307. if (!ret)
  5308. return ret;
  5309. // go past the node
  5310. frac2 = clamp( frac2, 0, 1 );
  5311. midf = start + (end - start)*frac2;
  5312. return EnumerateLeavesAlongExtrudedRay_R( node->children[!side], ray, midf, end, pEnum, context );
  5313. }
  5314. //-----------------------------------------------------------------------------
  5315. //
  5316. // Helper class to iterate over leaves
  5317. //
  5318. //-----------------------------------------------------------------------------
  5319. class CEngineBSPTree : public IEngineSpatialQuery
  5320. {
  5321. public:
  5322. // Returns the number of leaves
  5323. int LeafCount() const;
  5324. // Enumerates the leaves along a ray, box, etc.
  5325. bool EnumerateLeavesAtPoint( const Vector& pt, ISpatialLeafEnumerator* pEnum, intp context );
  5326. bool EnumerateLeavesInBox( const Vector& mins, const Vector& maxs, ISpatialLeafEnumerator* pEnum, intp context );
  5327. bool EnumerateLeavesInSphere( const Vector& center, float radius, ISpatialLeafEnumerator* pEnum, intp context );
  5328. bool EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, intp context );
  5329. bool EnumerateLeavesInSphereWithFlagSet( const Vector& center, float radius, ISpatialLeafEnumerator* pEnum, intp context, int nFlags );
  5330. int ListLeavesInBox( const Vector& mins, const Vector& maxs, unsigned short *pList, int listMax );
  5331. int ListLeavesInSphereWithFlagSet( int *pLeafsInSphere, const Vector& vecCenter, float flRadius, int nLeafCount, const uint16 *pLeafs, int nLeafStride, int nFlagsCheck );
  5332. };
  5333. //-----------------------------------------------------------------------------
  5334. // Singleton accessor
  5335. //-----------------------------------------------------------------------------
  5336. static CEngineBSPTree s_ToolBSPTree;
  5337. IEngineSpatialQuery* g_pToolBSPTree = &s_ToolBSPTree;
  5338. //-----------------------------------------------------------------------------
  5339. // Returns the number of leaves
  5340. //-----------------------------------------------------------------------------
  5341. int CEngineBSPTree::LeafCount() const
  5342. {
  5343. return host_state.worldbrush->numleafs;
  5344. }
  5345. //-----------------------------------------------------------------------------
  5346. // Enumerates the leaves at a point
  5347. //-----------------------------------------------------------------------------
  5348. bool CEngineBSPTree::EnumerateLeavesAtPoint( const Vector& pt,
  5349. ISpatialLeafEnumerator* pEnum, intp context )
  5350. {
  5351. int leaf = CM_PointLeafnum( pt );
  5352. return pEnum->EnumerateLeaf( leaf, context );
  5353. }
  5354. int CEngineBSPTree::ListLeavesInBox( const Vector& mins, const Vector& maxs, unsigned short *pList, int listMax )
  5355. {
  5356. #ifdef _X360
  5357. ListLeafBoxInfo_t info;
  5358. VectorAdd( mins, maxs, info.m_vecBoxCenter );
  5359. info.m_vecBoxCenter *= 0.5f;
  5360. VectorSubtract( maxs, info.m_vecBoxCenter, info.m_vecBoxHalfDiagonal );
  5361. info.m_vecBoxMax = maxs;
  5362. info.m_vecBoxMin = mins;
  5363. return ListLeafsInBox( host_state.worldbrush->nodes, &info, pList, listMax );
  5364. #else
  5365. Vector center, extents;
  5366. VectorAdd(mins, maxs, center );
  5367. center *= 0.5f;
  5368. VectorSubtract(maxs, center, extents);
  5369. return ListLeafsInBox( host_state.worldbrush->nodes, center, extents, pList, listMax );
  5370. #endif
  5371. }
  5372. int CEngineBSPTree::ListLeavesInSphereWithFlagSet( int *pLeafsInSphere, const Vector& vecCenter, float flRadius, int nLeafCount, const uint16 *pLeafs, int nLeafStride, int nFlagsCheck )
  5373. {
  5374. int nLeavesFound = 0;
  5375. const uint16 *pLeaf = pLeafs;
  5376. for ( int i = 0; i < nLeafCount; ++i, pLeaf = (const uint16*)( (const uint8*)pLeaf + nLeafStride ) )
  5377. {
  5378. mleaf_t& leaf = host_state.worldbrush->leafs[ *pLeaf ];
  5379. if ( ( leaf.flags & nFlagsCheck ) == 0 )
  5380. continue;
  5381. if ( !IsBoxIntersectingSphereExtents( leaf.m_vecCenter, leaf.m_vecHalfDiagonal, vecCenter, flRadius ) )
  5382. continue;
  5383. pLeafsInSphere[nLeavesFound++] = i;
  5384. }
  5385. return nLeavesFound;
  5386. }
  5387. bool CEngineBSPTree::EnumerateLeavesInBox( const Vector& mins, const Vector& maxs,
  5388. ISpatialLeafEnumerator* pEnum, intp context )
  5389. {
  5390. if ( !host_state.worldmodel )
  5391. return false;
  5392. unsigned short list[1024];
  5393. int count = ListLeavesInBox( mins, maxs, list, ARRAYSIZE(list) );
  5394. for ( int i = 0; i < count; i++ )
  5395. {
  5396. if ( !pEnum->EnumerateLeaf(list[i], context) )
  5397. break;
  5398. }
  5399. return true;
  5400. }
  5401. bool CEngineBSPTree::EnumerateLeavesInSphere( const Vector& center, float radius,
  5402. ISpatialLeafEnumerator* pEnum, intp context )
  5403. {
  5404. EnumLeafSphereInfo_t info;
  5405. info.m_vecCenter = center;
  5406. info.m_flRadius = radius;
  5407. info.m_pIterator = pEnum;
  5408. info.m_nContext = context;
  5409. info.m_vecBoxCenter = center;
  5410. info.m_vecBoxHalfDiagonal.Init( radius, radius, radius );
  5411. return EnumerateLeafInSphere_R<false>( host_state.worldbrush->nodes, info, ENUM_SPHERE_TEST_ALL );
  5412. }
  5413. bool CEngineBSPTree::EnumerateLeavesInSphereWithFlagSet( const Vector& center, float radius,
  5414. ISpatialLeafEnumerator* pEnum,
  5415. intp context, int nFlags )
  5416. {
  5417. EnumLeafSphereInfo_t info;
  5418. info.m_vecCenter = center;
  5419. info.m_flRadius = radius;
  5420. info.m_pIterator = pEnum;
  5421. info.m_nContext = context;
  5422. info.m_vecBoxCenter = center;
  5423. info.m_vecBoxHalfDiagonal.Init( radius, radius, radius );
  5424. return EnumerateLeafInSphere_R<true>(
  5425. host_state.worldbrush->nodes, info, nFlags | ENUM_SPHERE_TEST_ALL );
  5426. }
  5427. bool CEngineBSPTree::EnumerateLeavesAlongRay( Ray_t const& ray, ISpatialLeafEnumerator* pEnum, intp context )
  5428. {
  5429. if (!ray.m_IsSwept)
  5430. {
  5431. Vector mins, maxs;
  5432. VectorAdd( ray.m_Start, ray.m_Extents, maxs );
  5433. VectorSubtract( ray.m_Start, ray.m_Extents, mins );
  5434. return EnumerateLeavesInBox( mins, maxs, pEnum, context );
  5435. }
  5436. Vector end;
  5437. VectorAdd( ray.m_Start, ray.m_Delta, end );
  5438. if ( ray.m_IsRay )
  5439. {
  5440. return EnumerateLeavesAlongRay_R( host_state.worldbrush->nodes, ray, 0.0f, 1.0f, pEnum, context );
  5441. }
  5442. else
  5443. {
  5444. return EnumerateLeavesAlongExtrudedRay_R( host_state.worldbrush->nodes, ray, 0.0f, 1.0f, pEnum, context );
  5445. }
  5446. }