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.

3755 lines
128 KiB

  1. //===== Copyright 1996-2007, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $Revision: $
  6. // $NoKeywords: $
  7. //
  8. // This file contains code to allow us to associate client data with bsp leaves.
  9. //===========================================================================//
  10. #include "cbase.h"
  11. #include "clientleafsystem.h"
  12. #include "utlbidirectionalset.h"
  13. #include "model_types.h"
  14. #include "ivrenderview.h"
  15. #include "tier0/vprof.h"
  16. #include "bsptreedata.h"
  17. #include "detailobjectsystem.h"
  18. #include "engine/IStaticPropMgr.h"
  19. #include "engine/ivdebugoverlay.h"
  20. #include "vstdlib/jobthread.h"
  21. #include "tier1/utllinkedlist.h"
  22. #include "datacache/imdlcache.h"
  23. #include "view.h"
  24. #include "viewrender.h"
  25. #include "clientalphaproperty.h"
  26. #include "con_nprint.h"
  27. #include "collisionutils.h"
  28. #include "cache_hints.h"
  29. #include "mathlib/volumeculler.h"
  30. #include "iinput.h"
  31. #if defined(_PS3)
  32. #include "ps3/spu_job_shared.h"
  33. #include "buildrenderables_PS3.h"
  34. #endif
  35. #ifdef PORTAL
  36. #include "portalrender.h"
  37. #endif
  38. //#include "tier0/miniprofiler.h"
  39. // memdbgon must be the last include file in a .cpp file!!!
  40. #include "tier0/memdbgon.h"
  41. class VMatrix; // forward decl
  42. //extern LinkedMiniProfiler *g_pMiniProfilers;
  43. //LinkedMiniProfiler g_mpRecomputeLeaves("CClientLeafSystem::RecomputeRenderableLeaves", &g_pMiniProfilers);
  44. //LinkedMiniProfiler g_mpComputeBounds("CClientLeafSystem::ComputeBounds", &g_pMiniProfilers);
  45. static ConVar cl_drawleaf("cl_drawleaf", "-1", FCVAR_CHEAT );
  46. static ConVar r_PortalTestEnts( "r_PortalTestEnts", "1", FCVAR_CHEAT, "Clip entities against portal frustums." );
  47. static ConVar r_portalsopenall( "r_portalsopenall", "0", FCVAR_CHEAT, "Open all portals" );
  48. static ConVar r_shadows_on_renderables_enable( "r_shadows_on_renderables_enable", "0", 0, "Support casting RTT shadows onto other renderables" );
  49. static ConVar cl_leafsystemvis( "cl_leafsystemvis", "0", FCVAR_CHEAT );
  50. static ConVar r_alphafade_usefov( "r_alphafade_usefov", "1", FCVAR_CHEAT, "Account for FOV when computing an entity's distance-based alpha fade" );
  51. #if defined(_PS3)
  52. ConVar r_PS3_SPU_buildrenderables("r_PS3_SPU_buildrenderables", "1");
  53. ConVar r_PS3_SPU_BuildWRLists_ImmediateSync("r_PS3_SPU_BuildWRLists_ImmediateSync", "0");
  54. // temp - debugging
  55. ConVar r_PS3_SPU_BuildR_VolR("r_PS3_SPU_BuildR_VolR", "1");
  56. #endif
  57. extern ConVar cl_csm_disable_culling;
  58. extern ConVar cl_csm_shadows;
  59. extern ConVar cl_csm_entity_shadows;
  60. extern ConVar cl_csm_static_prop_shadows;
  61. extern ConVar cl_csm_sprite_shadows;
  62. extern ConVar cl_csm_ignore_disable_shadow_depth_rendering;
  63. extern ConVar cl_csm_optimize_static_props;
  64. DEFINE_FIXEDSIZE_ALLOCATOR( CClientRenderablesList, 1, CUtlMemoryPool::GROW_SLOW );
  65. //-----------------------------------------------------------------------------
  66. // Threading helpers
  67. //-----------------------------------------------------------------------------
  68. static void FrameLock()
  69. {
  70. mdlcache->BeginLock();
  71. }
  72. static void FrameUnlock()
  73. {
  74. mdlcache->EndLock();
  75. }
  76. //-----------------------------------------------------------------------------
  77. // The client leaf system
  78. //-----------------------------------------------------------------------------
  79. class CClientLeafSystem : public IClientLeafSystem, public ISpatialLeafEnumerator, public IClientAlphaPropertyMgr
  80. {
  81. public:
  82. virtual char const *Name() { return "CClientLeafSystem"; }
  83. // constructor, destructor
  84. CClientLeafSystem();
  85. virtual ~CClientLeafSystem();
  86. // Methods of IClientSystem
  87. bool Init() { return true; }
  88. void PostInit() {}
  89. void Shutdown() {}
  90. virtual bool IsPerFrame() { return true; }
  91. void PreRender();
  92. void PostRender() { }
  93. void Update( float frametime ) { m_nDebugIndex = 0; }
  94. // Diagnostic function to identify translucent objects
  95. void HighlightAllTranslucentRenderables();
  96. void LevelInitPreEntity();
  97. void LevelInitPostEntity() {}
  98. void LevelShutdownPreEntity();
  99. void LevelShutdownPostEntity();
  100. virtual void OnSave() {}
  101. virtual void OnRestore() {}
  102. virtual void SafeRemoveIfDesired() {}
  103. // Methods of IClientAlphaPropertyMgr
  104. public:
  105. virtual IClientAlphaProperty *CreateClientAlphaProperty( IClientUnknown *pUnknown );
  106. virtual void DestroyClientAlphaProperty( IClientAlphaProperty *pAlphaProperty );
  107. // Methods of IClientLeafSystem
  108. public:
  109. virtual void AddRenderable( IClientRenderable* pRenderable, bool bRenderWithViewModels, RenderableTranslucencyType_t nType, RenderableModelType_t nModelType, uint32 nSplitscreenEnabledFlags );
  110. virtual bool IsRenderableInPVS( IClientRenderable *pRenderable );
  111. virtual void CreateRenderableHandle( IClientRenderable* pRenderable, bool bRenderWithViewModels, RenderableTranslucencyType_t nType, RenderableModelType_t nModelType, uint32 nSplitscreenEnabled );
  112. virtual void RemoveRenderable( ClientRenderHandle_t handle );
  113. virtual void SetSubSystemDataInLeaf( int leaf, int nSubSystemIdx, CClientLeafSubSystemData *pData );
  114. virtual CClientLeafSubSystemData *GetSubSystemDataInLeaf( int leaf, int nSubSystemIdx );
  115. // FIXME: There's an incestuous relationship between DetailObjectSystem
  116. // and the ClientLeafSystem. Maybe they should be the same system?
  117. virtual void GetDetailObjectsInLeaf( int leaf, int& firstDetailObject, int& detailObjectCount );
  118. virtual void SetDetailObjectsInLeaf( int leaf, int firstDetailObject, int detailObjectCount );
  119. virtual void DrawDetailObjectsInLeaf( int leaf, int frameNumber, int& nFirstDetailObject, int& nDetailObjectCount );
  120. virtual bool ShouldDrawDetailObjectsInLeaf( int leaf, int frameNumber );
  121. virtual void RenderableChanged( ClientRenderHandle_t handle );
  122. virtual void CollateViewModelRenderables( CViewModelRenderablesList *pList );
  123. virtual void BuildRenderablesList( const SetupRenderInfo_t &info );
  124. #if defined(_PS3)
  125. virtual void BuildRenderablesList_PS3_Epilogue( void );
  126. #endif
  127. virtual void DrawStaticProps( bool enable );
  128. virtual void DrawSmallEntities( bool enable );
  129. virtual void EnableForceOpaquePass( ClientRenderHandle_t handle, bool bEnable );
  130. virtual bool IsEnableForceOpaquePass( ClientRenderHandle_t handle ) const;
  131. virtual void EnableAlternateSorting( ClientRenderHandle_t handle, bool bEnable );
  132. virtual void RenderWithViewModels( ClientRenderHandle_t handle, bool bEnable );
  133. virtual bool IsRenderingWithViewModels( ClientRenderHandle_t handle ) const;
  134. virtual void SetTranslucencyType( ClientRenderHandle_t handle, RenderableTranslucencyType_t nType );
  135. virtual RenderableTranslucencyType_t GetTranslucencyType( ClientRenderHandle_t handle ) const;
  136. virtual void SetModelType( ClientRenderHandle_t handle, RenderableModelType_t nType );
  137. virtual void EnableSplitscreenRendering( ClientRenderHandle_t handle, uint32 nFlags );
  138. virtual void EnableRendering( ClientRenderHandle_t handle, bool bEnable );
  139. virtual void EnableBloatedBounds( ClientRenderHandle_t handle, bool bEnable );
  140. virtual void DisableCachedRenderBounds( ClientRenderHandle_t handle, bool bDisable );
  141. virtual void RenderInFastReflections( ClientRenderHandle_t handle, bool bRenderInFastReflections );
  142. virtual bool IsRenderingInFastReflections( ClientRenderHandle_t handle ) const;
  143. virtual void DisableShadowDepthRendering( ClientRenderHandle_t handle, bool bDisable );
  144. virtual void DisableCSMRendering( ClientRenderHandle_t handle, bool bDisable );
  145. virtual void DisableShadowDepthCaching( ClientRenderHandle_t handle, bool bDisable );
  146. // Adds a renderable to a set of leaves
  147. virtual void AddRenderableToLeaves( ClientRenderHandle_t handle, int nLeafCount, unsigned short *pLeaves );
  148. void AddRenderableToLeaves( ClientRenderHandle_t handle, int nLeafCount, unsigned short *pLeaves, bool bReceiveShadows );
  149. // The following methods are related to shadows...
  150. virtual ClientLeafShadowHandle_t AddShadow( ClientShadowHandle_t userId, unsigned short flags );
  151. virtual void RemoveShadow( ClientLeafShadowHandle_t h );
  152. virtual void ProjectShadow( ClientLeafShadowHandle_t handle, int nLeafCount, const int *pLeafList );
  153. virtual void ProjectFlashlight( ClientLeafShadowHandle_t handle, int nLeafCount, const int *pLeafList );
  154. // Find all shadow casters in a set of leaves
  155. virtual void EnumerateShadowsInLeaves( int leafCount, WorldListLeafData_t* pLeaves, IClientLeafShadowEnum* pEnum );
  156. virtual void RecomputeRenderableLeaves();
  157. virtual void DisableLeafReinsertion( bool bDisable );
  158. //Assuming the renderable would be in a properly built render list, generate a render list entry
  159. virtual RenderGroup_t GenerateRenderListEntry( IClientRenderable *pRenderable, CClientRenderablesList::CEntry &entryOut );
  160. // Get renderable that render bound intersect with the query box
  161. virtual int GetEntitiesInBox( C_BaseEntity **pEntityList, int listMax, const Vector& vWorldSpaceMins, const Vector& vWorldSpaceMaxs );
  162. virtual void ComputeAllBounds( void );
  163. // methods of ISpatialLeafEnumerator
  164. public:
  165. bool EnumerateLeaf( int leaf, intp context );
  166. // Adds a shadow to a leaf
  167. void AddShadowToLeaf( int leaf, ClientLeafShadowHandle_t handle, bool bFlashlight );
  168. // Fill in a list of the leaves this renderable is in.
  169. // Returns -1 if the handle is invalid.
  170. int GetRenderableLeaves( ClientRenderHandle_t handle, int leaves[128] );
  171. // Get leaves this renderable is in
  172. virtual bool GetRenderableLeaf ( ClientRenderHandle_t handle, int* pOutLeaf, const int* pInIterator = 0, int* pOutIterator = 0 );
  173. // Singleton instance...
  174. static CClientLeafSystem s_ClientLeafSystem;
  175. private:
  176. enum
  177. {
  178. RENDER_FLAGS_DISABLE_RENDERING = 0x01,
  179. RENDER_FLAGS_HASCHANGED = 0x02,
  180. RENDER_FLAGS_ALTERNATE_SORTING = 0x04,
  181. RENDER_FLAGS_RENDER_WITH_VIEWMODELS = 0x08,
  182. RENDER_FLAGS_BLOAT_BOUNDS = 0x10,
  183. RENDER_FLAGS_BOUNDS_VALID = 0x20,
  184. RENDER_FLAGS_BOUNDS_ALWAYS_RECOMPUTE = 0x40,
  185. RENDER_FLAGS_IS_SPRITE = 0x80,
  186. RENDER_FLAGS_FORCE_OPAQUE_PASS = 0x100,
  187. };
  188. #if defined(_PS3) // to ease SPU job
  189. public:
  190. #endif
  191. // All the information associated with a particular handle
  192. struct RenderableInfo_t
  193. {
  194. IClientRenderable* m_pRenderable;
  195. CClientAlphaProperty *m_pAlphaProperty;
  196. int m_EnumCount; // Have I been added to a particular shadow yet?
  197. int m_nRenderFrame;
  198. unsigned short m_FirstShadow; // The first shadow caster that cast on it
  199. unsigned short m_LeafList; // What leafs is it in?
  200. short m_Area; // -1 if the renderable spans multiple areas.
  201. uint16 m_Flags; // rendering flags
  202. uint16 m_bRenderInFastReflection : 1; // Should we render in the "fast" reflection?
  203. uint16 m_bDisableShadowDepthRendering : 1; // Should we not render into the shadow depth map?
  204. uint16 m_bDisableCSMRendering : 1; // Should we not render into the CSM?
  205. uint16 m_bDisableShadowDepthCaching : 1; // Should we not be cached in the shadow depth map?
  206. uint16 m_nSplitscreenEnabled : 2; // splitscreen rendering flags
  207. uint16 m_nTranslucencyType : 2; // RenderableTranslucencyType_t
  208. uint16 m_nModelType : 8; // RenderableModelType_t
  209. Vector m_vecBloatedAbsMins; // Use this for tree insertion
  210. Vector m_vecBloatedAbsMaxs;
  211. Vector m_vecAbsMins; // NOTE: These members are not threadsafe!!
  212. Vector m_vecAbsMaxs; // They can be updated from any viewpoint (based on RENDER_FLAGS_BOUNDS_VALID)
  213. };
  214. #if defined(_PS3)
  215. private:
  216. #endif
  217. // The leaf contains an index into a list of renderables
  218. struct ClientLeaf_t
  219. {
  220. unsigned short m_FirstElement;
  221. unsigned short m_FirstShadow;
  222. unsigned short m_FirstDetailProp;
  223. unsigned short m_DetailPropCount;
  224. int m_DetailPropRenderFrame;
  225. CClientLeafSubSystemData *m_pSubSystemData[N_CLSUBSYSTEMS];
  226. };
  227. // Shadow information
  228. struct ShadowInfo_t
  229. {
  230. unsigned short m_FirstLeaf;
  231. unsigned short m_FirstRenderable;
  232. int m_EnumCount;
  233. ClientShadowHandle_t m_Shadow;
  234. unsigned short m_Flags;
  235. };
  236. struct EnumResult_t
  237. {
  238. int leaf;
  239. EnumResult_t *pNext;
  240. };
  241. struct EnumResultList_t
  242. {
  243. EnumResult_t *pHead;
  244. ClientRenderHandle_t handle;
  245. };
  246. #if defined(_PS3) // to ease SPU job
  247. public:
  248. #endif
  249. struct BuildRenderListInfo_t
  250. {
  251. Vector m_vecMins;
  252. Vector m_vecMaxs;
  253. short m_nArea;
  254. uint8 m_nAlpha;
  255. bool m_bPerformOcclusionTest : 1;
  256. bool m_bIgnoreZBuffer : 1;
  257. };
  258. #if defined(_PS3)
  259. private:
  260. #endif
  261. struct AlphaInfo_t
  262. {
  263. CClientAlphaProperty *m_pAlphaProperty;
  264. Vector m_vecCenter;
  265. float m_flRadius;
  266. float m_flFadeFactor;
  267. };
  268. private:
  269. // Adds a renderable to the list of renderables
  270. void AddRenderableToLeaf( int leaf, ClientRenderHandle_t handle, bool bReceiveShadows );
  271. void SortEntities( const Vector &vecRenderOrigin, const Vector &vecRenderForward, CClientRenderablesList::CEntry *pEntities, BuildRenderListInfo_t **pTranslucentRLInfo, int nEntities );
  272. // Returns -1 if the renderable spans more than one area. If it's totally in one area, then this returns the leaf.
  273. short GetRenderableArea( ClientRenderHandle_t handle );
  274. // remove renderables from leaves
  275. void RemoveFromTree( ClientRenderHandle_t handle );
  276. void InsertIntoTree( ClientRenderHandle_t &handle, const Vector &absMins, const Vector &absMaxs );
  277. // Adds, removes renderables from view model list
  278. void AddToViewModelList( ClientRenderHandle_t handle );
  279. void RemoveFromViewModelList( ClientRenderHandle_t handle );
  280. // Insert translucent renderables into list of translucent objects
  281. void InsertTranslucentRenderable( IClientRenderable* pRenderable,
  282. int& count, IClientRenderable** pList, float* pDist );
  283. // Adds a shadow to a leaf/removes shadow from renderable
  284. void AddShadowToRenderable( ClientRenderHandle_t renderHandle, ClientLeafShadowHandle_t shadowHandle );
  285. void RemoveShadowFromRenderables( ClientLeafShadowHandle_t handle );
  286. // Adds a shadow to a leaf/removes shadow from renderable
  287. bool ShouldRenderableReceiveShadow( ClientRenderHandle_t renderHandle, int nShadowFlags );
  288. // Adds a shadow to a leaf/removes shadow from leaf
  289. void RemoveShadowFromLeaves( ClientLeafShadowHandle_t handle );
  290. // Methods related to renderable list building
  291. void BuildRenderablesListForFastReflections( const SetupRenderInfo_t &info );
  292. #if defined(_PS3)
  293. void BuildRenderablesList_SPURSJob( const SetupRenderInfo_t &info,
  294. RenderableInfo_t **ppEA_Renderables, int *pEA_RenderablesCount,
  295. DetailRenderableInfo_t *pEA_DetailRenderables, int *pEA_DetailRenderablesCount,
  296. BuildRenderListInfo_t *pEA_RLInfo );
  297. virtual void PrepRenderablesListForSPU( void );
  298. #endif
  299. void BuildRenderablesListForCSMView( const SetupRenderInfo_t &info );
  300. int ExtractStaticProps( int nCount, RenderableInfo_t **ppRenderables );
  301. int ExtractSplitscreenRenderables( int nCount, RenderableInfo_t **ppRenderables );
  302. int ExtractNonFastReflectedRenderables( int nCount, RenderableInfo_t **ppRenderables );
  303. int ExtractTranslucentRenderables( int nCount, RenderableInfo_t **ppRenderables );
  304. int ExtractDuplicates( int nFrameNumber, int nCount, RenderableInfo_t **ppRenderables );
  305. int ExtractDisableShadowDepthRenderables( int nCount, RenderableInfo_t **ppRenderables );
  306. int ExtractDisableShadowDepthCacheRenderables( int nCount, RenderableInfo_t **ppRenderables );
  307. void ComputeBounds( int nCount, RenderableInfo_t **ppRenderables, BuildRenderListInfo_t *pRLInfo );
  308. int ExtractCulledRenderables( int nCount, RenderableInfo_t **ppRenderables, BuildRenderListInfo_t *pRLInfo, Frustum_t** ppFrustumList );
  309. int ExtractOccludedRenderables( int occlusionViewId, int nCount, RenderableInfo_t **ppRenderables, BuildRenderListInfo_t *pRLInfo );
  310. void AddRenderablesToRenderLists( const SetupRenderInfo_t &info, int nCount, RenderableInfo_t **ppRenderables, BuildRenderListInfo_t *pRLInfo, int nDetailCount, DetailRenderableInfo_t *pDetailInfo );
  311. void AddDependentRenderables( const SetupRenderInfo_t &info );
  312. int ComputeTranslucency( int nFrameNumber, int nViewID, int nCount, RenderableInfo_t **ppRenderables, BuildRenderListInfo_t *pRLInfo, const ScreenSizeComputeInfo_t &screenSizeInfo, const Vector& vecViewOrigin );
  313. void ComputeDistanceFade( int nCount, AlphaInfo_t *pAlphaInfo, BuildRenderListInfo_t *pRLInfo, float flDistScale, const Vector& vecViewOrigin );
  314. void ComputeScreenFade( const ScreenSizeComputeInfo_t &info, float flMinScreenWidth, float flMaxScreenWidth, int nCount, AlphaInfo_t *pAlphaInfo );
  315. void CalcRenderableWorldSpaceAABB_Bloated( const RenderableInfo_t &info, Vector &absMin, Vector &absMax );
  316. // Methods associated with the various bi-directional sets
  317. static unsigned short& FirstRenderableInLeaf( int leaf )
  318. {
  319. return s_ClientLeafSystem.m_Leaf[leaf].m_FirstElement;
  320. }
  321. static unsigned short& FirstLeafInRenderable( unsigned short renderable )
  322. {
  323. return s_ClientLeafSystem.m_Renderables[renderable].m_LeafList;
  324. }
  325. static unsigned short& FirstShadowInLeaf( int leaf )
  326. {
  327. return s_ClientLeafSystem.m_Leaf[leaf].m_FirstShadow;
  328. }
  329. static unsigned short& FirstLeafInShadow( ClientLeafShadowHandle_t shadow )
  330. {
  331. return s_ClientLeafSystem.m_Shadows[shadow].m_FirstLeaf;
  332. }
  333. static unsigned short& FirstShadowOnRenderable( unsigned short renderable )
  334. {
  335. return s_ClientLeafSystem.m_Renderables[renderable].m_FirstShadow;
  336. }
  337. static unsigned short& FirstRenderableInShadow( ClientLeafShadowHandle_t shadow )
  338. {
  339. return s_ClientLeafSystem.m_Shadows[shadow].m_FirstRenderable;
  340. }
  341. void FrameLock()
  342. {
  343. mdlcache->BeginLock();
  344. }
  345. void FrameUnlock()
  346. {
  347. mdlcache->EndLock();
  348. }
  349. // Stores data associated with each leaf.
  350. CUtlVector< ClientLeaf_t > m_Leaf;
  351. // Stores all unique non-detail renderables
  352. CUtlLinkedList< RenderableInfo_t, ClientRenderHandle_t, false, unsigned int > m_Renderables;
  353. // Information associated with shadows registered with the client leaf system
  354. CUtlLinkedList< ShadowInfo_t, ClientLeafShadowHandle_t, false, unsigned int > m_Shadows;
  355. // Maintains the list of all renderables in a particular leaf
  356. CBidirectionalSet< int, ClientRenderHandle_t, unsigned short, unsigned int > m_RenderablesInLeaf;
  357. // Maintains a list of all shadows in a particular leaf
  358. CBidirectionalSet< int, ClientLeafShadowHandle_t, unsigned short, unsigned int > m_ShadowsInLeaf;
  359. // Maintains a list of all shadows cast on a particular renderable
  360. CBidirectionalSet< ClientRenderHandle_t, ClientLeafShadowHandle_t, unsigned short, unsigned int > m_ShadowsOnRenderable;
  361. // Dirty list of renderables
  362. CUtlVector< ClientRenderHandle_t > m_DirtyRenderables;
  363. // List of renderables in view model render groups
  364. CUtlVector< ClientRenderHandle_t > m_ViewModels;
  365. // Should I draw static props?
  366. bool m_DrawStaticProps;
  367. bool m_DrawSmallObjects;
  368. bool m_bDisableLeafReinsertion;
  369. // A little enumerator to help us when adding shadows to renderables
  370. int m_ShadowEnum;
  371. // Does anything use alternate sorting?
  372. int m_nAlternateSortCount;
  373. // Does anything disable shadow depth
  374. int m_nDisableShadowDepthCount;
  375. // Does anything disable shadow depth cache
  376. int m_nDisableShadowDepthCacheCount;
  377. // Number of alpha properties out there
  378. int m_nAlphaPropertyCount;
  379. CUtlMemoryPool m_AlphaPropertyPool;
  380. int m_nDebugIndex;
  381. CThreadFastMutex m_DirtyRenderablesMutex;
  382. };
  383. //-----------------------------------------------------------------------------
  384. // Methods of IClientAlphaPropertyMgr
  385. //-----------------------------------------------------------------------------
  386. IClientAlphaProperty *CClientLeafSystem::CreateClientAlphaProperty( IClientUnknown *pUnk )
  387. {
  388. ++m_nAlphaPropertyCount;
  389. CClientAlphaProperty *pProperty = (CClientAlphaProperty*)m_AlphaPropertyPool.Alloc( sizeof(CClientAlphaProperty) );
  390. Construct( pProperty );
  391. pProperty->Init( pUnk );
  392. return pProperty;
  393. }
  394. void CClientLeafSystem::DestroyClientAlphaProperty( IClientAlphaProperty *pAlphaProperty )
  395. {
  396. if ( !pAlphaProperty )
  397. return;
  398. Destruct( static_cast<CClientAlphaProperty*>( pAlphaProperty ) );
  399. m_AlphaPropertyPool.Free( pAlphaProperty );
  400. Assert( m_nAlphaPropertyCount > 0 );
  401. if ( --m_nAlphaPropertyCount == 0 )
  402. {
  403. m_AlphaPropertyPool.Clear();
  404. }
  405. }
  406. //-----------------------------------------------------------------------------
  407. // Expose IClientLeafSystem to the client dll.
  408. //-----------------------------------------------------------------------------
  409. CClientLeafSystem CClientLeafSystem::s_ClientLeafSystem;
  410. IClientLeafSystem *g_pClientLeafSystem = &CClientLeafSystem::s_ClientLeafSystem;
  411. IClientAlphaPropertyMgr *g_pClientAlphaPropertyMgr = &CClientLeafSystem::s_ClientLeafSystem;
  412. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CClientLeafSystem, IClientLeafSystem, CLIENTLEAFSYSTEM_INTERFACE_VERSION, CClientLeafSystem::s_ClientLeafSystem );
  413. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CClientLeafSystem, IClientAlphaPropertyMgr, CLIENT_ALPHA_PROPERTY_MGR_INTERFACE_VERSION, CClientLeafSystem::s_ClientLeafSystem );
  414. void CalcRenderableWorldSpaceAABB_Fast( IClientRenderable *pRenderable, Vector &absMin, Vector &absMax );
  415. //-----------------------------------------------------------------------------
  416. // Helper functions.
  417. //-----------------------------------------------------------------------------
  418. void DefaultRenderBoundsWorldspace( IClientRenderable *pRenderable, Vector &absMins, Vector &absMaxs )
  419. {
  420. // SNPROF("DefaultRenderBoundsWorldspace");
  421. // Tracker 37433: This fixes a bug where if the stunstick is being wielded by a combine soldier, the fact that the stick was
  422. // attached to the soldier's hand would move it such that it would get frustum culled near the edge of the screen.
  423. C_BaseEntity *pEnt = pRenderable->GetIClientUnknown()->GetBaseEntity();
  424. if ( pEnt && ( pEnt->IsFollowingEntity() || ( pEnt->GetParentAttachment() > 0 ) ) )
  425. {
  426. C_BaseEntity *pParent = pEnt->GetMoveParent();
  427. if ( pParent )
  428. {
  429. // Get the parent's abs space world bounds.
  430. CalcRenderableWorldSpaceAABB_Fast( pParent, absMins, absMaxs );
  431. // Add the maximum of our local render bounds. This is making the assumption that we can be at any
  432. // point and at any angle within the parent's world space bounds.
  433. Vector vAddMins, vAddMaxs;
  434. pEnt->GetRenderBounds( vAddMins, vAddMaxs );
  435. // if our origin is actually farther away than that, expand again
  436. float radius = pEnt->GetLocalOrigin().Length();
  437. float flBloatSize = MAX( vAddMins.Length(), vAddMaxs.Length() );
  438. flBloatSize = MAX(flBloatSize, radius);
  439. absMins -= Vector( flBloatSize, flBloatSize, flBloatSize );
  440. absMaxs += Vector( flBloatSize, flBloatSize, flBloatSize );
  441. return;
  442. }
  443. }
  444. Vector mins, maxs;
  445. pRenderable->GetRenderBounds( mins, maxs );
  446. // FIXME: Should I just use a sphere here?
  447. // Another option is to pass the OBB down the tree; makes for a better fit
  448. // Generate a world-aligned AABB
  449. const QAngle& angles = pRenderable->GetRenderAngles();
  450. if (angles == vec3_angle)
  451. {
  452. const Vector& origin = pRenderable->GetRenderOrigin();
  453. VectorAdd( mins, origin, absMins );
  454. VectorAdd( maxs, origin, absMaxs );
  455. }
  456. else
  457. {
  458. TransformAABB( pRenderable->RenderableToWorldTransform(), mins, maxs, absMins, absMaxs );
  459. }
  460. Assert( absMins.IsValid() && absMaxs.IsValid() );
  461. }
  462. // Figure out a world space bounding box that encloses the entity's local render bounds in world space.
  463. inline void CalcRenderableWorldSpaceAABB(
  464. IClientRenderable *pRenderable,
  465. Vector &absMins,
  466. Vector &absMaxs )
  467. {
  468. pRenderable->GetRenderBoundsWorldspace( absMins, absMaxs );
  469. }
  470. // This gets an AABB for the renderable, but it doesn't cause a parent's bones to be setup.
  471. // This is used for placement in the leaves, but the more expensive version is used for culling.
  472. void CalcRenderableWorldSpaceAABB_Fast( IClientRenderable *pRenderable, Vector &absMin, Vector &absMax )
  473. {
  474. if ( !pRenderable )
  475. {
  476. AssertMsg( false, "Cannot calculate WorldSpaceAABB for NULL renderable!\n" );
  477. return;
  478. }
  479. C_BaseEntity *pEnt = pRenderable->GetIClientUnknown()->GetBaseEntity();
  480. if ( pEnt && ( pEnt->IsFollowingEntity() || ( pEnt->GetMoveParent() && ( pEnt->GetParentAttachment() > 0 ) ) ) )
  481. {
  482. C_BaseEntity *pParent = pEnt->GetMoveParent();
  483. if ( pParent )
  484. {
  485. // Get the parent's abs space world bounds.
  486. CalcRenderableWorldSpaceAABB_Fast( pParent, absMin, absMax );
  487. // Add the maximum of our local render bounds. This is making the assumption that we can be at any
  488. // point and at any angle within the parent's world space bounds.
  489. Vector vAddMins, vAddMaxs;
  490. pEnt->GetRenderBounds( vAddMins, vAddMaxs );
  491. // if our origin is actually farther away than that, expand again
  492. float radius = pEnt->GetLocalOrigin().Length();
  493. float flBloatSize = MAX( vAddMins.Length(), vAddMaxs.Length() );
  494. flBloatSize = MAX(flBloatSize, radius);
  495. absMin -= Vector( flBloatSize, flBloatSize, flBloatSize );
  496. absMax += Vector( flBloatSize, flBloatSize, flBloatSize );
  497. }
  498. }
  499. else
  500. {
  501. // Start out with our own render bounds. Since we don't have a parent, this won't incur any nasty
  502. CalcRenderableWorldSpaceAABB( pRenderable, absMin, absMax );
  503. }
  504. }
  505. //-----------------------------------------------------------------------------
  506. // constructor, destructor
  507. //-----------------------------------------------------------------------------
  508. CClientLeafSystem::CClientLeafSystem() : m_DrawStaticProps(true), m_DrawSmallObjects(true),
  509. m_AlphaPropertyPool( sizeof( CClientAlphaProperty ), 1024, CUtlMemoryPool::GROW_SLOW, "CClientAlphaProperty" )
  510. {
  511. // Set up the bi-directional lists...
  512. m_RenderablesInLeaf.Init( FirstRenderableInLeaf, FirstLeafInRenderable );
  513. m_ShadowsInLeaf.Init( FirstShadowInLeaf, FirstLeafInShadow );
  514. m_ShadowsOnRenderable.Init( FirstShadowOnRenderable, FirstRenderableInShadow );
  515. m_nAlternateSortCount = 0;
  516. m_nDisableShadowDepthCount = 0;
  517. m_nDisableShadowDepthCacheCount = 0;
  518. m_bDisableLeafReinsertion = false;
  519. }
  520. CClientLeafSystem::~CClientLeafSystem()
  521. {
  522. }
  523. //-----------------------------------------------------------------------------
  524. // Activate, deactivate static props
  525. //-----------------------------------------------------------------------------
  526. void CClientLeafSystem::DrawStaticProps( bool enable )
  527. {
  528. m_DrawStaticProps = enable;
  529. }
  530. void CClientLeafSystem::DrawSmallEntities( bool enable )
  531. {
  532. m_DrawSmallObjects = enable;
  533. }
  534. void CClientLeafSystem::DisableLeafReinsertion( bool bDisable )
  535. {
  536. m_bDisableLeafReinsertion = bDisable;
  537. }
  538. //-----------------------------------------------------------------------------
  539. // Level init, shutdown
  540. //-----------------------------------------------------------------------------
  541. void CClientLeafSystem::LevelInitPreEntity()
  542. {
  543. MEM_ALLOC_CREDIT();
  544. m_Renderables.EnsureCapacity( 1024 );
  545. m_RenderablesInLeaf.EnsureCapacity( 1024 );
  546. m_ShadowsInLeaf.EnsureCapacity( 256 );
  547. m_ShadowsOnRenderable.EnsureCapacity( 256 );
  548. m_DirtyRenderables.EnsureCapacity( 256 );
  549. // Add all the leaves we'll need
  550. int leafCount = engine->LevelLeafCount();
  551. m_Leaf.EnsureCapacity( leafCount );
  552. ClientLeaf_t newLeaf;
  553. newLeaf.m_FirstElement = m_RenderablesInLeaf.InvalidIndex();
  554. newLeaf.m_FirstShadow = m_ShadowsInLeaf.InvalidIndex();
  555. memset( newLeaf.m_pSubSystemData, 0, sizeof( newLeaf.m_pSubSystemData ) );
  556. newLeaf.m_FirstDetailProp = 0;
  557. newLeaf.m_DetailPropCount = 0;
  558. newLeaf.m_DetailPropRenderFrame = -1;
  559. while ( --leafCount >= 0 )
  560. {
  561. m_Leaf.AddToTail( newLeaf );
  562. }
  563. }
  564. void CClientLeafSystem::LevelShutdownPreEntity()
  565. {
  566. }
  567. void CClientLeafSystem::LevelShutdownPostEntity()
  568. {
  569. m_nAlternateSortCount = 0;
  570. m_nDisableShadowDepthCount = 0;
  571. m_nDisableShadowDepthCacheCount = 0;
  572. m_ViewModels.Purge();
  573. m_Renderables.Purge();
  574. m_RenderablesInLeaf.Purge();
  575. m_Shadows.Purge();
  576. // delete subsystem data
  577. for( int i = 0; i < m_Leaf.Count() ; i++ )
  578. {
  579. for( int j = 0 ; j < ARRAYSIZE( m_Leaf[i].m_pSubSystemData ) ; j++ )
  580. {
  581. if ( m_Leaf[i].m_pSubSystemData[j] )
  582. {
  583. delete m_Leaf[i].m_pSubSystemData[j];
  584. m_Leaf[i].m_pSubSystemData[j] = NULL;
  585. }
  586. }
  587. }
  588. m_Leaf.Purge();
  589. m_ShadowsInLeaf.Purge();
  590. m_ShadowsOnRenderable.Purge();
  591. m_DirtyRenderables.Purge();
  592. }
  593. //-----------------------------------------------------------------------------
  594. // Computes a bloated bounding box to reduce insertions into the tree
  595. //-----------------------------------------------------------------------------
  596. #define BBOX_GRANULARITY 32.0f
  597. #define MIN_SHRINK_VOLUME ( 32.0f * 32.0f * 32.0f )
  598. void CClientLeafSystem::CalcRenderableWorldSpaceAABB_Bloated( const RenderableInfo_t &info, Vector &absMin, Vector &absMax )
  599. {
  600. CalcRenderableWorldSpaceAABB_Fast( info.m_pRenderable, absMin, absMax );
  601. // Bloat bounds to avoid reinsertion into tree
  602. absMin.x = floor( absMin.x / BBOX_GRANULARITY ) * BBOX_GRANULARITY;
  603. absMin.y = floor( absMin.y / BBOX_GRANULARITY ) * BBOX_GRANULARITY;
  604. absMin.z = floor( absMin.z / BBOX_GRANULARITY ) * BBOX_GRANULARITY;
  605. absMax.x = ceil( absMax.x / BBOX_GRANULARITY ) * BBOX_GRANULARITY;
  606. absMax.y = ceil( absMax.y / BBOX_GRANULARITY ) * BBOX_GRANULARITY;
  607. absMax.z = ceil( absMax.z / BBOX_GRANULARITY ) * BBOX_GRANULARITY;
  608. // Optimization to make particle systems not re-insert themselves
  609. if ( info.m_Flags & RENDER_FLAGS_BLOAT_BOUNDS )
  610. {
  611. Vector vecTempMin, vecTempMax;
  612. VectorMin( info.m_vecBloatedAbsMins, absMin, vecTempMin );
  613. VectorMax( info.m_vecBloatedAbsMaxs, absMax, vecTempMax );
  614. float flTempVolume = ComputeVolume( vecTempMin, vecTempMax );
  615. float flCurrVolume = ComputeVolume( absMin, absMax );
  616. if ( ( flTempVolume <= MIN_SHRINK_VOLUME ) || ( flCurrVolume * 2.0f >= flTempVolume ) )
  617. {
  618. absMin = vecTempMin;
  619. absMax = vecTempMax;
  620. }
  621. }
  622. }
  623. //-----------------------------------------------------------------------------
  624. // This is what happens before rendering a particular view
  625. //-----------------------------------------------------------------------------
  626. void CClientLeafSystem::PreRender()
  627. {
  628. // Assert( m_DirtyRenderables.Count() == 0 );
  629. // FIXME: This should never need to happen here!
  630. // At the moment, it's necessary because of the horrid viewmodel/combatweapon
  631. // confusion in the code where a combat weapon changes its rendering model
  632. // per view.
  633. RecomputeRenderableLeaves();
  634. }
  635. // Use this to make sure we're not adding the same renderables to the list while we're going through and re-inserting them into the clientleafsystem
  636. static bool s_bIsInRecomputeRenderableLeaves = false;
  637. void CClientLeafSystem::RecomputeRenderableLeaves()
  638. {
  639. AUTO_LOCK_FM(m_DirtyRenderablesMutex);
  640. // MiniProfilerGuard mpGuard(&g_mpRecomputeLeaves);
  641. int i;
  642. int nIterations = 0;
  643. bool bDebugLeafSystem = !IsGameConsole() && cl_leafsystemvis.GetBool();
  644. Vector absMins, absMaxs;
  645. while ( m_DirtyRenderables.Count() )
  646. {
  647. if ( ++nIterations > 10 )
  648. {
  649. Warning( "Too many dirty renderables!\n" );
  650. break;
  651. }
  652. s_bIsInRecomputeRenderableLeaves = true;
  653. int nDirty = m_DirtyRenderables.Count();
  654. for ( i = nDirty; --i >= 0; )
  655. {
  656. ClientRenderHandle_t handle = m_DirtyRenderables[i];
  657. RenderableInfo_t &info = m_Renderables[ handle ];
  658. Assert( info.m_Flags & RENDER_FLAGS_HASCHANGED );
  659. // See note below
  660. info.m_Flags &= ~RENDER_FLAGS_HASCHANGED;
  661. if ( info.m_Flags & RENDER_FLAGS_RENDER_WITH_VIEWMODELS )
  662. continue;
  663. CalcRenderableWorldSpaceAABB_Bloated( info, absMins, absMaxs );
  664. if ( absMins != info.m_vecBloatedAbsMins || absMaxs != info.m_vecBloatedAbsMaxs )
  665. {
  666. // Update position in leaf system
  667. RemoveFromTree( handle );
  668. InsertIntoTree( m_DirtyRenderables[i], absMins, absMaxs );
  669. if ( bDebugLeafSystem )
  670. {
  671. debugoverlay->AddBoxOverlay( vec3_origin, absMins, absMaxs, QAngle( 0, 0, 0 ), 0, 255, 0, 0, 0 );
  672. }
  673. }
  674. }
  675. s_bIsInRecomputeRenderableLeaves = false;
  676. // NOTE: If we get the following error displayed in the console spew
  677. // "Re-entrancy found in CClientLeafSystem::RenderableChanged\n"
  678. // We'll have to reenable this code and remove the line that
  679. // removes the RENDER_FLAGS_HASCHANGED in the loop above.
  680. /*
  681. for ( i = nDirty; --i >= 0; )
  682. {
  683. // Cache off the area it's sitting in.
  684. ClientRenderHandle_t handle = m_DirtyRenderables[i];
  685. RenderableInfo_t& renderable = m_Renderables[ handle ];
  686. renderable.m_Flags &= ~RENDER_FLAGS_HASCHANGED;
  687. }
  688. */
  689. m_DirtyRenderables.RemoveMultiple( 0, nDirty );
  690. }
  691. }
  692. //-----------------------------------------------------------------------------
  693. // Creates a new renderable
  694. //-----------------------------------------------------------------------------
  695. void CClientLeafSystem::CreateRenderableHandle( IClientRenderable* pRenderable, bool bRenderWithViewModels, RenderableTranslucencyType_t nType, RenderableModelType_t nModelType, uint32 nSplitscreenEnabled )
  696. {
  697. Assert( pRenderable );
  698. Assert( pRenderable->RenderHandle() == INVALID_CLIENT_RENDER_HANDLE );
  699. ClientRenderHandle_t handle = m_Renderables.AddToTail();
  700. RenderableInfo_t &info = m_Renderables[handle];
  701. if ( nModelType == RENDERABLE_MODEL_UNKNOWN_TYPE )
  702. {
  703. int nType = modelinfo->GetModelType( pRenderable->GetModel() );
  704. switch( nType )
  705. {
  706. default: nModelType = RENDERABLE_MODEL_ENTITY; break;
  707. case mod_brush: nModelType = RENDERABLE_MODEL_BRUSH; break;
  708. case mod_studio: nModelType = RENDERABLE_MODEL_STUDIOMDL; break;
  709. }
  710. }
  711. int modelType = modelinfo->GetModelType( pRenderable->GetModel() );
  712. #ifdef _DEBUG
  713. // We need to know if it's a brush model for shadows
  714. switch ( modelType )
  715. {
  716. case mod_brush: Assert( nModelType == RENDERABLE_MODEL_BRUSH ); break;
  717. case mod_studio: Assert( nModelType == RENDERABLE_MODEL_STUDIOMDL || nModelType == RENDERABLE_MODEL_STATIC_PROP ); break;
  718. case mod_sprite: default: Assert( nModelType == RENDERABLE_MODEL_ENTITY ); break;
  719. }
  720. #endif
  721. info.m_Area = -1;
  722. info.m_pRenderable = pRenderable;
  723. info.m_pAlphaProperty = static_cast< CClientAlphaProperty* >( pRenderable->GetIClientUnknown()->GetClientAlphaProperty() );
  724. info.m_FirstShadow = m_ShadowsOnRenderable.InvalidIndex();
  725. info.m_LeafList = m_RenderablesInLeaf.InvalidIndex();
  726. info.m_Flags = ( modelType == mod_sprite ) ? RENDER_FLAGS_IS_SPRITE : 0;
  727. info.m_bRenderInFastReflection = false;
  728. info.m_bDisableShadowDepthRendering = false;
  729. info.m_bDisableCSMRendering = false;
  730. info.m_bDisableShadowDepthCaching = false;
  731. info.m_nRenderFrame = -1;
  732. info.m_EnumCount = 0;
  733. info.m_nSplitscreenEnabled = nSplitscreenEnabled & 0x3;
  734. info.m_nTranslucencyType = nType;
  735. info.m_nModelType = nModelType;
  736. info.m_vecBloatedAbsMins.Init( FLT_MAX, FLT_MAX, FLT_MAX );
  737. info.m_vecBloatedAbsMaxs.Init( -FLT_MAX, -FLT_MAX, -FLT_MAX );
  738. info.m_vecAbsMins.Init();
  739. info.m_vecAbsMaxs.Init();
  740. pRenderable->RenderHandle() = handle;
  741. RenderWithViewModels( handle, bRenderWithViewModels );
  742. }
  743. //-----------------------------------------------------------------------------
  744. // Call this if the model changes
  745. //-----------------------------------------------------------------------------
  746. void CClientLeafSystem::SetTranslucencyType( ClientRenderHandle_t handle, RenderableTranslucencyType_t nType )
  747. {
  748. if ( handle == INVALID_CLIENT_RENDER_HANDLE )
  749. return;
  750. RenderableInfo_t &info = m_Renderables[handle];
  751. info.m_nTranslucencyType = nType;
  752. }
  753. RenderableTranslucencyType_t CClientLeafSystem::GetTranslucencyType( ClientRenderHandle_t handle ) const
  754. {
  755. if ( handle == INVALID_CLIENT_RENDER_HANDLE )
  756. return RENDERABLE_IS_OPAQUE;
  757. const RenderableInfo_t &info = m_Renderables[handle];
  758. return (RenderableTranslucencyType_t)info.m_nTranslucencyType;
  759. }
  760. void CClientLeafSystem::RenderInFastReflections( ClientRenderHandle_t handle, bool bRenderInFastReflections )
  761. {
  762. if ( handle == INVALID_CLIENT_RENDER_HANDLE )
  763. return;
  764. RenderableInfo_t &info = m_Renderables[handle];
  765. info.m_bRenderInFastReflection = bRenderInFastReflections;
  766. }
  767. bool CClientLeafSystem::IsRenderingInFastReflections( ClientRenderHandle_t handle ) const
  768. {
  769. if ( handle == INVALID_CLIENT_RENDER_HANDLE )
  770. return false;
  771. const RenderableInfo_t &info = m_Renderables[handle];
  772. return info.m_bRenderInFastReflection;
  773. }
  774. void CClientLeafSystem::DisableShadowDepthRendering( ClientRenderHandle_t handle, bool bDisable )
  775. {
  776. if ( handle == INVALID_CLIENT_RENDER_HANDLE )
  777. return;
  778. RenderableInfo_t &info = m_Renderables[handle];
  779. if ( bDisable != info.m_bDisableShadowDepthRendering )
  780. {
  781. info.m_bDisableShadowDepthRendering = bDisable;
  782. m_nDisableShadowDepthCount += bDisable ? 1 : -1;
  783. Assert( m_nDisableShadowDepthCount >= 0 );
  784. }
  785. }
  786. void CClientLeafSystem::DisableCSMRendering( ClientRenderHandle_t handle, bool bDisable )
  787. {
  788. if ( handle == INVALID_CLIENT_RENDER_HANDLE )
  789. return;
  790. RenderableInfo_t &info = m_Renderables[handle];
  791. if ( bDisable != info.m_bDisableCSMRendering )
  792. {
  793. info.m_bDisableCSMRendering = bDisable;
  794. m_nDisableShadowDepthCount += bDisable ? 1 : -1;
  795. Assert( m_nDisableShadowDepthCount >= 0 );
  796. }
  797. }
  798. void CClientLeafSystem::DisableShadowDepthCaching( ClientRenderHandle_t handle, bool bDisable )
  799. {
  800. if ( handle == INVALID_CLIENT_RENDER_HANDLE )
  801. return;
  802. RenderableInfo_t &info = m_Renderables[handle];
  803. if ( bDisable != info.m_bDisableShadowDepthCaching )
  804. {
  805. info.m_bDisableShadowDepthCaching = bDisable;
  806. m_nDisableShadowDepthCacheCount += bDisable ? 1 : -1;
  807. Assert( m_nDisableShadowDepthCacheCount >= 0 );
  808. }
  809. }
  810. void CClientLeafSystem::EnableSplitscreenRendering( ClientRenderHandle_t handle, uint32 nFlags )
  811. {
  812. if ( handle == INVALID_CLIENT_RENDER_HANDLE )
  813. return;
  814. RenderableInfo_t &info = m_Renderables[handle];
  815. info.m_nSplitscreenEnabled = nFlags & 0x3;
  816. }
  817. void CClientLeafSystem::SetModelType( ClientRenderHandle_t handle, RenderableModelType_t nModelType )
  818. {
  819. if ( handle == INVALID_CLIENT_RENDER_HANDLE )
  820. return;
  821. RenderableInfo_t &info = m_Renderables[handle];
  822. if ( nModelType == RENDERABLE_MODEL_UNKNOWN_TYPE )
  823. {
  824. int nType = modelinfo->GetModelType( info.m_pRenderable->GetModel() );
  825. switch( nType )
  826. {
  827. default: nModelType = RENDERABLE_MODEL_ENTITY; break;
  828. case mod_brush: nModelType = RENDERABLE_MODEL_BRUSH; break;
  829. case mod_studio: nModelType = RENDERABLE_MODEL_STUDIOMDL; break;
  830. }
  831. }
  832. if ( info.m_nModelType != nModelType )
  833. {
  834. info.m_nModelType = nModelType;
  835. RenderableChanged( handle );
  836. }
  837. }
  838. void CClientLeafSystem::EnableRendering( ClientRenderHandle_t handle, bool bEnable )
  839. {
  840. if ( handle == INVALID_CLIENT_RENDER_HANDLE )
  841. return;
  842. RenderableInfo_t &info = m_Renderables[handle];
  843. if ( bEnable )
  844. {
  845. info.m_Flags &= ~RENDER_FLAGS_DISABLE_RENDERING;
  846. }
  847. else
  848. {
  849. info.m_Flags |= RENDER_FLAGS_DISABLE_RENDERING;
  850. }
  851. }
  852. void CClientLeafSystem::EnableBloatedBounds( ClientRenderHandle_t handle, bool bEnable )
  853. {
  854. if ( handle == INVALID_CLIENT_RENDER_HANDLE )
  855. return;
  856. RenderableInfo_t &info = m_Renderables[handle];
  857. if ( bEnable )
  858. {
  859. info.m_Flags |= RENDER_FLAGS_BLOAT_BOUNDS;
  860. }
  861. else
  862. {
  863. if ( info.m_Flags & RENDER_FLAGS_BLOAT_BOUNDS )
  864. {
  865. info.m_Flags &= ~RENDER_FLAGS_BLOAT_BOUNDS;
  866. // Necessary to generate unbloated bounds later
  867. RenderableChanged( handle );
  868. }
  869. }
  870. }
  871. void CClientLeafSystem::DisableCachedRenderBounds( ClientRenderHandle_t handle, bool bDisable )
  872. {
  873. if ( handle == INVALID_CLIENT_RENDER_HANDLE )
  874. return;
  875. RenderableInfo_t &info = m_Renderables[handle];
  876. if ( bDisable )
  877. {
  878. info.m_Flags |= RENDER_FLAGS_BOUNDS_ALWAYS_RECOMPUTE;
  879. }
  880. else
  881. {
  882. info.m_Flags &= ~RENDER_FLAGS_BOUNDS_ALWAYS_RECOMPUTE;
  883. }
  884. }
  885. //-----------------------------------------------------------------------------
  886. // Draw translucent objects in the opaque renderables pass
  887. //-----------------------------------------------------------------------------
  888. void CClientLeafSystem::EnableForceOpaquePass( ClientRenderHandle_t handle, bool bEnable )
  889. {
  890. if ( handle == INVALID_CLIENT_RENDER_HANDLE )
  891. return;
  892. RenderableInfo_t &info = m_Renderables[handle];
  893. if ( bEnable )
  894. {
  895. if ( (info.m_Flags & RENDER_FLAGS_FORCE_OPAQUE_PASS) == 0 )
  896. {
  897. info.m_Flags |= RENDER_FLAGS_FORCE_OPAQUE_PASS;
  898. }
  899. }
  900. else
  901. {
  902. if ( (info.m_Flags & RENDER_FLAGS_FORCE_OPAQUE_PASS) != 0 )
  903. {
  904. info.m_Flags &= ~RENDER_FLAGS_FORCE_OPAQUE_PASS;
  905. }
  906. }
  907. }
  908. bool CClientLeafSystem::IsEnableForceOpaquePass( ClientRenderHandle_t handle ) const
  909. {
  910. if ( handle == INVALID_CLIENT_RENDER_HANDLE )
  911. return false;
  912. return (m_Renderables[handle].m_Flags & RENDER_FLAGS_FORCE_OPAQUE_PASS) != 0;
  913. }
  914. //-----------------------------------------------------------------------------
  915. // Use alternate translucent sorting algorithm (draw translucent objects in the furthest leaf they lie in)
  916. //-----------------------------------------------------------------------------
  917. void CClientLeafSystem::EnableAlternateSorting( ClientRenderHandle_t handle, bool bEnable )
  918. {
  919. RenderableInfo_t &info = m_Renderables[handle];
  920. if ( bEnable )
  921. {
  922. if ( ( info.m_Flags & RENDER_FLAGS_ALTERNATE_SORTING ) == 0 )
  923. {
  924. ++m_nAlternateSortCount;
  925. info.m_Flags |= RENDER_FLAGS_ALTERNATE_SORTING;
  926. }
  927. }
  928. else
  929. {
  930. if ( ( info.m_Flags & RENDER_FLAGS_ALTERNATE_SORTING ) != 0 )
  931. {
  932. --m_nAlternateSortCount;
  933. info.m_Flags &= ~RENDER_FLAGS_ALTERNATE_SORTING;
  934. }
  935. }
  936. }
  937. //-----------------------------------------------------------------------------
  938. // Should this render with viewmodels?
  939. //-----------------------------------------------------------------------------
  940. void CClientLeafSystem::RenderWithViewModels( ClientRenderHandle_t handle, bool bEnable )
  941. {
  942. if ( handle == INVALID_CLIENT_RENDER_HANDLE )
  943. return;
  944. RenderableInfo_t &info = m_Renderables[handle];
  945. if ( bEnable )
  946. {
  947. if ( ( info.m_Flags & RENDER_FLAGS_RENDER_WITH_VIEWMODELS ) == 0 )
  948. {
  949. info.m_Flags |= RENDER_FLAGS_RENDER_WITH_VIEWMODELS;
  950. AddToViewModelList( handle );
  951. RemoveFromTree( handle );
  952. }
  953. }
  954. else
  955. {
  956. if ( ( info.m_Flags & RENDER_FLAGS_RENDER_WITH_VIEWMODELS ) != 0 )
  957. {
  958. info.m_Flags &= ~RENDER_FLAGS_RENDER_WITH_VIEWMODELS;
  959. RemoveFromViewModelList( handle );
  960. info.m_vecBloatedAbsMins.Init( FLT_MAX, FLT_MAX, FLT_MAX );
  961. info.m_vecBloatedAbsMaxs.Init( -FLT_MAX, -FLT_MAX, -FLT_MAX );
  962. RenderableChanged( handle );
  963. }
  964. }
  965. }
  966. bool CClientLeafSystem::IsRenderingWithViewModels( ClientRenderHandle_t handle ) const
  967. {
  968. if ( handle == INVALID_CLIENT_RENDER_HANDLE )
  969. return false;
  970. return ( m_Renderables[handle].m_Flags & RENDER_FLAGS_RENDER_WITH_VIEWMODELS ) != 0;
  971. }
  972. //-----------------------------------------------------------------------------
  973. // Add/remove renderable
  974. //-----------------------------------------------------------------------------
  975. void CClientLeafSystem::AddRenderable( IClientRenderable* pRenderable, bool bRenderWithViewModels, RenderableTranslucencyType_t nType, RenderableModelType_t nModelType, uint32 nSplitscreenEnabled )
  976. {
  977. // force a relink we we try to draw it for the first time
  978. CreateRenderableHandle( pRenderable, bRenderWithViewModels, nType, nModelType, nSplitscreenEnabled );
  979. ClientRenderHandle_t handle = pRenderable->RenderHandle();
  980. RenderableChanged( handle );
  981. }
  982. void CClientLeafSystem::RemoveRenderable( ClientRenderHandle_t handle )
  983. {
  984. AUTO_LOCK_FM(m_DirtyRenderablesMutex);
  985. // This can happen upon level shutdown
  986. if (!m_Renderables.IsValidIndex(handle))
  987. return;
  988. // Reset the render handle in the entity.
  989. IClientRenderable *pRenderable = m_Renderables[handle].m_pRenderable;
  990. Assert( handle == pRenderable->RenderHandle() );
  991. pRenderable->RenderHandle() = INVALID_CLIENT_RENDER_HANDLE;
  992. int nFlags = m_Renderables[handle].m_Flags;
  993. if ( nFlags & RENDER_FLAGS_ALTERNATE_SORTING )
  994. {
  995. --m_nAlternateSortCount;
  996. }
  997. if ( m_Renderables[handle].m_bDisableShadowDepthRendering )
  998. {
  999. --m_nDisableShadowDepthCount;
  1000. }
  1001. if ( m_Renderables[handle].m_bDisableShadowDepthCaching )
  1002. {
  1003. --m_nDisableShadowDepthCacheCount;
  1004. }
  1005. // Remove the renderable from the dirty list
  1006. if ( nFlags & RENDER_FLAGS_HASCHANGED )
  1007. {
  1008. // NOTE: This isn't particularly fast (linear search),
  1009. // but I'm assuming it's an unusual case where we remove
  1010. // renderables that are changing or that m_DirtyRenderables usually
  1011. // only has a couple entries
  1012. int i = m_DirtyRenderables.Find( handle );
  1013. Assert( i != m_DirtyRenderables.InvalidIndex() );
  1014. if ( m_DirtyRenderables.IsValidIndex( i ) )
  1015. {
  1016. m_DirtyRenderables.FastRemove( i );
  1017. }
  1018. }
  1019. if ( IsRenderingWithViewModels( handle ) )
  1020. {
  1021. RemoveFromViewModelList( handle );
  1022. }
  1023. RemoveFromTree( handle );
  1024. m_Renderables.Remove( handle );
  1025. }
  1026. int CClientLeafSystem::GetRenderableLeaves( ClientRenderHandle_t handle, int leaves[128] )
  1027. {
  1028. if ( !m_Renderables.IsValidIndex( handle ) )
  1029. return -1;
  1030. RenderableInfo_t *pRenderable = &m_Renderables[handle];
  1031. if ( pRenderable->m_LeafList == m_RenderablesInLeaf.InvalidIndex() )
  1032. return -1;
  1033. int nLeaves = 0;
  1034. for ( int i=m_RenderablesInLeaf.FirstBucket( handle ); i != m_RenderablesInLeaf.InvalidIndex(); i = m_RenderablesInLeaf.NextBucket( i ) )
  1035. {
  1036. leaves[nLeaves++] = m_RenderablesInLeaf.Bucket( i );
  1037. if ( nLeaves >= 128 )
  1038. break;
  1039. }
  1040. return nLeaves;
  1041. }
  1042. //-----------------------------------------------------------------------------
  1043. // Retrieve leaf handles to leaves a renderable is in
  1044. // the pOutLeaf parameter is filled with the leaf the renderable is in.
  1045. // If pInIterator is not specified, pOutLeaf is the first leaf in the list.
  1046. // if pInIterator is specified, that iterator is used to return the next leaf
  1047. // in the list in pOutLeaf.
  1048. // the pOutIterator parameter is filled with the iterater which index to the pOutLeaf returned.
  1049. //
  1050. // Returns false on failure cases where pOutLeaf will be invalid. CHECK THE RETURN!
  1051. //-----------------------------------------------------------------------------
  1052. bool CClientLeafSystem::GetRenderableLeaf(ClientRenderHandle_t handle, int* pOutLeaf, const int* pInIterator /* = 0 */, int* pOutIterator /* = 0 */)
  1053. {
  1054. // bail on invalid handle
  1055. if ( !m_Renderables.IsValidIndex( handle ) )
  1056. return false;
  1057. // bail on no output value pointer
  1058. if ( !pOutLeaf )
  1059. return false;
  1060. // an iterator was specified
  1061. if ( pInIterator )
  1062. {
  1063. int iter = *pInIterator;
  1064. // test for invalid iterator
  1065. if ( iter == m_RenderablesInLeaf.InvalidIndex() )
  1066. return false;
  1067. int iterNext = m_RenderablesInLeaf.NextBucket( iter );
  1068. // test for end of list
  1069. if ( iterNext == m_RenderablesInLeaf.InvalidIndex() )
  1070. return false;
  1071. // Give the caller the iterator used
  1072. if ( pOutIterator )
  1073. {
  1074. *pOutIterator = iterNext;
  1075. }
  1076. // set output value to the next leaf
  1077. *pOutLeaf = m_RenderablesInLeaf.Bucket( iterNext );
  1078. }
  1079. else // no iter param, give them the first bucket in the renderable's list
  1080. {
  1081. int iter = m_RenderablesInLeaf.FirstBucket( handle );
  1082. if ( iter == m_RenderablesInLeaf.InvalidIndex() )
  1083. return false;
  1084. // Set output value to this leaf
  1085. *pOutLeaf = m_RenderablesInLeaf.Bucket( iter );
  1086. // give this iterator to caller
  1087. if ( pOutIterator )
  1088. {
  1089. *pOutIterator = iter;
  1090. }
  1091. }
  1092. return true;
  1093. }
  1094. bool CClientLeafSystem::IsRenderableInPVS( IClientRenderable *pRenderable )
  1095. {
  1096. ClientRenderHandle_t handle = pRenderable->RenderHandle();
  1097. int leaves[128];
  1098. int nLeaves = GetRenderableLeaves( handle, leaves );
  1099. if ( nLeaves == -1 )
  1100. return false;
  1101. // Ask the engine if this guy is visible.
  1102. return render->AreAnyLeavesVisible( leaves, nLeaves );
  1103. }
  1104. void CClientLeafSystem::SetSubSystemDataInLeaf( int leaf, int nSubSystemIdx, CClientLeafSubSystemData *pData )
  1105. {
  1106. assert( nSubSystemIdx < N_CLSUBSYSTEMS );
  1107. if ( m_Leaf[leaf].m_pSubSystemData[nSubSystemIdx] )
  1108. delete m_Leaf[leaf].m_pSubSystemData[nSubSystemIdx];
  1109. m_Leaf[leaf].m_pSubSystemData[nSubSystemIdx] = pData;
  1110. }
  1111. CClientLeafSubSystemData *CClientLeafSystem::GetSubSystemDataInLeaf( int leaf, int nSubSystemIdx )
  1112. {
  1113. assert( nSubSystemIdx < N_CLSUBSYSTEMS );
  1114. return m_Leaf[leaf].m_pSubSystemData[nSubSystemIdx];
  1115. }
  1116. //-----------------------------------------------------------------------------
  1117. // Indicates which leaves detail objects are in
  1118. //-----------------------------------------------------------------------------
  1119. void CClientLeafSystem::SetDetailObjectsInLeaf( int leaf, int firstDetailObject,
  1120. int detailObjectCount )
  1121. {
  1122. m_Leaf[leaf].m_FirstDetailProp = firstDetailObject;
  1123. m_Leaf[leaf].m_DetailPropCount = detailObjectCount;
  1124. if ( detailObjectCount )
  1125. engine->SetLeafFlag( leaf, LEAF_FLAGS_CONTAINS_DETAILOBJECTS ); // for fast searches
  1126. }
  1127. //-----------------------------------------------------------------------------
  1128. // Returns the detail objects in a leaf
  1129. //-----------------------------------------------------------------------------
  1130. void CClientLeafSystem::GetDetailObjectsInLeaf( int leaf, int& firstDetailObject,
  1131. int& detailObjectCount )
  1132. {
  1133. firstDetailObject = m_Leaf[leaf].m_FirstDetailProp;
  1134. detailObjectCount = m_Leaf[leaf].m_DetailPropCount;
  1135. }
  1136. //-----------------------------------------------------------------------------
  1137. // Create/destroy shadows...
  1138. //-----------------------------------------------------------------------------
  1139. ClientLeafShadowHandle_t CClientLeafSystem::AddShadow( ClientShadowHandle_t userId, unsigned short flags )
  1140. {
  1141. ClientLeafShadowHandle_t idx = m_Shadows.AddToTail();
  1142. m_Shadows[idx].m_Shadow = userId;
  1143. m_Shadows[idx].m_FirstLeaf = m_ShadowsInLeaf.InvalidIndex();
  1144. m_Shadows[idx].m_FirstRenderable = m_ShadowsOnRenderable.InvalidIndex();
  1145. m_Shadows[idx].m_EnumCount = 0;
  1146. m_Shadows[idx].m_Flags = flags;
  1147. return idx;
  1148. }
  1149. void CClientLeafSystem::RemoveShadow( ClientLeafShadowHandle_t handle )
  1150. {
  1151. // Remove the shadow from all leaves + renderables...
  1152. RemoveShadowFromLeaves( handle );
  1153. RemoveShadowFromRenderables( handle );
  1154. // Blow away the handle
  1155. m_Shadows.Remove( handle );
  1156. }
  1157. //-----------------------------------------------------------------------------
  1158. // Adds a shadow to a leaf/removes shadow from renderable
  1159. //-----------------------------------------------------------------------------
  1160. inline bool CClientLeafSystem::ShouldRenderableReceiveShadow( ClientRenderHandle_t renderHandle, int nShadowFlags )
  1161. {
  1162. RenderableInfo_t &renderable = m_Renderables[renderHandle];
  1163. if ( renderable.m_nModelType == RENDERABLE_MODEL_ENTITY )
  1164. return false;
  1165. return renderable.m_pRenderable->ShouldReceiveProjectedTextures( nShadowFlags );
  1166. }
  1167. //-----------------------------------------------------------------------------
  1168. // Adds a shadow to a leaf/removes shadow from renderable
  1169. //-----------------------------------------------------------------------------
  1170. void CClientLeafSystem::AddShadowToRenderable( ClientRenderHandle_t renderHandle,
  1171. ClientLeafShadowHandle_t shadowHandle )
  1172. {
  1173. // Check if this renderable receives the type of projected texture that shadowHandle refers to.
  1174. int nShadowFlags = m_Shadows[shadowHandle].m_Flags;
  1175. if ( !ShouldRenderableReceiveShadow( renderHandle, nShadowFlags ) )
  1176. return;
  1177. m_ShadowsOnRenderable.AddElementToBucket( renderHandle, shadowHandle );
  1178. // Also, do some stuff specific to the particular types of renderables
  1179. #if 0
  1180. // If the renderable is a brush model, then add this shadow to it
  1181. IClientRenderable* pRenderable = m_Renderables[renderHandle].m_pRenderable;
  1182. switch( m_Renderables[renderHandle].m_nModelType )
  1183. {
  1184. case RENDERABLE_MODEL_BRUSH:
  1185. g_pClientShadowMgr->AddShadowToReceiver( m_Shadows[shadowHandle].m_Shadow,
  1186. pRenderable, SHADOW_RECEIVER_BRUSH_MODEL );
  1187. break;
  1188. case RENDERABLE_MODEL_STATIC_PROP:
  1189. g_pClientShadowMgr->AddShadowToReceiver( m_Shadows[shadowHandle].m_Shadow,
  1190. pRenderable, SHADOW_RECEIVER_STATIC_PROP );
  1191. break;
  1192. case RENDERABLE_MODEL_STUDIOMDL:
  1193. g_pClientShadowMgr->AddShadowToReceiver( m_Shadows[shadowHandle].m_Shadow,
  1194. pRenderable, SHADOW_RECEIVER_STUDIO_MODEL );
  1195. break;
  1196. }
  1197. #else
  1198. // Do AddShadowToReceiver to avoid branching
  1199. static const byte arrRecvType[0x4] = {
  1200. 0,
  1201. SHADOW_RECEIVER_STUDIO_MODEL,
  1202. SHADOW_RECEIVER_STATIC_PROP,
  1203. SHADOW_RECEIVER_BRUSH_MODEL
  1204. };
  1205. COMPILE_TIME_ASSERT( RENDERABLE_MODEL_STUDIOMDL == 1 );
  1206. COMPILE_TIME_ASSERT( RENDERABLE_MODEL_STATIC_PROP == 2 );
  1207. COMPILE_TIME_ASSERT( RENDERABLE_MODEL_BRUSH == 3 );
  1208. RenderableInfo_t const &ri = m_Renderables[renderHandle];
  1209. if ( ri.m_nModelType < ARRAYSIZE( arrRecvType ) )
  1210. {
  1211. g_pClientShadowMgr->AddShadowToReceiver(
  1212. m_Shadows[shadowHandle].m_Shadow,
  1213. ri.m_pRenderable,
  1214. ( ShadowReceiver_t ) arrRecvType[ ri.m_nModelType ] );
  1215. }
  1216. #endif
  1217. }
  1218. void CClientLeafSystem::RemoveShadowFromRenderables( ClientLeafShadowHandle_t handle )
  1219. {
  1220. m_ShadowsOnRenderable.RemoveElement( handle );
  1221. }
  1222. //-----------------------------------------------------------------------------
  1223. // Adds a shadow to a leaf/removes shadow from leaf
  1224. //-----------------------------------------------------------------------------
  1225. void CClientLeafSystem::AddShadowToLeaf( int leaf, ClientLeafShadowHandle_t shadow, bool bFlashlight )
  1226. {
  1227. m_ShadowsInLeaf.AddElementToBucket( leaf, shadow );
  1228. if ( !( bFlashlight || r_shadows_on_renderables_enable.GetBool() ) )
  1229. {
  1230. return;
  1231. }
  1232. // Add the shadow exactly once to all renderables in the leaf
  1233. unsigned short i = m_RenderablesInLeaf.FirstElement( leaf );
  1234. while ( i != m_RenderablesInLeaf.InvalidIndex() )
  1235. {
  1236. ClientRenderHandle_t renderable = m_RenderablesInLeaf.Element(i);
  1237. RenderableInfo_t& info = m_Renderables[renderable];
  1238. // Add each shadow exactly once to each renderable
  1239. if (info.m_EnumCount != m_ShadowEnum)
  1240. {
  1241. AddShadowToRenderable( renderable, shadow );
  1242. info.m_EnumCount = m_ShadowEnum;
  1243. }
  1244. i = m_RenderablesInLeaf.NextElement(i);
  1245. }
  1246. }
  1247. void CClientLeafSystem::RemoveShadowFromLeaves( ClientLeafShadowHandle_t handle )
  1248. {
  1249. m_ShadowsInLeaf.RemoveElement( handle );
  1250. }
  1251. //-----------------------------------------------------------------------------
  1252. // Adds a shadow to all leaves listed
  1253. //-----------------------------------------------------------------------------
  1254. void CClientLeafSystem::ProjectShadow( ClientLeafShadowHandle_t handle, int nLeafCount, const int *pLeafList )
  1255. {
  1256. // Remove the shadow from any leaves it current exists in
  1257. RemoveShadowFromLeaves( handle );
  1258. RemoveShadowFromRenderables( handle );
  1259. Assert( ( m_Shadows[handle].m_Flags & SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK ) == SHADOW_FLAGS_SHADOW );
  1260. // This will help us to avoid adding the shadow multiple times to a renderable
  1261. ++m_ShadowEnum;
  1262. for ( int i = 0; i < nLeafCount; ++i )
  1263. {
  1264. AddShadowToLeaf( pLeafList[i], handle, false );
  1265. }
  1266. }
  1267. void CClientLeafSystem::ProjectFlashlight( ClientLeafShadowHandle_t handle, int nLeafCount, const int *pLeafList )
  1268. {
  1269. VPROF_BUDGET( "CClientLeafSystem::ProjectFlashlight", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  1270. // Remove the shadow from any leaves it current exists in
  1271. RemoveShadowFromLeaves( handle );
  1272. RemoveShadowFromRenderables( handle );
  1273. Assert( ( m_Shadows[handle].m_Flags & SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK ) != 0 );
  1274. // This will help us to avoid adding the shadow multiple times to a renderable
  1275. ++m_ShadowEnum;
  1276. for ( int i = 0; i < nLeafCount; ++i )
  1277. {
  1278. AddShadowToLeaf( pLeafList[i], handle, true );
  1279. }
  1280. }
  1281. //-----------------------------------------------------------------------------
  1282. // Find all shadow casters in a set of leaves
  1283. //-----------------------------------------------------------------------------
  1284. void CClientLeafSystem::EnumerateShadowsInLeaves( int leafCount, WorldListLeafData_t* pLeaves, IClientLeafShadowEnum* pEnum )
  1285. {
  1286. if (leafCount == 0)
  1287. return;
  1288. // This will help us to avoid enumerating the shadow multiple times
  1289. ++m_ShadowEnum;
  1290. for (int i = 0; i < leafCount; ++i)
  1291. {
  1292. int leaf = pLeaves[i].leafIndex;
  1293. unsigned short j = m_ShadowsInLeaf.FirstElement( leaf );
  1294. while ( j != m_ShadowsInLeaf.InvalidIndex() )
  1295. {
  1296. ClientLeafShadowHandle_t shadow = m_ShadowsInLeaf.Element(j);
  1297. ShadowInfo_t& info = m_Shadows[shadow];
  1298. if (info.m_EnumCount != m_ShadowEnum)
  1299. {
  1300. pEnum->EnumShadow(info.m_Shadow);
  1301. info.m_EnumCount = m_ShadowEnum;
  1302. }
  1303. j = m_ShadowsInLeaf.NextElement(j);
  1304. }
  1305. }
  1306. }
  1307. //-----------------------------------------------------------------------------
  1308. // Adds a renderable to a leaf
  1309. //-----------------------------------------------------------------------------
  1310. void CClientLeafSystem::AddRenderableToLeaf( int leaf, ClientRenderHandle_t renderable, bool bReceiveShadows )
  1311. {
  1312. #ifdef VALIDATE_CLIENT_LEAF_SYSTEM
  1313. m_RenderablesInLeaf.ValidateAddElementToBucket( leaf, renderable );
  1314. #endif
  1315. m_RenderablesInLeaf.AddElementToBucket( leaf, renderable );
  1316. bool bShadowsOnRenderables = r_shadows_on_renderables_enable.GetBool();
  1317. if ( !bReceiveShadows )
  1318. {
  1319. return;
  1320. }
  1321. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1322. if ( bShadowsOnRenderables )
  1323. {
  1324. // skipping this code entirely is only safe with single-pass flashlight (i.e. on the 360)
  1325. // Add all shadows in the leaf to the renderable...
  1326. unsigned short i = m_ShadowsInLeaf.FirstElement( leaf );
  1327. while ( i != m_ShadowsInLeaf.InvalidIndex() )
  1328. {
  1329. ClientLeafShadowHandle_t shadow = m_ShadowsInLeaf.Element(i);
  1330. ShadowInfo_t& info = m_Shadows[shadow];
  1331. // Add each shadow exactly once to each renderable
  1332. if ( info.m_EnumCount != m_ShadowEnum )
  1333. {
  1334. AddShadowToRenderable( renderable, shadow );
  1335. info.m_EnumCount = m_ShadowEnum;
  1336. }
  1337. i = m_ShadowsInLeaf.NextElement(i);
  1338. }
  1339. }
  1340. else if ( /*!bShadowsOnRenderables &&*/ IsPC() || pRenderContext->IsCullingEnabledForSinglePassFlashlight() )
  1341. {
  1342. // for non-singlepass flashlight (i.e. PC) we need to still add all flashlights to the renderable
  1343. // OR if we're culling individual objects with single pass flashlight
  1344. // Add all flashlights in the leaf to the renderable...
  1345. unsigned short i = m_ShadowsInLeaf.FirstElement( leaf );
  1346. while ( i != m_ShadowsInLeaf.InvalidIndex() )
  1347. {
  1348. ClientLeafShadowHandle_t shadow = m_ShadowsInLeaf.Element(i);
  1349. ShadowInfo_t& info = m_Shadows[shadow];
  1350. // Add each flashlight exactly once to each renderable
  1351. if ( ( info.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) && ( info.m_EnumCount != m_ShadowEnum ) )
  1352. {
  1353. AddShadowToRenderable( renderable, shadow );
  1354. info.m_EnumCount = m_ShadowEnum;
  1355. }
  1356. i = m_ShadowsInLeaf.NextElement(i);
  1357. }
  1358. }
  1359. }
  1360. //-----------------------------------------------------------------------------
  1361. // Adds a renderable to a set of leaves
  1362. //-----------------------------------------------------------------------------
  1363. void CClientLeafSystem::AddRenderableToLeaves( ClientRenderHandle_t handle, int nLeafCount, unsigned short *pLeaves, bool bReceiveShadows )
  1364. {
  1365. for (int j = 0; j < nLeafCount; ++j)
  1366. {
  1367. AddRenderableToLeaf( pLeaves[j], handle, bReceiveShadows );
  1368. }
  1369. m_Renderables[handle].m_Area = engine->GetLeavesArea( pLeaves, nLeafCount );
  1370. }
  1371. void CClientLeafSystem::AddRenderableToLeaves( ClientRenderHandle_t handle, int nLeafCount, unsigned short *pLeaves )
  1372. {
  1373. bool bReceiveShadows = ShouldRenderableReceiveShadow( handle, SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK );
  1374. AddRenderableToLeaves( handle, nLeafCount, pLeaves, bReceiveShadows );
  1375. }
  1376. //-----------------------------------------------------------------------------
  1377. // Inserts an element into the tree
  1378. //-----------------------------------------------------------------------------
  1379. bool CClientLeafSystem::EnumerateLeaf( int leaf, intp context )
  1380. {
  1381. EnumResultList_t *pList = (EnumResultList_t *)context;
  1382. if ( ThreadInMainThread() )
  1383. {
  1384. bool bReceiveShadows = ShouldRenderableReceiveShadow( pList->handle, SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK );
  1385. AddRenderableToLeaf( leaf, pList->handle, bReceiveShadows );
  1386. }
  1387. else
  1388. {
  1389. EnumResult_t *p = new EnumResult_t;
  1390. p->leaf = leaf;
  1391. p->pNext = pList->pHead;
  1392. pList->pHead = p;
  1393. }
  1394. return true;
  1395. }
  1396. void CClientLeafSystem::InsertIntoTree( ClientRenderHandle_t &handle, const Vector &absMins, const Vector &absMaxs )
  1397. {
  1398. // NOTE: The render bounds here are relative to the renderable's coordinate system
  1399. RenderableInfo_t &info = m_Renderables[handle];
  1400. Assert( absMins.IsValid() && absMaxs.IsValid() );
  1401. Assert( ( info.m_Flags & RENDER_FLAGS_RENDER_WITH_VIEWMODELS ) == 0 );
  1402. Assert( ThreadInMainThread() );
  1403. info.m_vecBloatedAbsMins = absMins;
  1404. info.m_vecBloatedAbsMaxs = absMaxs;
  1405. // When we insert into the tree, increase the shadow enumerator
  1406. // to make sure each shadow is added exactly once to each renderable
  1407. m_ShadowEnum++;
  1408. unsigned short leafList[1024];
  1409. ISpatialQuery* pQuery = engine->GetBSPTreeQuery();
  1410. int leafCount = pQuery->ListLeavesInBox( absMins, absMaxs, leafList, ARRAYSIZE(leafList) );
  1411. bool bReceiveShadows = ShouldRenderableReceiveShadow( handle, SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK );
  1412. if ( !IsGameConsole() && cl_leafsystemvis.GetBool() )
  1413. {
  1414. char pTemp[256];
  1415. const char *pClassName = "<unknown renderable>";
  1416. C_BaseEntity *pEnt = info.m_pRenderable->GetIClientUnknown()->GetBaseEntity();
  1417. if ( pEnt )
  1418. {
  1419. pClassName = pEnt->GetClassname();
  1420. }
  1421. else
  1422. {
  1423. CNewParticleEffect *pEffect = dynamic_cast< CNewParticleEffect*>( info.m_pRenderable );
  1424. if ( pEffect )
  1425. {
  1426. Q_snprintf( pTemp, sizeof(pTemp), "ps: %s", pEffect->GetName() );
  1427. pClassName = pTemp;
  1428. }
  1429. else if ( dynamic_cast< CParticleEffectBinding* >( info.m_pRenderable ) )
  1430. {
  1431. pClassName = "<old particle system>";
  1432. }
  1433. }
  1434. con_nprint_t np;
  1435. np.time_to_live = 0.1f;
  1436. np.fixed_width_font = true;
  1437. np.color[0] = 1.0;
  1438. np.color[1] = 0.8;
  1439. np.color[2] = 0.1;
  1440. np.index = m_nDebugIndex++;
  1441. engine->Con_NXPrintf( &np, "%s", pClassName );
  1442. }
  1443. AddRenderableToLeaves( handle, leafCount, leafList, bReceiveShadows );
  1444. }
  1445. //-----------------------------------------------------------------------------
  1446. // Removes an element from the tree
  1447. //-----------------------------------------------------------------------------
  1448. void CClientLeafSystem::RemoveFromTree( ClientRenderHandle_t handle )
  1449. {
  1450. m_RenderablesInLeaf.RemoveElement( handle );
  1451. // Remove all shadows cast onto the object
  1452. m_ShadowsOnRenderable.RemoveBucket( handle );
  1453. switch( m_Renderables[handle].m_nModelType )
  1454. {
  1455. case RENDERABLE_MODEL_BRUSH:
  1456. g_pClientShadowMgr->RemoveAllShadowsFromReceiver(
  1457. m_Renderables[handle].m_pRenderable, SHADOW_RECEIVER_BRUSH_MODEL );
  1458. break;
  1459. case RENDERABLE_MODEL_STATIC_PROP:
  1460. g_pClientShadowMgr->RemoveAllShadowsFromReceiver(
  1461. m_Renderables[handle].m_pRenderable, SHADOW_RECEIVER_STATIC_PROP );
  1462. break;
  1463. case RENDERABLE_MODEL_STUDIOMDL:
  1464. g_pClientShadowMgr->RemoveAllShadowsFromReceiver(
  1465. m_Renderables[handle].m_pRenderable, SHADOW_RECEIVER_STUDIO_MODEL );
  1466. break;
  1467. }
  1468. }
  1469. //-----------------------------------------------------------------------------
  1470. // Call this when the renderable moves
  1471. //-----------------------------------------------------------------------------
  1472. void CClientLeafSystem::RenderableChanged( ClientRenderHandle_t handle )
  1473. {
  1474. AUTO_LOCK_FM(m_DirtyRenderablesMutex);
  1475. // This should not be called during view rendering
  1476. // Assert( !m_bDisableLeafReinsertion );
  1477. Assert ( handle != INVALID_CLIENT_RENDER_HANDLE );
  1478. Assert( m_Renderables.IsValidIndex( handle ) );
  1479. if ( !m_Renderables.IsValidIndex( handle ) )
  1480. return;
  1481. RenderableInfo_t &info = m_Renderables[handle];
  1482. info.m_Flags &= ~RENDER_FLAGS_BOUNDS_VALID;
  1483. if ( ( info.m_Flags & RENDER_FLAGS_HASCHANGED ) == 0 )
  1484. {
  1485. info.m_Flags |= RENDER_FLAGS_HASCHANGED;
  1486. m_DirtyRenderables.AddToTail( handle );
  1487. }
  1488. //#if _DEBUG
  1489. else
  1490. {
  1491. if ( s_bIsInRecomputeRenderableLeaves )
  1492. {
  1493. Warning( "------------------------------------------------------------\n" );
  1494. Warning( "------------------------------------------------------------\n" );
  1495. Warning( "------------------------------------------------------------\n" );
  1496. Warning( "------------------------------------------------------------\n" );
  1497. Warning( "Re-entrancy found in CClientLeafSystem::RenderableChanged\n" );
  1498. Warning( "Contact Shanon or Brian\n" );
  1499. Warning( "------------------------------------------------------------\n" );
  1500. Warning( "------------------------------------------------------------\n" );
  1501. Warning( "------------------------------------------------------------\n" );
  1502. Warning( "------------------------------------------------------------\n" );
  1503. }
  1504. // It had better be in the list
  1505. Assert( m_DirtyRenderables.Find( handle ) != m_DirtyRenderables.InvalidIndex() );
  1506. }
  1507. //#endif
  1508. }
  1509. //-----------------------------------------------------------------------------
  1510. // Adds, removes renderables from view model list
  1511. //-----------------------------------------------------------------------------
  1512. void CClientLeafSystem::AddToViewModelList( ClientRenderHandle_t handle )
  1513. {
  1514. MEM_ALLOC_CREDIT();
  1515. Assert( m_ViewModels.Find( handle ) == m_ViewModels.InvalidIndex() );
  1516. m_ViewModels.AddToTail( handle );
  1517. }
  1518. void CClientLeafSystem::RemoveFromViewModelList( ClientRenderHandle_t handle )
  1519. {
  1520. int i = m_ViewModels.Find( handle );
  1521. Assert( i != m_ViewModels.InvalidIndex() );
  1522. m_ViewModels.FastRemove( i );
  1523. }
  1524. //-----------------------------------------------------------------------------
  1525. // Detail system marks
  1526. //-----------------------------------------------------------------------------
  1527. void CClientLeafSystem::DrawDetailObjectsInLeaf( int leaf, int nFrameNumber, int& nFirstDetailObject, int& nDetailObjectCount )
  1528. {
  1529. ClientLeaf_t &leafInfo = m_Leaf[leaf];
  1530. leafInfo.m_DetailPropRenderFrame = nFrameNumber;
  1531. nFirstDetailObject = leafInfo.m_FirstDetailProp;
  1532. nDetailObjectCount = leafInfo.m_DetailPropCount;
  1533. }
  1534. //-----------------------------------------------------------------------------
  1535. // Are we close enough to this leaf to draw detail props *and* are there any props in the leaf?
  1536. //-----------------------------------------------------------------------------
  1537. bool CClientLeafSystem::ShouldDrawDetailObjectsInLeaf( int leaf, int frameNumber )
  1538. {
  1539. ClientLeaf_t &leafInfo = m_Leaf[leaf];
  1540. return ( (leafInfo.m_DetailPropRenderFrame == frameNumber ) &&
  1541. ( ( leafInfo.m_DetailPropCount != 0 ) || ( leafInfo.m_pSubSystemData[CLSUBSYSTEM_DETAILOBJECTS] ) ) );
  1542. }
  1543. //-----------------------------------------------------------------------------
  1544. // Compute which leaf the translucent renderables should render in
  1545. //-----------------------------------------------------------------------------
  1546. #define LeafToMarker( leaf ) reinterpret_cast<RenderableInfo_t *>(( (leaf) << 1 ) | 1)
  1547. #define IsLeafMarker( p ) (bool)((reinterpret_cast<size_t>(p)) & 1)
  1548. #define MarkerToLeaf( p ) (int)((reinterpret_cast<size_t>(p)) >> 1)
  1549. //-----------------------------------------------------------------------------
  1550. // Adds a renderable to the list of renderables to render this frame
  1551. //-----------------------------------------------------------------------------
  1552. inline void AddRenderableToRenderList( CClientRenderablesList &renderList, IClientRenderable *pRenderable,
  1553. int iLeaf, RenderGroup_t group, int nModelType, uint8 nAlphaModulation, bool bShadowDepthNoCache, bool bTwoPass = false )
  1554. {
  1555. #ifdef _DEBUG
  1556. if (cl_drawleaf.GetInt() >= 0)
  1557. {
  1558. if (iLeaf != cl_drawleaf.GetInt())
  1559. return;
  1560. }
  1561. #endif
  1562. Assert( group >= 0 && group < RENDER_GROUP_COUNT );
  1563. int &curCount = renderList.m_RenderGroupCounts[group];
  1564. if ( curCount < CClientRenderablesList::MAX_GROUP_ENTITIES )
  1565. {
  1566. Assert( (iLeaf >= 0) && (iLeaf <= 65535) );
  1567. CClientRenderablesList::CEntry *pEntry = &renderList.m_RenderGroups[group][curCount];
  1568. pEntry->m_pRenderable = pRenderable;
  1569. pEntry->m_iWorldListInfoLeaf = iLeaf;
  1570. pEntry->m_nModelType = nModelType;
  1571. pEntry->m_bShadowDepthNoCache = bShadowDepthNoCache;
  1572. pEntry->m_TwoPass = bTwoPass;
  1573. pEntry->m_bIsCombinedModel = false;
  1574. if ( nModelType == RENDERABLE_MODEL_STUDIOMDL )
  1575. {
  1576. const model_t *pModel = pRenderable->GetModel();
  1577. MDLHandle_t Handle = modelinfo->GetCacheHandle( pModel );
  1578. bool bIsCombined = g_pMDLCache->IsCombinedModel( Handle );
  1579. pEntry->m_bIsCombinedModel = bIsCombined;
  1580. }
  1581. pEntry->m_InstanceData.m_nAlpha = nAlphaModulation;
  1582. curCount++;
  1583. }
  1584. else
  1585. {
  1586. engine->Con_NPrintf( 10, "Warning: overflowed CClientRenderablesList group %d", group );
  1587. }
  1588. }
  1589. //-----------------------------------------------------------------------------
  1590. // Purpose:
  1591. // Input : renderList -
  1592. // renderGroup -
  1593. //-----------------------------------------------------------------------------
  1594. void CClientLeafSystem::CollateViewModelRenderables( CViewModelRenderablesList *pList )
  1595. {
  1596. bool bIsSplitScreenActive = engine->IsSplitScreenActive();
  1597. int nSlotMask = 0;
  1598. if ( bIsSplitScreenActive )
  1599. {
  1600. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  1601. nSlotMask = 1 << GET_ACTIVE_SPLITSCREEN_SLOT();
  1602. }
  1603. CViewModelRenderablesList::RenderGroups_t &opaqueList = pList->m_RenderGroups[ CViewModelRenderablesList::VM_GROUP_OPAQUE ];
  1604. CViewModelRenderablesList::RenderGroups_t &translucentList = pList->m_RenderGroups[ CViewModelRenderablesList::VM_GROUP_TRANSLUCENT ];
  1605. for ( int i = m_ViewModels.Count()-1; i >= 0; --i )
  1606. {
  1607. ClientRenderHandle_t handle = m_ViewModels[i];
  1608. RenderableInfo_t& renderable = m_Renderables[handle];
  1609. // Early out on splitscreen renderables if we don't want to render them
  1610. if ( bIsSplitScreenActive )
  1611. {
  1612. if ( ( renderable.m_nSplitscreenEnabled & nSlotMask ) == 0 )
  1613. continue;
  1614. }
  1615. int nAlpha = renderable.m_pAlphaProperty ? renderable.m_pAlphaProperty->ComputeRenderAlpha( ) : 255;
  1616. bool bIsTransparent = ( nAlpha != 255 ) || ( renderable.m_nTranslucencyType != RENDERABLE_IS_OPAQUE );
  1617. // That's why we need to test RENDER_GROUP_OPAQUE_ENTITY - it may have changed in ComputeFXBlend()
  1618. if ( !bIsTransparent )
  1619. {
  1620. int nOpaqueIndex = opaqueList.AddToTail();
  1621. CViewModelRenderablesList::CEntry *pOpaqueEntry = &opaqueList[nOpaqueIndex];
  1622. pOpaqueEntry->m_pRenderable = renderable.m_pRenderable;
  1623. pOpaqueEntry->m_InstanceData.m_nAlpha = 255;
  1624. pOpaqueEntry->m_InstanceData.m_bTwoPass = false;
  1625. }
  1626. else
  1627. {
  1628. int i = translucentList.AddToTail();
  1629. CViewModelRenderablesList::CEntry *pTranslucentEntry = &translucentList[i];
  1630. pTranslucentEntry->m_pRenderable = renderable.m_pRenderable;
  1631. pTranslucentEntry->m_InstanceData.m_nAlpha = nAlpha;
  1632. if ( renderable.m_nTranslucencyType == RENDERABLE_IS_TWO_PASS )
  1633. {
  1634. pTranslucentEntry->m_InstanceData.m_bTwoPass = true;
  1635. int nOpaqueIndex = opaqueList.AddToTail();
  1636. CViewModelRenderablesList::CEntry *pOpaqueEntry = &opaqueList[nOpaqueIndex];
  1637. pOpaqueEntry->m_pRenderable = renderable.m_pRenderable;
  1638. pOpaqueEntry->m_InstanceData.m_nAlpha = 255;
  1639. pOpaqueEntry->m_InstanceData.m_bTwoPass = true;
  1640. }
  1641. else
  1642. {
  1643. pTranslucentEntry->m_InstanceData.m_bTwoPass = false;
  1644. }
  1645. }
  1646. }
  1647. }
  1648. //-----------------------------------------------------------------------------
  1649. // Sort entities in a back-to-front ordering
  1650. //-----------------------------------------------------------------------------
  1651. void CClientLeafSystem::SortEntities( const Vector &vecRenderOrigin, const Vector &vecRenderForward,
  1652. CClientRenderablesList::CEntry *pEntities, BuildRenderListInfo_t **pTranslucentRLInfo, int nEntities )
  1653. {
  1654. // Don't sort if we only have 1 entity
  1655. if ( nEntities <= 1 )
  1656. return;
  1657. float dists[CClientRenderablesList::MAX_GROUP_ENTITIES];
  1658. // First get a distance for each entity.
  1659. int i;
  1660. Vector boxcenter;
  1661. Vector delta;
  1662. for( i=0; i < nEntities; i++ )
  1663. {
  1664. VectorAdd( pTranslucentRLInfo[i]->m_vecMins, pTranslucentRLInfo[i]->m_vecMaxs, boxcenter );
  1665. boxcenter *= 0.5f;
  1666. // Compute distance...
  1667. VectorSubtract( boxcenter, vecRenderOrigin, delta );
  1668. dists[i] = DotProduct( delta, vecRenderForward );
  1669. }
  1670. // H-sort.
  1671. int stepSize = 4;
  1672. while( stepSize )
  1673. {
  1674. int end = nEntities - stepSize;
  1675. for( i=0; i < end; i += stepSize )
  1676. {
  1677. if( dists[i] > dists[i+stepSize] )
  1678. {
  1679. V_swap( pEntities[i], pEntities[i+stepSize] );
  1680. V_swap( dists[i], dists[i+stepSize] );
  1681. if( i == 0 )
  1682. {
  1683. i = -stepSize;
  1684. }
  1685. else
  1686. {
  1687. i -= stepSize << 1;
  1688. }
  1689. }
  1690. }
  1691. stepSize >>= 1;
  1692. }
  1693. }
  1694. //-----------------------------------------------------------------------------
  1695. // Extracts static props from the list of renderables
  1696. //-----------------------------------------------------------------------------
  1697. int CClientLeafSystem::ExtractStaticProps( int nCount, RenderableInfo_t **ppRenderables )
  1698. {
  1699. if ( m_DrawStaticProps )
  1700. return nCount;
  1701. int nUniqueCount = 0;
  1702. for ( int i = 0; i < nCount; ++i )
  1703. {
  1704. RenderableInfo_t *pInfo = ppRenderables[i];
  1705. if ( !IsLeafMarker( pInfo ) )
  1706. {
  1707. // Early out on static props if we don't want to render them
  1708. if ( pInfo->m_nModelType == RENDERABLE_MODEL_STATIC_PROP )
  1709. {
  1710. // Necessary for dependent models to be grabbed
  1711. pInfo->m_nRenderFrame--;
  1712. continue;
  1713. }
  1714. }
  1715. ppRenderables[nUniqueCount++] = pInfo;
  1716. }
  1717. return nUniqueCount;
  1718. }
  1719. //-----------------------------------------------------------------------------
  1720. // Extracts renderables that are excluded in splitscreen
  1721. //-----------------------------------------------------------------------------
  1722. int CClientLeafSystem::ExtractSplitscreenRenderables( int nCount, RenderableInfo_t **ppRenderables )
  1723. {
  1724. #ifdef PORTAL2
  1725. // Ignore splitscreen culling when looking through a portal
  1726. if ( g_pPortalRender->GetViewRecursionLevel() > 0 )
  1727. return nCount;
  1728. #else
  1729. if ( !IsSplitScreenSupported() )
  1730. return nCount;
  1731. if ( !engine->IsSplitScreenActive() )
  1732. return nCount;
  1733. #endif
  1734. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  1735. int nSlotMask = 1 << GET_ACTIVE_SPLITSCREEN_SLOT();
  1736. int nUniqueCount = 0;
  1737. for ( int i = 0; i < nCount; ++i )
  1738. {
  1739. RenderableInfo_t *pInfo = ppRenderables[i];
  1740. if ( !IsLeafMarker( pInfo ) )
  1741. {
  1742. // Early out on splitscreen renderables if we don't want to render them
  1743. if ( ( pInfo->m_nSplitscreenEnabled & nSlotMask ) == 0 )
  1744. {
  1745. // Necessary for dependent models to be grabbed
  1746. pInfo->m_nRenderFrame--;
  1747. continue;
  1748. }
  1749. }
  1750. ppRenderables[nUniqueCount++] = pInfo;
  1751. }
  1752. return nUniqueCount;
  1753. }
  1754. //-----------------------------------------------------------------------------
  1755. // Extracts models which are *not* marked for "fast reflections"
  1756. //-----------------------------------------------------------------------------
  1757. int CClientLeafSystem::ExtractNonFastReflectedRenderables( int nCount, RenderableInfo_t **ppRenderables )
  1758. {
  1759. int nReflectedCount = 0;
  1760. for ( int i = 0; i < nCount; ++ i )
  1761. {
  1762. RenderableInfo_t *pInfo = ppRenderables[i];
  1763. if ( !IsLeafMarker( pInfo ) )
  1764. {
  1765. if ( !pInfo->m_bRenderInFastReflection )
  1766. {
  1767. // Necessary for dependent models to be grabbed
  1768. pInfo->m_nRenderFrame--;
  1769. continue;
  1770. }
  1771. }
  1772. ppRenderables[nReflectedCount++] = pInfo;
  1773. }
  1774. return nReflectedCount;
  1775. }
  1776. //-----------------------------------------------------------------------------
  1777. // Extracts models which are *not* marked for "fast reflections"
  1778. //-----------------------------------------------------------------------------
  1779. int CClientLeafSystem::ExtractDisableShadowDepthRenderables( int nCount, RenderableInfo_t **ppRenderables )
  1780. {
  1781. if ( m_nDisableShadowDepthCount == 0 )
  1782. return nCount;
  1783. int nNewCount = 0;
  1784. for ( int i = 0; i < nCount; ++ i )
  1785. {
  1786. RenderableInfo_t *pInfo = ppRenderables[i];
  1787. if ( !IsLeafMarker( pInfo ) )
  1788. {
  1789. if ( pInfo->m_bDisableShadowDepthRendering )
  1790. {
  1791. // Necessary for dependent models to be grabbed
  1792. pInfo->m_nRenderFrame--;
  1793. continue;
  1794. }
  1795. }
  1796. ppRenderables[nNewCount++] = pInfo;
  1797. }
  1798. return nNewCount;
  1799. }
  1800. //-----------------------------------------------------------------------------
  1801. // Extracts models which are cacheable or not depending on what we render now
  1802. //-----------------------------------------------------------------------------
  1803. int CClientLeafSystem::ExtractDisableShadowDepthCacheRenderables( int nCount, RenderableInfo_t **ppRenderables )
  1804. {
  1805. int nNewCount = 0;
  1806. for ( int i = 0; i < nCount; ++ i )
  1807. {
  1808. RenderableInfo_t *pInfo = ppRenderables[i];
  1809. if ( !IsLeafMarker( pInfo ) )
  1810. {
  1811. if ( !pInfo->m_bDisableShadowDepthCaching ) // this means renderable is in depth cache and shouldn't be rendered again
  1812. {
  1813. // Necessary for dependent models to be grabbed
  1814. pInfo->m_nRenderFrame--;
  1815. continue;
  1816. }
  1817. }
  1818. ppRenderables[nNewCount++] = pInfo;
  1819. }
  1820. return nNewCount;
  1821. }
  1822. //-----------------------------------------------------------------------------
  1823. // Extracts duplicates
  1824. //-----------------------------------------------------------------------------
  1825. int CClientLeafSystem::ExtractDuplicates( int nFrameNumber, int nCount, RenderableInfo_t **ppRenderables )
  1826. {
  1827. // NOTE: We don't know whether these renderables are translucent or not
  1828. // but we do know if they participate in alternate sorting, which is all we need.
  1829. int nUniqueCount = 0;
  1830. int nLeaf = 0;
  1831. // For better sorting, we're gonna choose the leaf that is closest to the camera.
  1832. // The leaf list passed in here is sorted front to back
  1833. // FIXME: This algorithm won't work in a threaded context since it stores state in renderableinfo_t
  1834. if ( m_nAlternateSortCount == 0 )
  1835. {
  1836. // I expect this is the typical case; nothing needs alternate sorting
  1837. // look 8 entries ahead and precache to minimize cache misses
  1838. #if defined( _X360 ) || defined( _PS3 )
  1839. const int nNumPrefetchLookahead = 8;
  1840. int nPrefCount = MIN(nCount,nNumPrefetchLookahead);
  1841. int nPrefIterCount = MAX(nCount-nNumPrefetchLookahead,0);
  1842. for ( int i = 0; i < nPrefCount; i++ )
  1843. {
  1844. PREFETCH_128( ppRenderables[i], 0 );
  1845. }
  1846. #endif
  1847. for ( int i = 0; i < nCount; i++ )
  1848. {
  1849. #if defined( _X360 ) || defined( _PS3 )
  1850. if ( i < nPrefIterCount )
  1851. {
  1852. PREFETCH_128( ppRenderables[i+nNumPrefetchLookahead], 0 );
  1853. }
  1854. #endif
  1855. RenderableInfo_t *pInfo = ppRenderables[i];
  1856. if ( !IsLeafMarker( pInfo ) )
  1857. {
  1858. // Skip these bad boys altogether
  1859. if ( pInfo->m_Flags & ( RENDER_FLAGS_RENDER_WITH_VIEWMODELS | RENDER_FLAGS_DISABLE_RENDERING ) )
  1860. continue;
  1861. // If we've seen this already, then we don't need to add it
  1862. if ( pInfo->m_nRenderFrame == nFrameNumber )
  1863. continue;
  1864. pInfo->m_nRenderFrame = nFrameNumber;
  1865. }
  1866. ppRenderables[nUniqueCount++] = pInfo;
  1867. }
  1868. return nUniqueCount;
  1869. }
  1870. // Here, we have to worry about alternate sorting. I'm not sure if I
  1871. // can do better than 2n unless I cache off counts of each renderable
  1872. // in the first loop in BuildRenderablesList. I'm doing it this way
  1873. // because I don't believe we'll ever use this path.
  1874. int nAlternateSortCount = 0;
  1875. for ( int i = 0; i < nCount; ++i )
  1876. {
  1877. RenderableInfo_t *pInfo = ppRenderables[i];
  1878. if ( !IsLeafMarker( pInfo ) )
  1879. {
  1880. // If we've seen this already, then we don't need to add it
  1881. if ( ( pInfo->m_Flags & RENDER_FLAGS_ALTERNATE_SORTING ) == 0 )
  1882. {
  1883. if( pInfo->m_nRenderFrame == nFrameNumber )
  1884. continue;
  1885. pInfo->m_nRenderFrame = nFrameNumber;
  1886. }
  1887. else
  1888. {
  1889. // A little convoluted, but I don't want to store any unnecessary state
  1890. // Basically, the render frame will == frame number + duplication count by the end
  1891. // NOTE: This will produce a problem for a few frames every 4 billion frames when wraparound happens
  1892. // tough noogies
  1893. ++nAlternateSortCount;
  1894. if( pInfo->m_nRenderFrame < nFrameNumber )
  1895. pInfo->m_nRenderFrame = nFrameNumber + 1;
  1896. else
  1897. ++pInfo->m_nRenderFrame;
  1898. }
  1899. }
  1900. ppRenderables[nUniqueCount++] = pInfo;
  1901. }
  1902. if ( nAlternateSortCount )
  1903. {
  1904. // Extract out the renderables which use alternate sorting
  1905. nCount = nUniqueCount;
  1906. nUniqueCount = 0;
  1907. nLeaf = 0;
  1908. for ( int i = 0; i < nCount; ++i )
  1909. {
  1910. RenderableInfo_t *pInfo = ppRenderables[i];
  1911. if ( !IsLeafMarker( pInfo ) )
  1912. {
  1913. if ( pInfo->m_Flags & RENDER_FLAGS_ALTERNATE_SORTING )
  1914. {
  1915. // Add in the last one we encountered
  1916. if( --pInfo->m_nRenderFrame != nFrameNumber )
  1917. continue;
  1918. }
  1919. }
  1920. ppRenderables[nUniqueCount++] = pInfo;
  1921. }
  1922. }
  1923. return nUniqueCount;
  1924. }
  1925. //-----------------------------------------------------------------------------
  1926. // Extracts static props from the list of renderables
  1927. //-----------------------------------------------------------------------------
  1928. int CClientLeafSystem::ExtractTranslucentRenderables( int nCount, RenderableInfo_t **ppRenderables )
  1929. {
  1930. int nUniqueCount = 0;
  1931. for ( int i = 0; i < nCount; ++i )
  1932. {
  1933. RenderableInfo_t *pInfo = ppRenderables[i];
  1934. if ( !IsLeafMarker( pInfo ) )
  1935. {
  1936. if ( pInfo->m_nTranslucencyType == RENDERABLE_IS_TRANSLUCENT )
  1937. {
  1938. // Necessary for dependent models to be grabbed
  1939. pInfo->m_nRenderFrame--;
  1940. continue;
  1941. }
  1942. }
  1943. ppRenderables[nUniqueCount++] = pInfo;
  1944. }
  1945. return nUniqueCount;
  1946. }
  1947. #ifndef _GAMECONSOLE
  1948. static ConVar r_disable_distance_fade_on_big_props( "r_disable_distance_fade_on_big_props", "0", FCVAR_CHEAT, "Completely disable distance fading on large props" );
  1949. static ConVar r_disable_distance_fade_on_big_props_thresh( "r_disable_distance_fade_on_big_props_thresh", "48000", FCVAR_CHEAT, "Distance prop fade disable threshold size" );
  1950. #endif
  1951. //-----------------------------------------------------------------------------
  1952. // Computes translucency for all renderables
  1953. //-----------------------------------------------------------------------------
  1954. void CClientLeafSystem::ComputeDistanceFade( int nCount, AlphaInfo_t *pAlphaInfo, BuildRenderListInfo_t *pRLInfo, float flDistScale, const Vector& vecViewOrigin )
  1955. {
  1956. // Distance fade computations
  1957. float flDistFactorSq = 1.0f;
  1958. C_BasePlayer *pLocal = C_BasePlayer::GetLocalPlayer();
  1959. if ( pLocal && r_alphafade_usefov.GetBool() )
  1960. {
  1961. flDistFactorSq = pLocal->GetFOVDistanceAdjustFactor();
  1962. flDistFactorSq *= flDistFactorSq;
  1963. }
  1964. flDistFactorSq *= flDistScale*flDistScale;
  1965. #ifndef _GAMECONSOLE
  1966. const bool bDisableDistanceFadeOnBigProps = r_disable_distance_fade_on_big_props.GetBool();
  1967. const float flDistanceFadeDisableThreshold = r_disable_distance_fade_on_big_props_thresh.GetFloat();
  1968. #endif
  1969. for ( int i = 0; i < nCount; ++i )
  1970. {
  1971. CClientAlphaProperty *pAlphaProp = pAlphaInfo[i].m_pAlphaProperty;
  1972. if ( !pAlphaProp )
  1973. continue;
  1974. // Distance fade is inactive in this case
  1975. if ( pAlphaProp->m_nDistFadeEnd == 0 )
  1976. continue;
  1977. #ifndef _GAMECONSOLE
  1978. if ( bDisableDistanceFadeOnBigProps )
  1979. {
  1980. // Just disable distance fading on very large props for CS:GO - it looks terrible and is distracting in many cases, and doesn't help CPU perf much if at all.
  1981. Vector diag( pRLInfo[i].m_vecMaxs - pRLInfo[i].m_vecMins );
  1982. // Not really box volume - hacked so one function is useful on zero thickness boxes too.
  1983. float flFakeVol = ( diag.x * diag.x ) + ( diag.y * diag.y ) + ( diag.z * diag.z );
  1984. if ( flFakeVol > flDistanceFadeDisableThreshold )
  1985. continue;
  1986. }
  1987. #endif
  1988. float flCurrentDistanceSq;
  1989. if ( pAlphaProp->m_nDistanceFadeMode == CLIENT_ALPHA_DISTANCE_FADE_USE_CENTER )
  1990. {
  1991. flCurrentDistanceSq = flDistFactorSq * vecViewOrigin.DistToSqr( pAlphaInfo[i].m_vecCenter );
  1992. }
  1993. else
  1994. {
  1995. flCurrentDistanceSq = flDistFactorSq * CalcSqrDistanceToAABB( pRLInfo[i].m_vecMins, pRLInfo[i].m_vecMaxs, vecViewOrigin );
  1996. }
  1997. float flDistFadeStartSq = pAlphaProp->m_nDistFadeStart;
  1998. flDistFadeStartSq *= flDistFadeStartSq;
  1999. if ( flCurrentDistanceSq <= flDistFadeStartSq )
  2000. continue;
  2001. float flDistFadeEndSq = pAlphaProp->m_nDistFadeEnd;
  2002. flDistFadeEndSq *= flDistFadeEndSq;
  2003. if ( flCurrentDistanceSq >= flDistFadeEndSq )
  2004. {
  2005. pAlphaInfo[i].m_flFadeFactor = 0.0f;
  2006. continue;
  2007. }
  2008. // NOTE: Because of the if-checks above, flDistFadeEndSq != flDistFadeStartSq here
  2009. pAlphaInfo[i].m_flFadeFactor = ( flDistFadeEndSq - flCurrentDistanceSq ) / ( flDistFadeEndSq - flDistFadeStartSq );
  2010. }
  2011. }
  2012. float ComputeScreenSize( const Vector &vecOrigin, float flRadius, const ScreenSizeComputeInfo_t& info )
  2013. {
  2014. // This is sort of faked, but it's faster that way
  2015. // FIXME: Also, there's a much faster way to do this with similar triangles
  2016. // but I want to make sure it exactly matches the current matrices, so
  2017. // for now, I do it this conservative way
  2018. /*
  2019. Vector4D testPoint1, testPoint2;
  2020. VectorMA( vecOrigin, flRadius, info.m_vecViewUp, testPoint1.AsVector3D() );
  2021. VectorMA( vecOrigin, -flRadius, info.m_vecViewUp, testPoint2.AsVector3D() );
  2022. testPoint1.w = testPoint2.w = 1.0f;
  2023. Vector4D clipPos1, clipPos2;
  2024. Vector4DMultiply( info.m_matViewProj, testPoint1, clipPos1 );
  2025. Vector4DMultiply( info.m_matViewProj, testPoint2, clipPos2 );
  2026. if (clipPos1.w >= 0.001f)
  2027. {
  2028. clipPos1.y /= clipPos1.w;
  2029. }
  2030. else
  2031. {
  2032. clipPos1.y *= 1000;
  2033. }
  2034. if (clipPos2.w >= 0.001f)
  2035. {
  2036. clipPos2.y /= clipPos2.w;
  2037. }
  2038. else
  2039. {
  2040. clipPos2.y *= 1000;
  2041. }
  2042. // The divide-by-two here is because y goes from -1 to 1 in projection space
  2043. return info.m_nViewportHeight * fabs( clipPos2.y - clipPos1.y ) * 0.5f;
  2044. */
  2045. // NOTE: Optimized version of the above algorithm, which only uses y and w components of clip
  2046. // Can also optimize based on clipPos = a +/- b * r
  2047. const float *pViewProjY = info.m_matViewProj[1];
  2048. const float *pViewProjW = info.m_matViewProj[3];
  2049. float flODotY = pViewProjY[0] * vecOrigin.x + pViewProjY[1] * vecOrigin.y + pViewProjY[2] * vecOrigin.z + pViewProjY[3];
  2050. float flViewDotY = pViewProjY[0] * info.m_vecViewUp.x + pViewProjY[1] * info.m_vecViewUp.y + pViewProjY[2] * info.m_vecViewUp.z;
  2051. flViewDotY *= flRadius;
  2052. float flODotW = pViewProjW[0] * vecOrigin.x + pViewProjW[1] * vecOrigin.y + pViewProjW[2] * vecOrigin.z + pViewProjW[3];
  2053. float flViewDotW = pViewProjW[0] * info.m_vecViewUp.x + pViewProjW[1] * info.m_vecViewUp.y + pViewProjW[2] * info.m_vecViewUp.z;
  2054. flViewDotW *= flRadius;
  2055. float y0 = flODotY + flViewDotY;
  2056. float w0 = flODotW + flViewDotW;
  2057. y0 *= ( w0 >= 0.001f ) ? ( 1.0f / w0 ) : 1000.0f;
  2058. float y1 = flODotY - flViewDotY;
  2059. float w1 = flODotW - flViewDotW;
  2060. y1 *= ( w1 >= 0.001f ) ? ( 1.0f / w1 ) : 1000.0f;
  2061. // The divide-by-two here is because y goes from -1 to 1 in projection space
  2062. return info.m_nViewportHeight * fabs( y1 - y0 ) * 0.5f;
  2063. }
  2064. void ComputeScreenSizeInfo( ScreenSizeComputeInfo_t *pInfo )
  2065. {
  2066. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  2067. VMatrix viewMatrix, projectionMatrix;
  2068. pRenderContext->GetMatrix( MATERIAL_VIEW, &viewMatrix );
  2069. pRenderContext->GetMatrix( MATERIAL_PROJECTION, &projectionMatrix );
  2070. MatrixMultiply( projectionMatrix, viewMatrix, pInfo->m_matViewProj );
  2071. int x, y, w, h;
  2072. pRenderContext->GetViewport( x, y, w, h );
  2073. pInfo->m_nViewportHeight = h;
  2074. pRenderContext->GetWorldSpaceCameraVectors( NULL, NULL, &pInfo->m_vecViewUp );
  2075. }
  2076. void CClientLeafSystem::ComputeScreenFade( const ScreenSizeComputeInfo_t &info, float flMinScreenWidth, float flMaxScreenWidth, int nCount, AlphaInfo_t *pAlphaInfo )
  2077. {
  2078. if ( flMaxScreenWidth <= flMinScreenWidth )
  2079. {
  2080. flMaxScreenWidth = flMinScreenWidth;
  2081. }
  2082. if ( flMinScreenWidth <= 0 )
  2083. return;
  2084. float flFalloffFactor;
  2085. if ( flMaxScreenWidth != flMinScreenWidth )
  2086. {
  2087. flFalloffFactor = 1.0f / ( flMaxScreenWidth - flMinScreenWidth );
  2088. }
  2089. else
  2090. {
  2091. flFalloffFactor = 1.0f;
  2092. }
  2093. for ( int i = 0; i < nCount; ++i )
  2094. {
  2095. CClientAlphaProperty *pAlphaProp = pAlphaInfo[i].m_pAlphaProperty;
  2096. if ( !pAlphaProp )
  2097. continue;
  2098. // Fade is inactive in this case
  2099. if ( pAlphaProp->m_flFadeScale <= 0.0f )
  2100. continue;
  2101. float flPixelWidth = ComputeScreenSize( pAlphaInfo[i].m_vecCenter, pAlphaInfo[i].m_flRadius, info ) / pAlphaProp->m_flFadeScale;
  2102. // NOTE: This is to account for an error in the original screen computations years ago
  2103. flPixelWidth *= 2.0f;
  2104. float flAlpha = 0.0f;
  2105. if ( flPixelWidth > flMinScreenWidth )
  2106. {
  2107. if ( ( flMaxScreenWidth >= 0 ) && ( flPixelWidth < flMaxScreenWidth ) )
  2108. {
  2109. flAlpha = flFalloffFactor * (flPixelWidth - flMinScreenWidth );
  2110. }
  2111. else
  2112. {
  2113. flAlpha = 1.0f;
  2114. }
  2115. }
  2116. pAlphaInfo[i].m_flFadeFactor = MIN( pAlphaInfo[i].m_flFadeFactor, flAlpha );
  2117. }
  2118. }
  2119. extern ConVar cl_leveloverview;
  2120. #ifdef _DEBUG
  2121. extern ConVar r_FadeProps;
  2122. #endif
  2123. int CClientLeafSystem::ComputeTranslucency( int nFrameNumber, int nViewID, int nCount, RenderableInfo_t **ppRenderables, BuildRenderListInfo_t *pRLInfo, const ScreenSizeComputeInfo_t &screenSizeInfo, const Vector& vecViewOrigin )
  2124. {
  2125. SNPROF("CClientLeafSystem::ComputeTranslucency");
  2126. AlphaInfo_t *pAlphaInfo = (AlphaInfo_t*)stackalloc( nCount * sizeof(AlphaInfo_t) );
  2127. for ( int i = 0; i < nCount; ++i )
  2128. {
  2129. RenderableInfo_t *pInfo = ppRenderables[i];
  2130. if ( IsLeafMarker( pInfo ) )
  2131. {
  2132. pAlphaInfo[i].m_pAlphaProperty = NULL;
  2133. continue;
  2134. }
  2135. Vector vecCenter;
  2136. VectorAdd( pRLInfo[i].m_vecMaxs, pRLInfo[i].m_vecMins, vecCenter );
  2137. vecCenter *= 0.5f;
  2138. pAlphaInfo[i].m_vecCenter = vecCenter;
  2139. pAlphaInfo[i].m_flRadius = vecCenter.DistTo( pRLInfo[i].m_vecMaxs );
  2140. pAlphaInfo[i].m_pAlphaProperty = pInfo->m_pAlphaProperty;
  2141. pAlphaInfo[i].m_flFadeFactor = 1.0f;
  2142. }
  2143. for ( int i = 0; i < nCount; ++i )
  2144. {
  2145. // FIXME: Computing the base alpha could potentially be sorted by renderfx type
  2146. CClientAlphaProperty *pAlphaProp = pAlphaInfo[i].m_pAlphaProperty;
  2147. if ( pAlphaProp )
  2148. {
  2149. uint8 nAlpha = pAlphaProp->CClientAlphaProperty::ComputeRenderAlpha( );
  2150. bool bIgnoreZBuffer = pAlphaProp->CClientAlphaProperty::IgnoresZBuffer();
  2151. pRLInfo[i].m_nAlpha = nAlpha;
  2152. pRLInfo[i].m_bIgnoreZBuffer = bIgnoreZBuffer;
  2153. }
  2154. else
  2155. {
  2156. pRLInfo[i].m_nAlpha = 255;
  2157. pRLInfo[i].m_bIgnoreZBuffer = false;
  2158. }
  2159. }
  2160. // If we're taking devshots, don't fade props at all
  2161. bool bFadeProps = true;
  2162. #ifdef _DEBUG
  2163. bFadeProps = r_FadeProps.GetBool();
  2164. #endif
  2165. if ( nViewID == VIEW_3DSKY )
  2166. {
  2167. bFadeProps = false;
  2168. }
  2169. if ( !g_MakingDevShots && !cl_leveloverview.GetInt() && !input->CAM_IsThirdPersonOverview() && bFadeProps )
  2170. {
  2171. // We have three types of alpha fade calculation (the *minimum* of these alpha values is used):
  2172. // - distance fade (fade based on distance - set optionally, per-entity in Hammer,
  2173. // modified by a global cpu_level-based distance scale)
  2174. // - level screen fade (fade based on screen area - set optionally, on the map entity in Hammer)
  2175. // - global screen fade (fade based on screen area - set globally, based on cpu_level)
  2176. float flMinLevelFadeArea, flMaxLevelFadeArea;
  2177. float flMinGlobalFadeArea, flMaxGlobalFadeArea, flGlobalDistFadeScale;
  2178. modelinfo->GetLevelScreenFadeRange( &flMinLevelFadeArea, &flMaxLevelFadeArea );
  2179. view->GetScreenFadeDistances( &flMinGlobalFadeArea, &flMaxGlobalFadeArea, &flGlobalDistFadeScale );
  2180. ComputeDistanceFade( nCount, pAlphaInfo, pRLInfo, flGlobalDistFadeScale, vecViewOrigin );
  2181. if ( ( flMinLevelFadeArea > 0.0f ) || ( flMinGlobalFadeArea > 0.0f ) )
  2182. {
  2183. ComputeScreenFade( screenSizeInfo, flMinLevelFadeArea, flMaxLevelFadeArea, nCount, pAlphaInfo );
  2184. ComputeScreenFade( screenSizeInfo, flMinGlobalFadeArea, flMaxGlobalFadeArea, nCount, pAlphaInfo );
  2185. }
  2186. for ( int i = 0; i < nCount; ++i )
  2187. {
  2188. if ( !pAlphaInfo[i].m_pAlphaProperty )
  2189. continue;
  2190. float flAlpha = pRLInfo[i].m_nAlpha * pAlphaInfo[i].m_flFadeFactor;
  2191. int nAlpha = (int)flAlpha;
  2192. pRLInfo[i].m_nAlpha = clamp( nAlpha, 0, 255 );
  2193. }
  2194. }
  2195. // CTSRIKE15 only using cascade shadow mapping - code below is for projected shadow
  2196. #ifndef CSTRIKE15
  2197. // Update shadows
  2198. for ( int i = 0; i < nCount; ++i )
  2199. {
  2200. CClientAlphaProperty *pAlphaProp = pAlphaInfo[i].m_pAlphaProperty;
  2201. if ( !pAlphaProp || ( pAlphaInfo[i].m_pAlphaProperty->m_hShadowHandle == CLIENTSHADOW_INVALID_HANDLE ) )
  2202. continue;
  2203. int nAlpha = pRLInfo[i].m_nAlpha;
  2204. if ( pAlphaProp->m_bShadowAlphaOverride )
  2205. {
  2206. nAlpha = pAlphaProp->m_pOuter->GetClientRenderable()->OverrideShadowAlphaModulation( nAlpha );
  2207. nAlpha = clamp( nAlpha, 0, 255 );
  2208. }
  2209. g_pClientShadowMgr->SetFalloffBias( pAlphaInfo[i].m_pAlphaProperty->m_hShadowHandle, (255 - nAlpha) );
  2210. }
  2211. #endif
  2212. // Strip invisible ones out
  2213. int nUniqueCount = 0;
  2214. for ( int i = 0; i < nCount; ++i )
  2215. {
  2216. if ( !IsLeafMarker( ppRenderables[i] ) && ( !pRLInfo[i].m_nAlpha ) )
  2217. {
  2218. // Necessary for dependent models to be grabbed
  2219. ppRenderables[i]->m_nRenderFrame--;
  2220. continue;
  2221. }
  2222. ppRenderables[nUniqueCount] = ppRenderables[i];
  2223. pRLInfo[nUniqueCount] = pRLInfo[i];
  2224. ++nUniqueCount;
  2225. }
  2226. return nUniqueCount;
  2227. }
  2228. //-----------------------------------------------------------------------------
  2229. // Computes bounds for all renderables
  2230. //-----------------------------------------------------------------------------
  2231. void CClientLeafSystem::ComputeAllBounds( void )
  2232. {
  2233. VectorAligned vecAbsMins, vecAbsMaxs;
  2234. MDLCACHE_CRITICAL_SECTION();
  2235. for ( int i = m_Renderables.Head(); i != m_Renderables.InvalidIndex(); i = m_Renderables.Next( i ) )
  2236. {
  2237. RenderableInfo_t *pInfo = &m_Renderables[ i ];
  2238. if (pInfo->m_Flags & RENDER_FLAGS_DISABLE_RENDERING )
  2239. continue;
  2240. if ( ( pInfo->m_Flags & RENDER_FLAGS_BOUNDS_VALID ) == 0 )
  2241. {
  2242. CalcRenderableWorldSpaceAABB( pInfo->m_pRenderable, pInfo->m_vecAbsMins, pInfo->m_vecAbsMaxs );
  2243. if ( ( pInfo->m_Flags & RENDER_FLAGS_BOUNDS_ALWAYS_RECOMPUTE ) == 0 )
  2244. {
  2245. pInfo->m_Flags |= RENDER_FLAGS_BOUNDS_VALID;
  2246. }
  2247. }
  2248. #ifdef _DEBUG
  2249. else
  2250. {
  2251. // If these assertions trigger, it means there's some state that GetRenderBounds
  2252. // depends on which, on change, doesn't call ClientLeafSystem::RenderableChanged().
  2253. Vector vecTestMins, vecTestMaxs;
  2254. CalcRenderableWorldSpaceAABB( pInfo->m_pRenderable, vecTestMins, vecTestMaxs );
  2255. Assert( VectorsAreEqual( vecTestMins, pInfo->m_vecAbsMins, 1e-3 ) );
  2256. Assert( VectorsAreEqual( vecTestMaxs, pInfo->m_vecAbsMaxs, 1e-3 ) );
  2257. }
  2258. #endif
  2259. }
  2260. }
  2261. //-----------------------------------------------------------------------------
  2262. // Computes bounds for all renderables in the list
  2263. //-----------------------------------------------------------------------------
  2264. void CClientLeafSystem::ComputeBounds( int nCount, RenderableInfo_t **ppRenderables, BuildRenderListInfo_t *pRLInfo )
  2265. {
  2266. SNPROF("CClientLeafSystem::ComputeBounds");
  2267. // MiniProfilerGuard mpGuard(&g_mpComputeBounds);
  2268. for ( int i = 0; i < nCount; ++i )
  2269. {
  2270. RenderableInfo_t *pInfo = ppRenderables[i];
  2271. if ( IsLeafMarker( pInfo ) )
  2272. continue;
  2273. // UNDONE: Investigate speed tradeoffs of occlusion culling brush models too?
  2274. pRLInfo[i].m_bPerformOcclusionTest = ( pInfo->m_nModelType == RENDERABLE_MODEL_STATIC_PROP || pInfo->m_nModelType == RENDERABLE_MODEL_STUDIOMDL );
  2275. pRLInfo[i].m_nArea = pInfo->m_Area;
  2276. pRLInfo[i].m_nAlpha = 255; // necessary to set for shadow depth rendering
  2277. // Bounds should be valid as ComputeAllBounds called from CViewRender::RenderView
  2278. pRLInfo[i].m_vecMins = pInfo->m_vecAbsMins;
  2279. pRLInfo[i].m_vecMaxs = pInfo->m_vecAbsMaxs;
  2280. }
  2281. }
  2282. //-----------------------------------------------------------------------------
  2283. // Culls renderables based on view frustum + areaportals
  2284. //-----------------------------------------------------------------------------
  2285. int CClientLeafSystem::ExtractCulledRenderables( int nCount, RenderableInfo_t **ppRenderables, BuildRenderListInfo_t *pRLInfo, Frustum_t** ppFrustumList )
  2286. {
  2287. SNPROF("CClientLeafSystem::ExtractCulledRenderables");
  2288. bool bPortalTestEnts = r_PortalTestEnts.GetBool() && !r_portalsopenall.GetBool();
  2289. // FIXME: sort by area and inline cull. Should make it a bunch faster
  2290. int nUniqueCount = 0;
  2291. if ( bPortalTestEnts )
  2292. {
  2293. for ( int i = 0; i < nCount; ++i )
  2294. {
  2295. RenderableInfo_t *pInfo = ppRenderables[i];
  2296. BuildRenderListInfo_t &rlInfo = pRLInfo[i];
  2297. if ( !IsLeafMarker( pInfo ) )
  2298. {
  2299. int frustumIndex = rlInfo.m_nArea + 1;
  2300. if ( ppFrustumList[frustumIndex]->CullBox( rlInfo.m_vecMins, rlInfo.m_vecMaxs ) )
  2301. {
  2302. // Necessary for dependent models to be grabbed
  2303. pInfo->m_nRenderFrame--;
  2304. continue;
  2305. }
  2306. }
  2307. pRLInfo[nUniqueCount] = rlInfo;
  2308. ppRenderables[nUniqueCount] = pInfo;
  2309. ++nUniqueCount;
  2310. }
  2311. return nUniqueCount;
  2312. }
  2313. // Debug mode, doesn't need to be fast
  2314. for ( int i = 0; i < nCount; ++i )
  2315. {
  2316. RenderableInfo_t *pInfo = ppRenderables[i];
  2317. BuildRenderListInfo_t &rlInfo = pRLInfo[i];
  2318. if ( !IsLeafMarker( pInfo ) )
  2319. {
  2320. // cull with main frustum
  2321. if ( ppFrustumList[0]->CullBox( rlInfo.m_vecMins, rlInfo.m_vecMaxs ) )
  2322. {
  2323. // Necessary for dependent models to be grabbed
  2324. pInfo->m_nRenderFrame--;
  2325. continue;
  2326. }
  2327. }
  2328. pRLInfo[nUniqueCount] = rlInfo;
  2329. ppRenderables[nUniqueCount] = pInfo;
  2330. ++nUniqueCount;
  2331. }
  2332. return nUniqueCount;
  2333. }
  2334. //-----------------------------------------------------------------------------
  2335. // Culls renderables based on occlusion
  2336. //-----------------------------------------------------------------------------
  2337. int CClientLeafSystem::ExtractOccludedRenderables( int occlusionViewId, int nCount, RenderableInfo_t **ppRenderables, BuildRenderListInfo_t *pRLInfo )
  2338. {
  2339. static ConVarRef r_occlusion("r_occlusion");
  2340. // occlusion is off, just return
  2341. if ( !r_occlusion.GetBool() )
  2342. return nCount;
  2343. int nUniqueCount = 0;
  2344. for ( int i = 0; i < nCount; ++i )
  2345. {
  2346. RenderableInfo_t *pInfo = ppRenderables[i];
  2347. BuildRenderListInfo_t &rlInfo = pRLInfo[i];
  2348. if ( !IsLeafMarker( pInfo ) )
  2349. {
  2350. if ( rlInfo.m_bPerformOcclusionTest )
  2351. {
  2352. // test to see if this renderable is occluded by the engine's occlusion system
  2353. if ( engine->IsOccluded( occlusionViewId, rlInfo.m_vecMins, rlInfo.m_vecMaxs ) )
  2354. {
  2355. // Necessary for dependent models to be grabbed
  2356. pInfo->m_nRenderFrame--;
  2357. continue;
  2358. }
  2359. }
  2360. }
  2361. pRLInfo[nUniqueCount] = rlInfo;
  2362. ppRenderables[nUniqueCount] = pInfo;
  2363. ++nUniqueCount;
  2364. }
  2365. return nUniqueCount;
  2366. }
  2367. //-----------------------------------------------------------------------------
  2368. // Adds renderables into their final lists
  2369. //-----------------------------------------------------------------------------
  2370. void CClientLeafSystem::AddDependentRenderables( const SetupRenderInfo_t &info )
  2371. {
  2372. // NOTE: This turns out to have non-zero cost.
  2373. // Remove early out if we actually end up needing to use this
  2374. return;
  2375. CClientRenderablesList *pRenderList = info.m_pRenderList;
  2376. pRenderList->m_nBoneSetupDependencyCount = 0;
  2377. for ( int i = 0; i < RENDER_GROUP_COUNT; ++i )
  2378. {
  2379. int nCount = pRenderList->m_RenderGroupCounts[i];
  2380. for ( int j = 0; j < nCount; ++j )
  2381. {
  2382. IClientRenderable *pRenderable = pRenderList->m_RenderGroups[i][j].m_pRenderable;
  2383. C_BaseEntity *pEnt = pRenderable->GetIClientUnknown()->GetBaseEntity();
  2384. if ( !pEnt )
  2385. continue;
  2386. while ( pEnt->IsFollowingEntity() || ( pEnt->GetMoveParent() && pEnt->GetParentAttachment() > 0 ) )
  2387. {
  2388. pEnt = pEnt->GetMoveParent();
  2389. ClientRenderHandle_t hParent = pEnt->GetRenderHandle();
  2390. Assert( hParent != INVALID_CLIENT_RENDER_HANDLE );
  2391. if ( hParent == INVALID_CLIENT_RENDER_HANDLE )
  2392. continue;
  2393. RenderableInfo_t &parentInfo = m_Renderables[hParent];
  2394. if ( parentInfo.m_nRenderFrame != info.m_nRenderFrame )
  2395. {
  2396. parentInfo.m_nRenderFrame = info.m_nRenderFrame;
  2397. pRenderList->m_pBoneSetupDependency[ pRenderList->m_nBoneSetupDependencyCount++ ] = pEnt->GetClientRenderable();
  2398. }
  2399. }
  2400. }
  2401. }
  2402. }
  2403. //-----------------------------------------------------------------------------
  2404. // Adds renderables into their final lists
  2405. //-----------------------------------------------------------------------------
  2406. void CClientLeafSystem::AddRenderablesToRenderLists( const SetupRenderInfo_t &info, int nCount, RenderableInfo_t **ppRenderables, BuildRenderListInfo_t *pRLInfo, int nDetailCount, DetailRenderableInfo_t *pDetailInfo )
  2407. {
  2408. SNPROF("CClientLeafSystem::AddRenderablesToRenderLists");
  2409. // Vitaliy (2/15/2013) -- stop rendering the detail props since the rendering code crashes when they are rendered anyways
  2410. nDetailCount = 0;
  2411. CClientRenderablesList::CEntry *pTranslucentEntries = info.m_pRenderList->m_RenderGroups[RENDER_GROUP_TRANSLUCENT];
  2412. int &nTranslucentEntries = info.m_pRenderList->m_RenderGroupCounts[RENDER_GROUP_TRANSLUCENT];
  2413. BuildRenderListInfo_t **pTranslucentRLInfo = (BuildRenderListInfo_t**)stackalloc( nCount * sizeof(BuildRenderListInfo_t*) );
  2414. #if 0//defined(_PS3)
  2415. bool bPortalTestEnts = r_PortalTestEnts.GetBool() && !r_portalsopenall.GetBool();
  2416. Frustum_t *list[MAX_MAP_AREAS];
  2417. if ( bPortalTestEnts )
  2418. {
  2419. engine->GetFrustumList( list, ARRAYSIZE(list) );
  2420. }
  2421. #endif
  2422. int nTranslucent = 0;
  2423. int nCurDetail = 0;
  2424. int nTLucInfoCount = 0;
  2425. int nWorldListLeafIndex = -1;
  2426. for ( int i = 0; i < nCount; ++i )
  2427. {
  2428. RenderableInfo_t *pInfo = ppRenderables[i];
  2429. if ( IsLeafMarker( pInfo ) )
  2430. {
  2431. // Add detail props for this leaf
  2432. if ( !info.m_bDrawDepthViewNonCachedObjectsOnly ) // Detail props are considered cacheable
  2433. {
  2434. for( ; nCurDetail < nDetailCount; ++nCurDetail )
  2435. {
  2436. Assert( 0 );
  2437. DetailRenderableInfo_t &detailInfo = pDetailInfo[nCurDetail];
  2438. if ( detailInfo.m_nLeafIndex > nWorldListLeafIndex )
  2439. break;
  2440. Assert( detailInfo.m_nLeafIndex == nWorldListLeafIndex );
  2441. AddRenderableToRenderList( *info.m_pRenderList, detailInfo.m_pRenderable,
  2442. nWorldListLeafIndex, detailInfo.m_nRenderGroup, RENDERABLE_MODEL_ENTITY, detailInfo.m_InstanceData.m_nAlpha,
  2443. false, // detail props are allowed to be cached
  2444. false // single pass
  2445. );
  2446. }
  2447. }
  2448. int nNewTranslucent = nTranslucentEntries - nTranslucent;
  2449. if ( ( nNewTranslucent != 0 ) && info.m_bDrawTranslucentObjects )
  2450. {
  2451. // Sort the new translucent entities.
  2452. Assert( nNewTranslucent == nTLucInfoCount );
  2453. SortEntities( info.m_vecRenderOrigin, info.m_vecRenderForward, &pTranslucentEntries[nTranslucent], pTranslucentRLInfo, nNewTranslucent );
  2454. }
  2455. nTranslucent = nTranslucentEntries;
  2456. nTLucInfoCount = 0;
  2457. nWorldListLeafIndex++;
  2458. continue;
  2459. }
  2460. #if 0//defined(_PS3)
  2461. {
  2462. // two pass culling - recalc AABB and re-cull if still invalid since we didn't perform this pass on SPU
  2463. if ( ( pInfo->m_Flags & RENDER_FLAGS_BOUNDS_VALID ) == 0 )
  2464. {
  2465. CalcRenderableWorldSpaceAABB( pInfo->m_pRenderable, pInfo->m_vecAbsMins, pInfo->m_vecAbsMaxs );
  2466. if ( ( pInfo->m_Flags & RENDER_FLAGS_BOUNDS_ALWAYS_RECOMPUTE ) == 0 )
  2467. {
  2468. // NOTE: If aiments aren't showing up sometimes, we need to either fix
  2469. // invalidatephysicsrecursive for aiments (best fix, but may be harder)
  2470. // or we should not or this in for aiments
  2471. pInfo->m_Flags |= RENDER_FLAGS_BOUNDS_VALID;
  2472. }
  2473. // don't add if culled
  2474. BuildRenderListInfo_t &rlInfo = pRLInfo[i];
  2475. pRLInfo[i].m_vecMins = pInfo->m_vecAbsMins;
  2476. pRLInfo[i].m_vecMaxs = pInfo->m_vecAbsMaxs;
  2477. int frustumIndex = rlInfo.m_nArea + 1;
  2478. if ( list[frustumIndex]->CullBox( rlInfo.m_vecMins, rlInfo.m_vecMaxs ) )
  2479. {
  2480. // Necessary for dependent models to be grabbed
  2481. pInfo->m_nRenderFrame--;
  2482. continue;
  2483. }
  2484. // cull with main frustum
  2485. if ( engine->CullBox( rlInfo.m_vecMins, rlInfo.m_vecMaxs ) )
  2486. {
  2487. // Necessary for dependent models to be grabbed
  2488. pInfo->m_nRenderFrame--;
  2489. continue;
  2490. }
  2491. }
  2492. }
  2493. #endif
  2494. bool bIsTranslucent = ( pRLInfo[i].m_nAlpha != 255 ) || ( pInfo->m_nTranslucencyType != RENDERABLE_IS_OPAQUE );
  2495. if ( !bIsTranslucent || (pInfo->m_Flags & RENDER_FLAGS_FORCE_OPAQUE_PASS) )
  2496. {
  2497. AddRenderableToRenderList( *info.m_pRenderList, pInfo->m_pRenderable,
  2498. nWorldListLeafIndex, RENDER_GROUP_OPAQUE, pInfo->m_nModelType, pRLInfo[i].m_nAlpha, pInfo->m_bDisableShadowDepthCaching );
  2499. continue;
  2500. }
  2501. // FIXME: Remove call to GetFXBlend
  2502. bool bIsTwoPass = ( pInfo->m_nTranslucencyType == RENDERABLE_IS_TWO_PASS ) && ( pRLInfo[i].m_nAlpha == 255 ); // Two pass?
  2503. // Add to appropriate list if drawing translucent objects (shadow depth mapping will skip this)
  2504. if ( info.m_bDrawTranslucentObjects )
  2505. {
  2506. RenderGroup_t group;
  2507. if ( !pRLInfo[i].m_bIgnoreZBuffer )
  2508. {
  2509. group = RENDER_GROUP_TRANSLUCENT;
  2510. pTranslucentRLInfo[nTLucInfoCount++] = &pRLInfo[i];
  2511. }
  2512. else
  2513. {
  2514. group = RENDER_GROUP_TRANSLUCENT_IGNOREZ;
  2515. }
  2516. AddRenderableToRenderList( *info.m_pRenderList, pInfo->m_pRenderable,
  2517. nWorldListLeafIndex, group, pInfo->m_nModelType, pRLInfo[i].m_nAlpha, pInfo->m_bDisableShadowDepthCaching, bIsTwoPass );
  2518. }
  2519. if ( bIsTwoPass ) // Also add to opaque list if it's a two-pass model...
  2520. {
  2521. AddRenderableToRenderList( *info.m_pRenderList, pInfo->m_pRenderable,
  2522. nWorldListLeafIndex, RENDER_GROUP_OPAQUE, pInfo->m_nModelType, 255, pInfo->m_bDisableShadowDepthCaching, bIsTwoPass );
  2523. }
  2524. }
  2525. // Add detail props for this leaf
  2526. for( ; nCurDetail < nDetailCount; ++nCurDetail )
  2527. {
  2528. Assert( 0 );
  2529. DetailRenderableInfo_t &detailInfo = pDetailInfo[nCurDetail];
  2530. if ( detailInfo.m_nLeafIndex > nWorldListLeafIndex )
  2531. break;
  2532. Assert( detailInfo.m_nLeafIndex == nWorldListLeafIndex );
  2533. AddRenderableToRenderList( *info.m_pRenderList, detailInfo.m_pRenderable,
  2534. nWorldListLeafIndex, detailInfo.m_nRenderGroup, RENDERABLE_MODEL_ENTITY, detailInfo.m_InstanceData.m_nAlpha,
  2535. false, // detail props are allowed to be cached
  2536. false // single pass
  2537. );
  2538. }
  2539. int nNewTranslucent = nTranslucentEntries - nTranslucent;
  2540. if( ( nNewTranslucent != 0 ) && info.m_bDrawTranslucentObjects )
  2541. {
  2542. // Sort the new translucent entities.
  2543. Assert( nNewTranslucent == nTLucInfoCount );
  2544. SortEntities( info.m_vecRenderOrigin, info.m_vecRenderForward, &pTranslucentEntries[nTranslucent], pTranslucentRLInfo, nNewTranslucent );
  2545. }
  2546. AddDependentRenderables( info );
  2547. }
  2548. static ConVar r_drawallrenderables( "r_drawallrenderables", "0", FCVAR_CHEAT, "Draw all renderables, even ones inside solid leaves." );
  2549. extern ConVar r_flashlight_nostaticgeo;
  2550. static ConVar r_fastreflectionfastpath( "r_fastreflectionfastpath", "1" );
  2551. void CClientLeafSystem::BuildRenderablesListForFastReflections( const SetupRenderInfo_t &info )
  2552. {
  2553. for ( int i = m_Renderables.Head(); i != m_Renderables.InvalidIndex(); i = m_Renderables.Next( i ) )
  2554. {
  2555. RenderableInfo_t *pInfo = &m_Renderables[ i ];
  2556. if ( pInfo->m_Flags & ( RENDER_FLAGS_RENDER_WITH_VIEWMODELS | RENDER_FLAGS_DISABLE_RENDERING ) )
  2557. continue;
  2558. // If we've seen this already, then we don't need to add it
  2559. if ( pInfo->m_nRenderFrame == info.m_nRenderFrame )
  2560. continue;
  2561. pInfo->m_nRenderFrame = info.m_nRenderFrame;
  2562. if ( pInfo->m_bRenderInFastReflection )
  2563. {
  2564. // Use frustum 0 instead of [area index + 1] beacuse we're not guaranteed to have valid per-area frustums
  2565. // wehn taking the simple world model + fast reflection path.
  2566. // Frustum 0 is always valid (and more conservative than area frustums in slots 1, 2, 3...) because it's the camera frustum,
  2567. // whereas the area frustums are smaller/refined frusta that result from clipping the camera frustum against 2D screen-space area portals
  2568. int nFrustumIndex = 0; // pInfo->m_Area + 1;
  2569. // Bounds should be valid as ComputeAllBounds called from CViewRender::RenderView
  2570. if ( !info.m_ppFrustumList[ nFrustumIndex ]->CullBox( pInfo->m_vecAbsMins, pInfo->m_vecAbsMaxs ) )
  2571. {
  2572. RenderGroup_t renderGroup = RENDER_GROUP_OPAQUE;
  2573. CClientAlphaProperty *pAlphaProp = pInfo->m_pAlphaProperty;
  2574. if ( pAlphaProp )
  2575. {
  2576. int nAlpha = pAlphaProp->ComputeRenderAlpha();
  2577. bool bIsTranslucent = ( nAlpha != 255 ) || ( pInfo->m_nTranslucencyType != RENDERABLE_IS_OPAQUE );
  2578. if ( bIsTranslucent )
  2579. {
  2580. renderGroup = pAlphaProp->IgnoresZBuffer() ? RENDER_GROUP_TRANSLUCENT_IGNOREZ : RENDER_GROUP_TRANSLUCENT;
  2581. }
  2582. }
  2583. AddRenderableToRenderList( *info.m_pRenderList, pInfo->m_pRenderable,
  2584. 0, renderGroup, pInfo->m_nModelType, 255, pInfo->m_bDisableShadowDepthCaching );
  2585. }
  2586. }
  2587. }
  2588. }
  2589. #ifndef _CERT
  2590. ConVar r_highlight_translucent_renderables( "r_highlight_translucent_renderables", "0" );
  2591. #endif // _CERT
  2592. void CClientLeafSystem::HighlightAllTranslucentRenderables()
  2593. {
  2594. for ( int i = m_Renderables.Head(); i != m_Renderables.InvalidIndex(); i = m_Renderables.Next( i ) )
  2595. {
  2596. RenderableInfo_t &info = m_Renderables[i];
  2597. int nAlpha = info.m_pAlphaProperty ? info.m_pAlphaProperty->ComputeRenderAlpha( ) : 255;
  2598. bool bIsTranslucent = ( nAlpha != 255 ) || ( info.m_nTranslucencyType != RENDERABLE_IS_OPAQUE );
  2599. if ( bIsTranslucent )
  2600. {
  2601. C_BaseEntity *pEntity = dynamic_cast< C_BaseEntity * >( info.m_pRenderable );
  2602. if ( pEntity )
  2603. {
  2604. Vector vecSurroundMins, vecSurroundMaxs;
  2605. pEntity->CollisionProp()->WorldSpaceSurroundingBounds( &vecSurroundMins, &vecSurroundMaxs );
  2606. Vector center = 0.5f * (vecSurroundMins + vecSurroundMaxs);
  2607. Vector extents = vecSurroundMaxs - center;
  2608. NDebugOverlay::Box( center, -extents, extents, 150, 150, 0, 0, 0 );
  2609. NDebugOverlay::EntityTextAtPosition( center, 0, pEntity->GetDebugName(), 0, 255, 255, 255, 255 );
  2610. }
  2611. }
  2612. }
  2613. }
  2614. #if defined(_PS3)
  2615. // 7LS TODO: get rid of these literals!
  2616. struct SPURenderListData
  2617. {
  2618. int m_orderedListCount_PS3;
  2619. int m_detailRenderablesCount_PS3;
  2620. bool m_bEpilogue;
  2621. SetupRenderInfo_t m_info;
  2622. CClientLeafSystem::RenderableInfo_t *m_orderedList_PS3[4096] ALIGN16;
  2623. DetailRenderableInfo_t m_detailRenderables_PS3[2048] ALIGN16;
  2624. CClientLeafSystem::BuildRenderListInfo_t m_RLInfo_PS3[4096] ALIGN16;
  2625. };
  2626. SPURenderListData g_SPURLData[ MAX_CONCURRENT_BUILDVIEWS ] ALIGN16;
  2627. //-----------------------------------------------------------------------------
  2628. // Init and push SPURS job for BuildRenderablesList
  2629. //-----------------------------------------------------------------------------
  2630. int g_debugViewID_DEBUG= 0;
  2631. uint32 g_debugRendAddr = 0;
  2632. void CClientLeafSystem::BuildRenderablesList_SPURSJob( const SetupRenderInfo_t &info,
  2633. RenderableInfo_t **ppEA_Renderables, int *pEA_RenderablesCount,
  2634. DetailRenderableInfo_t *pEA_DetailRenderables, int *pEA_DetailRenderablesCount,
  2635. BuildRenderListInfo_t *pEA_RLInfo )
  2636. {
  2637. SNPROF("CClientLeafSystem::BuildRenderablesList_SPURSJob");
  2638. static ConVarRef r_occlusion("r_occlusion");
  2639. static int cascadeID = 0;
  2640. static bool bLastJobPushedCSM = false;
  2641. PS3BuildRenderablesJobData *pJobData = g_pBuildRenderablesJob->GetJobData( g_viewBuilder.GetBuildViewID() );
  2642. // fill SPU job struct
  2643. buildRenderablesJob_SPU *pJob_SPU = &pJobData->buildRenderablesJobSPU;
  2644. pJob_SPU->debugJob = r_PS3_SPU_buildrenderables.GetInt();
  2645. pJob_SPU->debugViewID = g_viewBuilder.GetBuildViewID();
  2646. pJob_SPU->debugViewID_DEBUG = g_debugViewID_DEBUG;
  2647. pJob_SPU->pEA_debugRenderable = g_debugRendAddr;
  2648. pJob_SPU->info = info;
  2649. pJob_SPU->pEA_worldbrush_leafs = engine->GetHostStateWorldBrush();
  2650. pJob_SPU->viewOrigin = CurrentViewOrigin();
  2651. pJob_SPU->pEA_clientRenderablesList_RenderGroups = (void *)info.m_pRenderList->m_RenderGroups;
  2652. pJob_SPU->pEA_clientRenderablesList_RenderGroupCounts = (void *)info.m_pRenderList->m_RenderGroupCounts;
  2653. pJob_SPU->pEA_clientleafsystem_mleaf = s_ClientLeafSystem.m_Leaf.Base();
  2654. void **ppTmp = (void **)&m_RenderablesInLeaf;
  2655. pJob_SPU->pEA_renderablesInLeafLIST = (void *)(*ppTmp);
  2656. void **ppRenderables = (void **)&m_Renderables;
  2657. pJob_SPU->pEA_renderablesLIST = (void *)(*ppRenderables);
  2658. pJob_SPU->renderablesHeadIdx = m_Renderables.Head();
  2659. pJob_SPU->info_mpRenderList_mDetailFade = info.m_pRenderList->m_DetailFade;
  2660. pJob_SPU->maxCount = m_Renderables.Count(); // what about duplicates??
  2661. pJob_SPU->buildFastReflectionRenderables= info.m_bFastEntityRendering && r_fastreflectionfastpath.GetBool();
  2662. // Get Frustums
  2663. pJob_SPU->pEA_frustums[ 0 ] = g_viewBuilder.GetBuildViewFrustum();
  2664. for( int lp = 0; lp < g_viewBuilder.GetNumAreaFrustum(); lp++ )
  2665. {
  2666. if( engine->ShouldUseAreaFrustum( lp ) )
  2667. {
  2668. pJob_SPU->pEA_frustums[ lp+1 ] = g_viewBuilder.GetBuildViewAreaFrustumID( lp );
  2669. }
  2670. else
  2671. {
  2672. pJob_SPU->pEA_frustums[ lp+1 ] = g_viewBuilder.GetBuildViewFrustum();
  2673. }
  2674. }
  2675. pJob_SPU->numAreaFrustums = g_viewBuilder.GetNumAreaFrustum() + 1;
  2676. C_BasePlayer *pLocal = C_BasePlayer::GetLocalPlayer();
  2677. float flFactor = pLocal ? pLocal->GetFOVDistanceAdjustFactor() : 1.0f;
  2678. pJob_SPU->flFactor = flFactor;
  2679. g_pDetailObjectSystem->GetDetailFadeValues( pJob_SPU->flDetailFadeStart, pJob_SPU->flDetailFadeEnd );
  2680. modelinfo->GetLevelScreenFadeRange( &pJob_SPU->flMinLevelFadeArea, &pJob_SPU->flMaxLevelFadeArea );
  2681. view->GetScreenFadeDistances( &pJob_SPU->flMinGlobalFadeArea, &pJob_SPU->flMaxGlobalFadeArea, &pJob_SPU->flGlobalDistFadeScale );
  2682. pJob_SPU->bComputeScreenFade = 0;
  2683. if( ( pJob_SPU->flMinLevelFadeArea > 0.0f ) || ( pJob_SPU->flMinGlobalFadeArea > 0.0f ) )
  2684. {
  2685. ScreenSizeComputeInfo_t ssinfo;
  2686. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  2687. VMatrix viewMatrix, projectionMatrix;
  2688. pRenderContext->GetMatrix( MATERIAL_VIEW, &viewMatrix );
  2689. pRenderContext->GetMatrix( MATERIAL_PROJECTION, &projectionMatrix );
  2690. MatrixMultiply( projectionMatrix, viewMatrix, ssinfo.m_matViewProj );
  2691. int x, y, w, h;
  2692. pRenderContext->GetViewport( x, y, w, h );
  2693. ssinfo.m_nViewportHeight = h;
  2694. pRenderContext->GetWorldSpaceCameraVectors( NULL, NULL, &ssinfo.m_vecViewUp );
  2695. pJob_SPU->bComputeScreenFade = 1;
  2696. pJob_SPU->screensizecomputeinfo = ssinfo;
  2697. }
  2698. pJob_SPU->shouldDrawDetailObjects = g_pDetailObjectSystem->ShouldDrawDetailObjects();
  2699. pJob_SPU->detailObjects_count = g_pDetailObjectSystem->GetDetailObjectsCount();
  2700. if( pJob_SPU->detailObjects_count )
  2701. {
  2702. pJob_SPU->pEA_detailObjects = g_pDetailObjectSystem->GetDetailObjectsBase();
  2703. pJob_SPU->pEA_detailObjects_origin = g_pDetailObjectSystem->GetDetailObjectsOriginOffset();
  2704. }
  2705. pJob_SPU->strideCDetailModel = g_pDetailObjectSystem->GetCDetailModelStride();
  2706. pJob_SPU->r_drawallrenderables = r_drawallrenderables.GetInt();
  2707. pJob_SPU->r_portaltestents_AND_NOTr_portalsopenall = r_PortalTestEnts.GetBool() && !r_portalsopenall.GetBool();
  2708. pJob_SPU->r_occlusion = r_occlusion.GetBool();
  2709. pJob_SPU->clientleafsystem_alternateSortCount = m_nAlternateSortCount;
  2710. pJob_SPU->clientleafsystem_drawStaticProps = m_DrawStaticProps;
  2711. pJob_SPU->clientleafsystem_disableShadowDepthCount = m_nDisableShadowDepthCount;
  2712. pJob_SPU->frameCount = gpGlobals->framecount;
  2713. pJob_SPU->curTime = gpGlobals->curtime;
  2714. //out
  2715. pJob_SPU->ppEA_Renderables = ppEA_Renderables;
  2716. pJob_SPU->pEA_RenderablesCount = pEA_RenderablesCount;
  2717. pJob_SPU->pEA_DetailRenderables = pEA_DetailRenderables;
  2718. pJob_SPU->pEA_DetailRenderablesCount = pEA_DetailRenderablesCount;
  2719. pJob_SPU->pEA_RLInfo = pEA_RLInfo;
  2720. // push
  2721. job_buildrenderables::JobDescriptor_t *pJobDescriptor = &pJobData->jobDescriptor;
  2722. pJobDescriptor->header = g_buildRenderablesJobDescriptor.header;
  2723. pJobDescriptor->header.useInOutBuffer = 1;
  2724. pJobDescriptor->header.sizeStack = (32*1024)/16;
  2725. pJobDescriptor->header.sizeInOrInOut = 0;
  2726. pJobDescriptor->header.sizeDmaList = 0;
  2727. AddInputDma( pJobDescriptor, sizeof(buildRenderablesJob_SPU), pJob_SPU );
  2728. if( info.m_bCSMView )
  2729. {
  2730. pJob_SPU->bCSMView = true;
  2731. if( info.m_bCSMView )
  2732. {
  2733. if( bLastJobPushedCSM )
  2734. {
  2735. cascadeID++;
  2736. }
  2737. else
  2738. {
  2739. cascadeID = 0;
  2740. bLastJobPushedCSM = true;
  2741. }
  2742. }
  2743. pJob_SPU->cascadeID = cascadeID;
  2744. pJob_SPU->bDisableCSMCulling = cl_csm_disable_culling.GetBool();
  2745. pJob_SPU->bShadowEntities = cl_csm_entity_shadows.GetBool() && cl_csm_shadows.GetBool();
  2746. pJob_SPU->bShadowStaticProps = cl_csm_static_prop_shadows.GetBool() && cl_csm_shadows.GetBool();
  2747. pJob_SPU->bShadowSprites = cl_csm_sprite_shadows.GetBool() && cl_csm_shadows.GetBool();
  2748. pJob_SPU->bIgnoreDisableShadowDepthRendering = cl_csm_ignore_disable_shadow_depth_rendering.GetBool();
  2749. void *pVolColForSPU = g_viewBuilder.GetBuildViewVolumeCuller();
  2750. AddInputDma( pJobDescriptor, sizeof(CVolumeCuller), pVolColForSPU );
  2751. }
  2752. else
  2753. {
  2754. pJob_SPU->bCSMView = false;
  2755. }
  2756. if( r_PS3_SPU_BuildWRLists_ImmediateSync.GetInt() )
  2757. {
  2758. SNPROF("CClientLeafSystem::BuildRenderablesList_SPURSJob->Sync");
  2759. CELL_VERIFY( g_pBuildRenderablesJob->m_pRoot->m_queuePortBuildRenderables[ g_viewBuilder.GetBuildViewID() ].pushJob( &pJobDescriptor->header, sizeof(*pJobDescriptor), 0, CELL_SPURS_JOBQUEUE_FLAG_SYNC_JOB ) );
  2760. CELL_VERIFY( g_pBuildRenderablesJob->m_pRoot->m_queuePortBuildRenderables[ g_viewBuilder.GetBuildViewID() ].sync( 0 ) );
  2761. }
  2762. else
  2763. {
  2764. // OLD method of pushing buildrenderable jobs - we now do this at the end of pass1 allowing us to better schedule those jobs given the buildworld jobs can
  2765. // all run concurrently. The problem is in the documentation /implementation of pushsync and the impact it has on all jobs pushed prior to it.
  2766. // See implementation of push of buildrenderable jobs in viewrender.cpp - CConcurrentViewBuilder::PushBuildRenderableJobs
  2767. #if 0
  2768. int syncTag = 0;
  2769. // world job pushed, this job syncs (is dependant) against that one
  2770. if( g_viewBuilder.GetWorldRenderListElement() )
  2771. {
  2772. // some views don't build world lists (simpleworldmodel for waterreflection)
  2773. // to sync
  2774. syncTag = 1 + g_viewBuilder.GetBuildViewID();
  2775. // causes some particle 'popping' with this syncMask
  2776. //CELL_VERIFY( g_pBuildRenderablesJob->m_pRoot->m_queuePortBuildRenderables[ g_viewBuilder.GetBuildViewID() ].pushSync( 0x01 << syncTag, 0 ) );
  2777. //Msg("pushSync 0x%x\n", 0x01 << syncTag );
  2778. // or sync with all previous buildworld/buildrenderable jobs
  2779. int syncMask = 0;
  2780. for( int i = 0; i < (1 + g_viewBuilder.GetBuildViewID()); i++ )
  2781. {
  2782. syncMask |= (0x01 << (i+1));
  2783. }
  2784. CELL_VERIFY( g_pBuildRenderablesJob->m_pRoot->m_queuePortBuildRenderables[ g_viewBuilder.GetBuildViewID() ].pushSync( syncMask, 0 ) );
  2785. //Msg("pushSync 0x%x\n", syncMask );
  2786. }
  2787. CELL_VERIFY( g_pBuildRenderablesJob->m_pRoot->m_queuePortBuildRenderables[ g_viewBuilder.GetBuildViewID() ].pushJob( &pJobDescriptor->header, sizeof(*pJobDescriptor), syncTag, CELL_SPURS_JOBQUEUE_FLAG_SYNC_JOB ) );
  2788. //Msg("pushJob Renderable(%d) SyncTag(%d)\n", g_viewBuilder.GetBuildViewID(), syncTag );
  2789. #endif
  2790. }
  2791. }
  2792. //-----------------------------------------------------------------------------
  2793. // only call once per frame
  2794. //-----------------------------------------------------------------------------
  2795. void CClientLeafSystem::PrepRenderablesListForSPU( void )
  2796. {
  2797. // only want to do this once
  2798. SNPROF("CClientLeafSystem::PrepRenderablesListForSPU");
  2799. // reset view count
  2800. // update aabb's
  2801. if( ( r_PS3_SPU_buildrenderables.GetInt() > 0 ) )
  2802. {
  2803. // SPU path only - update all AABB's - see how long this takes, moving this code over to SPU not straightforward
  2804. // one time hit may be acceptable given the CSM views, etc
  2805. // will make the SPU code more manageable
  2806. VectorAligned vecAbsMins, vecAbsMaxs;
  2807. for ( int i = m_Renderables.Head(); i != m_Renderables.InvalidIndex(); i = m_Renderables.Next( i ) )
  2808. {
  2809. RenderableInfo_t *pInfo = &m_Renderables[ i ];
  2810. if ( ( pInfo->m_Flags & RENDER_FLAGS_BOUNDS_VALID ) == 0 )
  2811. {
  2812. CalcRenderableWorldSpaceAABB( pInfo->m_pRenderable, vecAbsMins, vecAbsMaxs );
  2813. pInfo->m_vecAbsMins = vecAbsMins;
  2814. pInfo->m_vecAbsMaxs = vecAbsMaxs;
  2815. //if ( ( pInfo->m_Flags & RENDER_FLAGS_BOUNDS_ALWAYS_RECOMPUTE ) == 0 ) // should be valid this frame for all views regardless, right? TODO - which ents have this set?
  2816. {
  2817. pInfo->m_Flags |= RENDER_FLAGS_BOUNDS_VALID;
  2818. }
  2819. }
  2820. }
  2821. }
  2822. }
  2823. #endif
  2824. void CClientLeafSystem::BuildRenderablesListForCSMView( const SetupRenderInfo_t &setupInfo )
  2825. {
  2826. //Frustum_t *list[MAX_MAP_AREAS];
  2827. //engine->GetFrustumList( list, ARRAYSIZE(list) );
  2828. const bool bDisableCSMCulling = cl_csm_disable_culling.GetBool();
  2829. const bool bShadowEntities = cl_csm_entity_shadows.GetBool() && cl_csm_shadows.GetBool();
  2830. const bool bShadowStaticProps = cl_csm_static_prop_shadows.GetBool() && cl_csm_shadows.GetBool();
  2831. const bool bShadowSprites = cl_csm_sprite_shadows.GetBool() && cl_csm_shadows.GetBool();
  2832. const bool bIgnoreDisableShadowDepthRendering = cl_csm_ignore_disable_shadow_depth_rendering.GetBool();
  2833. const bool bOptimizedCSMStaticProps = cl_csm_optimize_static_props.GetBool();
  2834. const CVolumeCuller *pCSMVolumeCuller = setupInfo.m_pCSMVolumeCuller;
  2835. for ( int i = m_Renderables.Head(); i != m_Renderables.InvalidIndex(); i = m_Renderables.Next( i ) )
  2836. {
  2837. RenderableInfo_t *pInfo = &m_Renderables[ i ];
  2838. if ( ( !bIgnoreDisableShadowDepthRendering ) && ( pInfo->m_bDisableShadowDepthRendering || ( pInfo->m_bDisableCSMRendering && bOptimizedCSMStaticProps ) ) )
  2839. continue;
  2840. if ( pInfo->m_Flags & ( RENDER_FLAGS_DISABLE_RENDERING | RENDER_FLAGS_RENDER_WITH_VIEWMODELS ) )
  2841. continue;
  2842. if ( !bShadowEntities )
  2843. {
  2844. if ( ( pInfo->m_nModelType == RENDERABLE_MODEL_ENTITY ) || ( pInfo->m_nModelType == RENDERABLE_MODEL_STUDIOMDL ) )
  2845. continue;
  2846. }
  2847. if ( ( !bShadowStaticProps ) && ( pInfo->m_nModelType == RENDERABLE_MODEL_STATIC_PROP ) )
  2848. continue;
  2849. if ( ( !bShadowSprites ) && ( pInfo->m_Flags & RENDER_FLAGS_IS_SPRITE ) )
  2850. continue;
  2851. // If we've seen this already, then we don't need to add it
  2852. if ( pInfo->m_nRenderFrame == setupInfo.m_nRenderFrame )
  2853. continue;
  2854. pInfo->m_nRenderFrame = setupInfo.m_nRenderFrame;
  2855. VectorAligned vecAbsMins, vecAbsMaxs;
  2856. // Bounds should be valid as ComputeAllBounds called from CViewRender::RenderView
  2857. vecAbsMins = pInfo->m_vecAbsMins;
  2858. vecAbsMaxs = pInfo->m_vecAbsMaxs;
  2859. if ( ( !bDisableCSMCulling ) && ( pCSMVolumeCuller ) && ( !pCSMVolumeCuller->CheckBox( vecAbsMins, vecAbsMaxs ) ) )
  2860. continue;
  2861. RenderGroup_t renderGroup = RENDER_GROUP_OPAQUE;
  2862. CClientAlphaProperty *pAlphaProp = pInfo->m_pAlphaProperty;
  2863. if ( pAlphaProp )
  2864. {
  2865. int nAlpha = pAlphaProp->ComputeRenderAlpha();
  2866. bool bIsTranslucent = ( nAlpha != 255 ) || ( pInfo->m_nTranslucencyType != RENDERABLE_IS_OPAQUE );
  2867. if ( bIsTranslucent )
  2868. {
  2869. renderGroup = pAlphaProp->IgnoresZBuffer() ? RENDER_GROUP_TRANSLUCENT_IGNOREZ : RENDER_GROUP_TRANSLUCENT;
  2870. }
  2871. }
  2872. AddRenderableToRenderList( *setupInfo.m_pRenderList, pInfo->m_pRenderable,
  2873. 0, renderGroup, pInfo->m_nModelType, 255, pInfo->m_bDisableShadowDepthCaching );
  2874. }
  2875. }
  2876. //-----------------------------------------------------------------------------
  2877. // Main entry point to build renderable lists
  2878. //-----------------------------------------------------------------------------
  2879. void CClientLeafSystem::BuildRenderablesList( const SetupRenderInfo_t &info )
  2880. {
  2881. ASSERT_NO_REENTRY();
  2882. SNPROF("CClientLeafSystem::BuildRenderablesList");
  2883. info.m_pWorldListInfo = g_viewBuilder.GetWorldListInfoElement( info.m_nBuildViewID );
  2884. info.m_pRenderList = g_viewBuilder.GetRenderablesListElement( info.m_nBuildViewID );
  2885. info.m_pCSMVolumeCuller = g_viewBuilder.GetBuildViewVolumeCuller( info.m_nBuildViewID );
  2886. info.m_pFrustum = g_viewBuilder.GetBuildViewFrustum( info.m_nBuildViewID );
  2887. info.m_ppFrustumList = g_viewBuilder.GetBuildViewFrustumList( info.m_nBuildViewID );
  2888. #ifndef _CERT
  2889. if ( r_highlight_translucent_renderables.GetBool() )
  2890. {
  2891. HighlightAllTranslucentRenderables();
  2892. }
  2893. #endif // _CERT
  2894. #if defined(_PS3)
  2895. int viewId = g_viewBuilder.GetBuildViewID();
  2896. SPURenderListData *pSPUDst = &g_SPURLData[ viewId ];
  2897. pSPUDst->m_bEpilogue = false;
  2898. #endif
  2899. if ( info.m_bFastEntityRendering && r_fastreflectionfastpath.GetBool() )
  2900. {
  2901. BuildRenderablesListForFastReflections( info );
  2902. return;
  2903. }
  2904. #if defined(_PS3)
  2905. int nCount_PS3;
  2906. RenderableInfo_t **ppRenderables_PS3;
  2907. if( ( r_PS3_SPU_buildrenderables.GetInt() > 0 ) && g_viewBuilder.IsSPUBuildRWJobsOn() )
  2908. {
  2909. // Run BuildRenderables on SPU
  2910. // this goes hand-in-hand with building worldlists on SPU and runs the job in parallel while the PPU continues
  2911. // a sync point is required while drawing and entry into here assumes 2 passes over the rendering
  2912. // lists are built during the 1st pass, drawn during the 2nd (where/when the jobs started in pass 1 are synced)
  2913. // world lists must be built before the renderables list can be. When kicking the renderables job, we must ensure
  2914. // we sync to the appropriate buildworldlist job (using pushsync command with the appropriate mask)
  2915. pSPUDst->m_bEpilogue = !info.m_bCSMView;
  2916. memcpy( &pSPUDst->m_info, &info, sizeof(SetupRenderInfo_t) );
  2917. BuildRenderablesList_SPURSJob( pSPUDst->m_info, pSPUDst->m_orderedList_PS3, &pSPUDst->m_orderedListCount_PS3, pSPUDst->m_detailRenderables_PS3, &pSPUDst->m_detailRenderablesCount_PS3, pSPUDst->m_RLInfo_PS3 );
  2918. }
  2919. else
  2920. {
  2921. #endif
  2922. if ( info.m_bCSMView )
  2923. {
  2924. BuildRenderablesListForCSMView( info );
  2925. return;
  2926. }
  2927. // Deal with detail objects
  2928. CUtlVectorFixedGrowable< DetailRenderableInfo_t, 2048 > detailRenderables( 2048 );
  2929. // Get the fade information for detail objects
  2930. float flDetailDist = g_pDetailObjectSystem->ComputeDetailFadeInfo( &info.m_pRenderList->m_DetailFade );
  2931. g_pDetailObjectSystem->BuildRenderingData( detailRenderables, info, flDetailDist, info.m_pRenderList->m_DetailFade );
  2932. // First build a non-unique list of renderables, separated by special leaf markers
  2933. CUtlVectorFixedGrowable< RenderableInfo_t *, 2048 > orderedList( 2048 );
  2934. if ( info.m_nViewID != VIEW_3DSKY && r_drawallrenderables.GetBool() )
  2935. {
  2936. // HACK - treat all renderables as being in first visible leaf
  2937. int leaf = info.m_pWorldListInfo->m_pLeafDataList[ 0 ].leafIndex;
  2938. orderedList.AddToTail( LeafToMarker( leaf ) );
  2939. #if 1
  2940. for ( int i = m_Renderables.Head(); i != m_Renderables.InvalidIndex(); i = m_Renderables.Next( i ) )
  2941. {
  2942. orderedList.AddToTail( &m_Renderables[ i ] );
  2943. }
  2944. #else
  2945. renderable_LIST_t **ppRenderables = (renderable_LIST_t **)&m_Renderables;
  2946. renderable_LIST_t *pRenderables = *ppRenderables;
  2947. int i = m_Renderables.Head();
  2948. for ( ; i != 0xffff; )
  2949. {
  2950. orderedList.AddToTail( &m_Renderables[ i ] );
  2951. //i = m_Renderables.Next( i )
  2952. i = pRenderables[i].next;
  2953. }
  2954. #endif
  2955. }
  2956. else
  2957. {
  2958. SNPROF("CClientLeafSystem::BuildRenderablesList->A");
  2959. int leaf = 0;
  2960. for ( int i = 0; i < info.m_pWorldListInfo->m_LeafCount; ++i )
  2961. {
  2962. leaf = info.m_pWorldListInfo->m_pLeafDataList[i].leafIndex;
  2963. orderedList.AddToTail( LeafToMarker( leaf ) );
  2964. // iterate over all elements in this leaf
  2965. unsigned short idx = m_RenderablesInLeaf.FirstElement(leaf);
  2966. #if 1 // old
  2967. for ( ; idx != m_RenderablesInLeaf.InvalidIndex(); idx = m_RenderablesInLeaf.NextElement( idx ) )
  2968. {
  2969. orderedList.AddToTail( &m_Renderables[ m_RenderablesInLeaf.Element(idx) ] );
  2970. }
  2971. #else
  2972. // TMP
  2973. renderableInLeaf_LIST_t **pTmp = (renderableInLeaf_LIST_t **)&m_RenderablesInLeaf;
  2974. renderableInLeaf_LIST_t *pRenderablesInLeaf = (renderableInLeaf_LIST_t *)(*pTmp);
  2975. // TMP
  2976. for ( ; idx != 0xffff; )
  2977. {
  2978. unsigned int renderableInLeafIdxNEW = pRenderablesInLeaf[idx].element;
  2979. unsigned int renderableInLeafIdxOLD = m_RenderablesInLeaf.Element(idx);
  2980. if( renderableInLeafIdxNEW != renderableInLeafIdxOLD )
  2981. {
  2982. DebuggerBreak();
  2983. }
  2984. orderedList.AddToTail( &m_Renderables[ m_RenderablesInLeaf.Element(idx) ] );
  2985. unsigned short idxOLD = m_RenderablesInLeaf.NextElement( idx );
  2986. idx = pRenderablesInLeaf[idx].next;
  2987. if( idx != idxOLD )
  2988. {
  2989. DebuggerBreak();
  2990. }
  2991. }
  2992. #endif
  2993. }
  2994. }
  2995. // Debugging
  2996. int nCount = orderedList.Count();
  2997. RenderableInfo_t **ppRenderables = orderedList.Base();
  2998. {
  2999. SNPROF("CClientLeafSystem::BuildRenderablesList->B");
  3000. nCount = ExtractDuplicates( info.m_nRenderFrame, nCount, ppRenderables );
  3001. nCount = ExtractStaticProps( nCount, ppRenderables );
  3002. nCount = ExtractSplitscreenRenderables( nCount, ppRenderables );
  3003. }
  3004. if ( info.m_bFastEntityRendering )
  3005. {
  3006. nCount = ExtractNonFastReflectedRenderables( nCount, ppRenderables );
  3007. }
  3008. if ( info.m_nViewID == VIEW_SHADOW_DEPTH_TEXTURE )
  3009. {
  3010. nCount = ExtractDisableShadowDepthRenderables( nCount, ppRenderables );
  3011. if ( info.m_bDrawDepthViewNonCachedObjectsOnly )
  3012. {
  3013. nCount = ExtractDisableShadowDepthCacheRenderables( nCount, ppRenderables );
  3014. }
  3015. }
  3016. if ( !info.m_bDrawTranslucentObjects )
  3017. {
  3018. nCount = ExtractTranslucentRenderables( nCount, ppRenderables );
  3019. }
  3020. BuildRenderListInfo_t* pRLInfo = (BuildRenderListInfo_t*)stackalloc( nCount * sizeof(BuildRenderListInfo_t) );
  3021. ComputeBounds( nCount, ppRenderables, pRLInfo );
  3022. nCount = ExtractCulledRenderables( nCount, ppRenderables, pRLInfo, info.m_ppFrustumList );
  3023. if ( info.m_bDrawTranslucentObjects )
  3024. {
  3025. nCount = ComputeTranslucency( gpGlobals->framecount /*info.m_nRenderFrame*/, info.m_nViewID, nCount, ppRenderables, pRLInfo, info.m_screenSizeInfo, info.m_vecRenderOrigin );
  3026. }
  3027. //
  3028. nCount = ExtractOccludedRenderables( info.m_nOcclustionViewID, nCount, ppRenderables, pRLInfo );
  3029. AddRenderablesToRenderLists( info, nCount, ppRenderables, pRLInfo, detailRenderables.Count(), detailRenderables.Base() );
  3030. // Msg("PPU count = %d, detailcount = %d\n",nCount, detailRenderables.Count() );
  3031. stackfree( pRLInfo );
  3032. #if defined(_PS3)
  3033. }
  3034. #endif
  3035. }
  3036. #if defined(_PS3)
  3037. void CClientLeafSystem::BuildRenderablesList_PS3_Epilogue( void )
  3038. {
  3039. if( r_PS3_SPU_buildrenderables.GetInt() > 0 )
  3040. {
  3041. int nCount_PS3;
  3042. RenderableInfo_t **ppRenderables_PS3;
  3043. int viewId = g_viewBuilder.GetBuildViewID();
  3044. SPURenderListData *pSPUDst = &g_SPURLData[ viewId ];
  3045. // epilogue for non csm, non fast reflection views
  3046. if( pSPUDst->m_bEpilogue )
  3047. {
  3048. nCount_PS3 = pSPUDst->m_orderedListCount_PS3;
  3049. ppRenderables_PS3 = pSPUDst->m_orderedList_PS3;
  3050. nCount_PS3 = ExtractOccludedRenderables( nCount_PS3, ppRenderables_PS3, pSPUDst->m_RLInfo_PS3 );
  3051. AddRenderablesToRenderLists( pSPUDst->m_info, nCount_PS3, ppRenderables_PS3, pSPUDst->m_RLInfo_PS3, pSPUDst->m_detailRenderablesCount_PS3, pSPUDst->m_detailRenderables_PS3 );
  3052. }
  3053. }
  3054. }
  3055. #endif
  3056. RenderGroup_t CClientLeafSystem::GenerateRenderListEntry( IClientRenderable *pRenderable, CClientRenderablesList::CEntry &entryOut )
  3057. {
  3058. ClientRenderHandle_t iter = m_Renderables.Head();
  3059. while( m_Renderables.IsValidIndex( iter ) )
  3060. {
  3061. RenderableInfo_t &info = m_Renderables.Element( iter );
  3062. if( info.m_pRenderable == pRenderable )
  3063. {
  3064. int nAlpha = info.m_pAlphaProperty ? info.m_pAlphaProperty->ComputeRenderAlpha( ) : 255;
  3065. bool bIsTranslucent = ( nAlpha != 255 ) || ( info.m_nTranslucencyType != RENDERABLE_IS_OPAQUE );
  3066. entryOut.m_pRenderable = pRenderable;
  3067. entryOut.m_iWorldListInfoLeaf = 0; //info.m_RenderLeaf;
  3068. entryOut.m_bShadowDepthNoCache = false;
  3069. entryOut.m_TwoPass = ( info.m_nTranslucencyType == RENDERABLE_IS_TWO_PASS );
  3070. entryOut.m_nModelType = info.m_nModelType;
  3071. entryOut.m_InstanceData.m_nAlpha = nAlpha;
  3072. if ( !bIsTranslucent )
  3073. return RENDER_GROUP_OPAQUE;
  3074. return info.m_pAlphaProperty->IgnoresZBuffer() ? RENDER_GROUP_TRANSLUCENT_IGNOREZ : RENDER_GROUP_TRANSLUCENT;
  3075. }
  3076. iter = m_Renderables.Next( iter );
  3077. }
  3078. entryOut.m_pRenderable = NULL;
  3079. entryOut.m_iWorldListInfoLeaf = 0;
  3080. entryOut.m_bShadowDepthNoCache = false;
  3081. entryOut.m_TwoPass = false;
  3082. entryOut.m_nModelType = RENDERABLE_MODEL_ENTITY;
  3083. entryOut.m_InstanceData.m_nAlpha = 255;
  3084. return RENDER_GROUP_COUNT;
  3085. }
  3086. int CClientLeafSystem::GetEntitiesInBox( C_BaseEntity **pEntityList, int listMax, const Vector& vWorldSpaceMins, const Vector& vWorldSpaceMaxs )
  3087. {
  3088. // NOTE: The render bounds here are relative to the renderable's coordinate system
  3089. Assert( vWorldSpaceMins.IsValid() && vWorldSpaceMaxs.IsValid() );
  3090. Assert( ThreadInMainThread() );
  3091. // Make use of m_ShadowEnum to avoid adding same entity to the list
  3092. ++m_ShadowEnum;
  3093. // When we insert into the tree, increase the shadow enumerator
  3094. // to make sure each shadow is added exactly once to each renderable
  3095. unsigned short leafList[1024];
  3096. ISpatialQuery* pQuery = engine->GetBSPTreeQuery();
  3097. int leafCount = pQuery->ListLeavesInBox( vWorldSpaceMins, vWorldSpaceMaxs, leafList, ARRAYSIZE(leafList) );
  3098. int totalCount = 0;
  3099. for ( int i=0; i<leafCount; ++i )
  3100. {
  3101. unsigned short leaf = leafList[i];
  3102. // iterate over all elements in this leaf
  3103. unsigned short idx = m_RenderablesInLeaf.FirstElement(leaf);
  3104. for ( ; idx != m_RenderablesInLeaf.InvalidIndex(); idx = m_RenderablesInLeaf.NextElement( idx ) )
  3105. {
  3106. ClientRenderHandle_t handle = m_RenderablesInLeaf.Element(idx);
  3107. RenderableInfo_t &info = m_Renderables[ handle ];
  3108. // Add each shadow exactly once to each renderable
  3109. if (info.m_EnumCount != m_ShadowEnum)
  3110. {
  3111. info.m_EnumCount = m_ShadowEnum;
  3112. }
  3113. else
  3114. {
  3115. continue;
  3116. }
  3117. if ( IsBoxIntersectingBox( vWorldSpaceMins, vWorldSpaceMaxs, info.m_vecAbsMins, info.m_vecAbsMaxs ) )
  3118. {
  3119. C_BaseEntity *pEnt = m_Renderables[ handle ].m_pRenderable->GetIClientUnknown()->GetBaseEntity();
  3120. if ( pEnt )
  3121. {
  3122. pEntityList[totalCount] = pEnt;
  3123. ++totalCount;
  3124. }
  3125. }
  3126. }
  3127. }
  3128. return totalCount;
  3129. }