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.

4747 lines
167 KiB

  1. //===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #include "render_pch.h"
  9. #include "shadowmgr.h"
  10. #include "utllinkedlist.h"
  11. #include "utlvector.h"
  12. #include "interface.h"
  13. #include "mathlib/vmatrix.h"
  14. #include "bsptreedata.h"
  15. #include "materialsystem/itexture.h"
  16. #include "filesystem.h"
  17. #include "utlbidirectionalset.h"
  18. #include "l_studio.h"
  19. #include "shaderapi/ishaderapi.h"
  20. #include "istudiorender.h"
  21. #include "engine/ivmodelrender.h"
  22. #include "collisionutils.h"
  23. #include "debugoverlay.h"
  24. #include "tier0/vprof.h"
  25. #include "disp.h"
  26. #include "gl_rmain.h"
  27. #include "MaterialBuckets.h"
  28. #include "r_decal.h"
  29. #include "cmodel_engine.h"
  30. #include "iclientrenderable.h"
  31. #include "cdll_engine_int.h"
  32. #include "sys_dll.h"
  33. #include "render.h"
  34. #include "vstdlib/jobthread.h"
  35. #include "tier1/utlstack.h"
  36. // memdbgon must be the last include file in a .cpp file!!!
  37. #include "tier0/memdbgon.h"
  38. //-----------------------------------------------------------------------------
  39. // Shadow-related functionality exported by the engine
  40. //
  41. // We have two shadow-related caches in this system
  42. // 1) A surface cache. We keep track of which surfaces the shadows can
  43. // potentially hit. The computation of the surface cache should be
  44. // as fast as possible
  45. // 2) A surface vertex cache. Once we know what surfaces the shadow
  46. // hits, we caompute the actual polygons using a clip. This is only
  47. // useful for shadows that we know don't change too frequently, so
  48. // we pass in a flag when making the shadow to indicate whether the
  49. // vertex cache should be used or not. The assumption is that the client
  50. // of this system should know whether the shadows are always changing or not
  51. //
  52. // The first cache is generated when the shadow is initially projected, and
  53. // the second cache is generated when the surfaces are actually being rendered.
  54. //
  55. // For rendering, I assign a sort order ID to all materials used by shadow
  56. // decals. The sort order serves the identical purpose to the material's EnumID
  57. // but I remap those IDs so I can keep a small list of decals to render with
  58. // that enum ID (the other option would be to allocate an array with a number
  59. // of elements == to the number of material enumeration IDs, which is pretty large).
  60. //-----------------------------------------------------------------------------
  61. //-----------------------------------------------------------------------------
  62. // forward decarations
  63. //-----------------------------------------------------------------------------
  64. extern int r_surfacevisframe;
  65. #define SHADOW_BACKFACE_EPSILON 0.01f
  66. // Max number of vertices per shadow decal
  67. enum
  68. {
  69. SHADOW_VERTEX_SMALL_CACHE_COUNT = 8,
  70. SHADOW_VERTEX_LARGE_CACHE_COUNT = 32,
  71. MAX_CLIP_PLANE_COUNT = 4,
  72. SURFACE_BOUNDS_CACHE_COUNT = 1024,
  73. //=============================================================================
  74. // HPE_BEGIN:
  75. // [smessick] Cache size for the shadow decals. This used to be on the stack.
  76. //=============================================================================
  77. SHADOW_DECAL_CACHE_COUNT = 16*1024,
  78. MAX_SHADOW_DECAL_CACHE_COUNT = 64*1024,
  79. //=============================================================================
  80. // HPE_END
  81. //=============================================================================
  82. };
  83. //-----------------------------------------------------------------------------
  84. // ConVars (must be defined before CShadowMgr is instanced!)
  85. //-----------------------------------------------------------------------------
  86. ConVar r_shadows("r_shadows", "1");
  87. ConVar r_shadows_gamecontrol("r_shadows_gamecontrol", "-1", FCVAR_CHEAT ); // Shadow override controlled by game entities (shadow_controller)
  88. static ConVar r_shadowwireframe("r_shadowwireframe", "0", FCVAR_CHEAT );
  89. static ConVar r_shadowids("r_shadowids", "0", FCVAR_CHEAT );
  90. static ConVar r_flashlightdrawsweptbbox( "r_flashlightdrawsweptbbox", "0" );
  91. static ConVar r_flashlightnodraw( "r_flashlightnodraw", "0" );
  92. static ConVar r_flashlightupdatedepth( "r_flashlightupdatedepth", "1" );
  93. static ConVar r_flashlightdrawdepth( "r_flashlightdrawdepth", "0" );
  94. static ConVar r_flashlightdrawdepthres( "r_flashlightdrawdepthres", "256" );
  95. static ConVar r_flashlightrenderworld( "r_flashlightrenderworld", "1" );
  96. static ConVar r_flashlightrendermodels( "r_flashlightrendermodels", "1" );
  97. static ConVar r_flashlightrender( "r_flashlightrender", "1" );
  98. static ConVar r_flashlightculldepth( "r_flashlightculldepth", "1" );
  99. static ConVar r_threaded_shadow_clip( "r_threaded_shadow_clip", "0" );
  100. static ConVar r_flashlight_always_cull_for_single_pass( "r_flashlight_always_cull_for_single_pass", "0" );
  101. //-----------------------------------------------------------------------------
  102. // Implementation of IShadowMgr
  103. //-----------------------------------------------------------------------------
  104. class CShadowMgr : public IShadowMgrInternal, ISpatialLeafEnumerator
  105. {
  106. public:
  107. // constructor
  108. CShadowMgr();
  109. // Methods inherited from IShadowMgr
  110. virtual ShadowHandle_t CreateShadow( IMaterial* pMaterial, IMaterial* pModelMaterial, void* pBindProxy, int creationFlags );
  111. virtual ShadowHandle_t CreateShadowEx( IMaterial* pMaterial, IMaterial* pModelMaterial, void* pBindProxy, int creationFlags, int nEntIndex );
  112. virtual void DestroyShadow( ShadowHandle_t handle );
  113. virtual void SetShadowMaterial( ShadowHandle_t handle, IMaterial* pMaterial, IMaterial* pModelMaterial, void* pBindProxy );
  114. virtual void EnableShadow( ShadowHandle_t handle, bool bEnable );
  115. virtual void ProjectFlashlight( ShadowHandle_t handle, const VMatrix& worldToShadow, int nLeafCount, const int *pLeafList );
  116. virtual void ProjectShadow( ShadowHandle_t handle, const Vector &origin,
  117. const Vector& projectionDir, const VMatrix& worldToShadow, const Vector2D& size,
  118. int nLeafCount, const int *pLeafList,
  119. float maxHeight, float falloffOffset, float falloffAmount, const Vector &vecCasterOrigin );
  120. virtual const Frustum_t &GetFlashlightFrustum( ShadowHandle_t handle );
  121. virtual const FlashlightState_t &GetFlashlightState( ShadowHandle_t handle );
  122. virtual int ProjectAndClipVertices( ShadowHandle_t handle, int count,
  123. Vector** ppPosition, ShadowVertex_t*** ppOutVertex );
  124. virtual void AddShadowToBrushModel( ShadowHandle_t handle, model_t* pModel,
  125. const Vector& origin, const QAngle& angles );
  126. virtual void RemoveAllShadowsFromBrushModel( model_t* pModel );
  127. virtual void AddShadowToModel( ShadowHandle_t shadow, ModelInstanceHandle_t handle );
  128. virtual void RemoveAllShadowsFromModel( ModelInstanceHandle_t handle );
  129. virtual const ShadowInfo_t& GetInfo( ShadowHandle_t handle );
  130. virtual void SetFlashlightRenderState( ShadowHandle_t handle );
  131. virtual int GetNumShadowsOnModel( ModelInstanceHandle_t instance );
  132. virtual int GetShadowsOnModel( ModelInstanceHandle_t instance, ShadowHandle_t* pShadowArray, bool bNormalShadows, bool bFlashlightShadows );
  133. virtual void FlashlightDrawCallback( ShadowDrawCallbackFn_t pCallback, void *pData );
  134. virtual void SetSinglePassFlashlightRenderState( ShadowHandle_t handle );
  135. virtual void PushSinglePassFlashlightStateEnabled( bool bEnable );
  136. virtual void PopSinglePassFlashlightStateEnabled( void );
  137. // Methods inherited from IShadowMgrInternal
  138. virtual void LevelInit( int nSurfCount );
  139. virtual void LevelShutdown();
  140. virtual void AddShadowsOnSurfaceToRenderList( ShadowDecalHandle_t decalHandle );
  141. virtual void ClearShadowRenderList();
  142. virtual void ComputeRenderInfo( ShadowDecalRenderInfo_t* pInfo, ShadowHandle_t handle ) const;
  143. virtual void SetModelShadowState( ModelInstanceHandle_t instance );
  144. virtual unsigned short InvalidShadowIndex( );
  145. // Methods of ISpatialLeafEnumerator
  146. virtual bool EnumerateLeaf( int leaf, intp context );
  147. // Sets the texture coordinate range for a shadow...
  148. virtual void SetShadowTexCoord( ShadowHandle_t handle, float x, float y, float w, float h );
  149. // Set extra clip planes related to shadows...
  150. // These are used to prevent pokethru and back-casting
  151. virtual void ClearExtraClipPlanes( ShadowHandle_t shadow );
  152. virtual void AddExtraClipPlane( ShadowHandle_t shadow, const Vector& normal, float dist );
  153. // Gets the first model associated with a shadow
  154. unsigned short& FirstModelInShadow( ShadowHandle_t h ) { return m_Shadows[h].m_FirstModel; }
  155. // Set the darkness falloff bias
  156. virtual void SetFalloffBias( ShadowHandle_t shadow, unsigned char ucBias );
  157. // Set the number of world material buckets. This should happen exactly once per level load.
  158. virtual void SetNumWorldMaterialBuckets( int numMaterialSortBins );
  159. // Update the state for a flashlight.
  160. virtual void UpdateFlashlightState( ShadowHandle_t shadowHandle, const FlashlightState_t &lightState );
  161. virtual void DrawFlashlightDecals( IMatRenderContext *pRenderContext, int sortGroup, bool bDoMasking, float flFade );
  162. virtual void DrawFlashlightDecalsOnSurfaceList( IMatRenderContext *pRenderContext, SurfaceHandle_t *pList, int listCount, bool bDoMasking );
  163. virtual void DrawFlashlightOverlays( IMatRenderContext *pRenderContext, int sortGroup, bool bDoMasking );
  164. virtual void DrawFlashlightDepthTexture( );
  165. virtual void SetFlashlightDepthTexture( ShadowHandle_t shadowHandle, ITexture *pFlashlightDepthTexture, unsigned char ucShadowStencilBit );
  166. virtual void DrawFlashlightDecalsOnDisplacements( IMatRenderContext *pRenderContext, int sortGroup, CDispInfo **visibleDisps, int nVisibleDisps, bool bDoMasking );
  167. virtual bool ModelHasShadows( ModelInstanceHandle_t instance );
  168. virtual void DrawVolumetrics();
  169. virtual int ProjectAndClipVerticesEx( ShadowHandle_t handle, int count,
  170. Vector** ppPosition, ShadowVertex_t*** ppOutVertex, ShadowClipState_t& clip );
  171. virtual bool SinglePassFlashlightModeEnabled( void );
  172. virtual int SetupFlashlightRenderInstanceInfo( ShadowHandle_t *pFlashlights, uint32 *pModelUsageMask, int nUsageStride, int nInstanceCount, const ModelInstanceHandle_t *pInstance );
  173. virtual void GetFlashlightRenderInfo( FlashlightInstance_t *pFlashlightState, int nCount, const ShadowHandle_t *pHandles );
  174. virtual void RemoveAllDecalsFromShadow( ShadowHandle_t handle );
  175. virtual void SkipShadowForEntity( int nEntIndex );
  176. virtual void PushFlashlightScissorBounds( void );
  177. virtual void PopFlashlightScissorBounds( void );
  178. virtual void DisableDropShadows();
  179. private:
  180. enum
  181. {
  182. SHADOW_DISABLED = (SHADOW_LAST_FLAG << 1),
  183. };
  184. typedef CUtlFixedLinkedList< ShadowDecalHandle_t >::IndexType_t ShadowSurfaceIndex_t;
  185. struct SurfaceBounds_t
  186. {
  187. fltx4 m_vecMins;
  188. fltx4 m_vecMaxs;
  189. Vector m_vecCenter;
  190. float m_flRadius;
  191. int m_nSurfaceIndex;
  192. };
  193. struct ShadowVertexSmallList_t
  194. {
  195. ShadowVertex_t m_Verts[SHADOW_VERTEX_SMALL_CACHE_COUNT];
  196. };
  197. struct ShadowVertexLargeList_t
  198. {
  199. ShadowVertex_t m_Verts[SHADOW_VERTEX_LARGE_CACHE_COUNT];
  200. };
  201. // A cache entries' worth of vertices....
  202. struct ShadowVertexCache_t
  203. {
  204. unsigned short m_Count;
  205. ShadowHandle_t m_Shadow;
  206. unsigned short m_CachedVerts;
  207. ShadowVertex_t* m_pVerts;
  208. };
  209. typedef unsigned short FlashlightHandle_t;
  210. // Shadow state
  211. struct Shadow_t : public ShadowInfo_t
  212. {
  213. Vector m_ProjectionDir;
  214. IMaterial* m_pMaterial; // material for rendering surfaces
  215. IMaterial* m_pModelMaterial; // material for rendering models
  216. void* m_pBindProxy;
  217. unsigned short m_Flags;
  218. unsigned short m_SortOrder;
  219. float m_flSphereRadius; // Radius of sphere surrounding the shadow
  220. Ray_t m_Ray; // NOTE: Ray needs to be on 16-byte boundaries.
  221. Vector m_vecSphereCenter; // Sphere surrounding the shadow
  222. FlashlightHandle_t m_FlashlightHandle;
  223. ITexture *m_pFlashlightDepthTexture;
  224. // Extra clip planes
  225. unsigned short m_ClipPlaneCount;
  226. Vector m_ClipPlane[MAX_CLIP_PLANE_COUNT];
  227. float m_ClipDist[MAX_CLIP_PLANE_COUNT];
  228. // First shadow decal the shadow has
  229. ShadowSurfaceIndex_t m_FirstDecal;
  230. // First model the shadow is projected onto
  231. unsigned short m_FirstModel;
  232. // Stencil bit used to mask this shadow
  233. unsigned char m_ucShadowStencilBit;
  234. int m_nEntIndex;
  235. };
  236. // Each surface has one of these, they reference the main shadow
  237. // projector and cached off shadow decals.
  238. struct ShadowDecal_t
  239. {
  240. SurfaceHandle_t m_SurfID;
  241. ShadowSurfaceIndex_t m_ShadowListIndex;
  242. ShadowHandle_t m_Shadow;
  243. DispShadowHandle_t m_DispShadow;
  244. unsigned short m_ShadowVerts;
  245. // This is a handle of the next shadow decal to be rendered
  246. ShadowDecalHandle_t m_NextRender;
  247. };
  248. // This structure is used when building new shadow information
  249. struct ShadowBuildInfo_t
  250. {
  251. ShadowHandle_t m_Shadow;
  252. Vector m_RayStart;
  253. Vector m_ProjectionDirection;
  254. Vector m_vecSphereCenter; // Sphere surrounding the shadow
  255. float m_flSphereRadius; // Radius of sphere surrounding the shadow
  256. const byte *m_pVis; // Vis from the ray start
  257. };
  258. // This structure contains rendering information
  259. struct ShadowRenderInfo_t
  260. {
  261. int m_VertexCount;
  262. int m_IndexCount;
  263. int m_nMaxVertices;
  264. int m_nMaxIndices;
  265. int m_Count;
  266. int* m_pCache;
  267. int m_DispCount;
  268. const VMatrix* m_pModelToWorld;
  269. VMatrix m_WorldToModel;
  270. DispShadowHandle_t* m_pDispCache;
  271. };
  272. // Structures used to assign sort order handles
  273. struct SortOrderInfo_t
  274. {
  275. intp m_MaterialEnum;
  276. int m_RefCount;
  277. };
  278. typedef void (*ShadowDebugFunc_t)( ShadowHandle_t shadowHandle, const Vector &vecCentroid );
  279. // m_FlashlightWorldMaterialBuckets is where surfaces are stored per flashlight each frame.
  280. typedef CUtlVector<FlashlightHandle_t> WorldMaterialBuckets_t;
  281. #pragma pack(16)
  282. struct FlashlightInfo_t
  283. {
  284. Frustum_t m_Frustum;
  285. FlashlightState_t m_FlashlightState;
  286. unsigned short m_Shadow;
  287. CMaterialsBuckets<SurfaceHandle_t> m_MaterialBuckets;
  288. CMaterialsBuckets<SurfaceHandle_t> m_OccluderBuckets;
  289. int m_nSplitscreenOwner;
  290. };
  291. #pragma pack()
  292. struct DispDecalWorkItem_t
  293. {
  294. ShadowDecalHandle_t h;
  295. bool bKeepShadow;
  296. int vertCount;
  297. int indexCount;
  298. };
  299. private:
  300. // Applies a flashlight to all surfaces in the leaf
  301. void ApplyFlashlightToLeaf( const Shadow_t &shadow, mleaf_t* pLeaf, ShadowBuildInfo_t* pBuild );
  302. // Applies a shadow to all surfaces in the leaf
  303. void ApplyShadowToLeaf( const Shadow_t &shadow, mleaf_t* RESTRICT pLeaf, ShadowBuildInfo_t* RESTRICT pBuild );
  304. // These functions deal with creation of render sort ids
  305. void SetMaterial( Shadow_t& shadow, IMaterial* pMaterial, IMaterial* pModelMaterial, void* pBindProxy );
  306. void CleanupMaterial( Shadow_t& shadow );
  307. // These functions add/remove shadow decals to surfaces
  308. ShadowDecalHandle_t AddShadowDecalToSurface( SurfaceHandle_t surfID, ShadowHandle_t handle );
  309. void RemoveShadowDecalFromSurface( SurfaceHandle_t surfID, ShadowDecalHandle_t decalHandle );
  310. // Adds the surface to the list for this shadow
  311. bool AddDecalToShadowList( ShadowHandle_t handle, ShadowDecalHandle_t decalHandle );
  312. // Removes the shadow to the list of surfaces
  313. void RemoveDecalFromShadowList( ShadowHandle_t handle, ShadowDecalHandle_t decalHandle );
  314. // Actually projects + clips vertices
  315. int ProjectAndClipVertices( const Shadow_t& shadow, const VMatrix& worldToShadow,
  316. const VMatrix *pWorldToModel, int count, Vector** ppPosition, ShadowVertex_t*** ppOutVertex, ShadowClipState_t& clip );
  317. // These functions hook/unhook shadows up to surfaces + vice versa
  318. void AddSurfaceToShadow( ShadowHandle_t handle, SurfaceHandle_t surfID );
  319. void RemoveSurfaceFromShadow( ShadowHandle_t handle, SurfaceHandle_t surfID );
  320. void RemoveAllSurfacesFromShadow( ShadowHandle_t handle );
  321. void RemoveAllShadowsFromSurface( SurfaceHandle_t surfID );
  322. // Deals with model shadow management
  323. void RemoveAllModelsFromShadow( ShadowHandle_t handle );
  324. // Applies the shadow to a surface
  325. void ApplyShadowToSurface( ShadowBuildInfo_t& build, SurfaceHandle_t surfID );
  326. // Applies the shadow to a displacement
  327. void ApplyShadowToDisplacement( ShadowBuildInfo_t& build, IDispInfo *pDispInfo, bool bIsFlashlight );
  328. // Renders shadows that all share a material enumeration
  329. void RenderShadowList( IMatRenderContext *pRenderContext, ShadowDecalHandle_t decalHandle, const VMatrix* pModelToWorld );
  330. // Should we cache vertices?
  331. bool ShouldCacheVertices( const ShadowDecal_t& decal );
  332. // Generates a list displacement shadow vertices to render
  333. bool GenerateDispShadowRenderInfo( ShadowDecal_t& decal, ShadowRenderInfo_t& info );
  334. // Generates a list shadow vertices to render
  335. bool GenerateNormalShadowRenderInfo( IMatRenderContext *pRenderContext, ShadowDecal_t& decal, ShadowRenderInfo_t& info );
  336. // Adds normal shadows to the mesh builder
  337. int AddNormalShadowsToMeshBuilder( CMeshBuilder& meshBuilder, ShadowRenderInfo_t& info );
  338. // Adds displacement shadows to the mesh builder
  339. int AddDisplacementShadowsToMeshBuilder( CMeshBuilder& meshBuilder,
  340. ShadowRenderInfo_t& info, int baseIndex );
  341. // Does the actual work of computing shadow vertices
  342. bool ComputeShadowVertices( ShadowDecal_t& decal, const VMatrix* pModelToWorld, const VMatrix* pWorldToModel, ShadowVertexCache_t* pVertexCache );
  343. // Project vertices into shadow space
  344. bool ProjectVerticesIntoShadowSpace( const VMatrix * RESTRICT modelToShadow,
  345. float maxDist, int count, Vector** RESTRICT ppPosition, ShadowClipState_t& clip );
  346. // Copies vertex info from the clipped vertices
  347. void CopyClippedVertices( int count, ShadowVertex_t** ppSrcVert, ShadowVertex_t* pDstVert, const Vector &vToAdd );
  348. // Allocate, free vertices
  349. ShadowVertex_t* AllocateVertices( ShadowVertexCache_t& cache, int count );
  350. void FreeVertices( ShadowVertexCache_t& cache );
  351. // Gets at cache entry...
  352. ShadowVertex_t* GetCachedVerts( const ShadowVertexCache_t& cache );
  353. // Clears out vertices in the temporary cache
  354. void ClearTempCache( );
  355. // Renders debugging information
  356. void RenderDebuggingInfo( const ShadowRenderInfo_t &info, ShadowDebugFunc_t func );
  357. // Methods for dealing with world material buckets for flashlights.
  358. void ClearAllFlashlightMaterialBuckets( void );
  359. void AddSurfaceToFlashlightMaterialBuckets( ShadowHandle_t handle, SurfaceHandle_t surfID );
  360. void AllocFlashlightMaterialBuckets( FlashlightHandle_t flashlightID );
  361. // Render all projected textures (including shadows and flashlights)
  362. void RenderProjectedTextures( IMatRenderContext *pRenderContext, const VMatrix* pModelToWorld );
  363. void RenderFlashlights( bool bDoMasking, bool bDoSimpleProjections, const VMatrix* pModelToWorld );
  364. void SetFlashlightStencilMasks( bool bDoMasking );
  365. void SetStencilAndScissor( IMatRenderContext *pRenderContext, FlashlightInfo_t &flashlightInfo, bool bUseStencil );
  366. void EnableStencilAndScissorMasking( IMatRenderContext *pRenderContext, const FlashlightInfo_t &flashlightInfo, bool bDoMasking );
  367. void DisableStencilAndScissorMasking( IMatRenderContext *pRenderContext, const FlashlightInfo_t &flashlightInfo, bool bDoMasking );
  368. void RenderShadows( IMatRenderContext *pRenderContext, const VMatrix* pModelToWorld );
  369. // Generates a list shadow vertices to render
  370. void GenerateShadowRenderInfo( IMatRenderContext *pRenderContext, ShadowDecalHandle_t decalHandle, ShadowRenderInfo_t& info );
  371. void GenerateShadowRenderInfoThreaded( IMatRenderContext *pRenderContext, ShadowDecalHandle_t decalHandle, ShadowRenderInfo_t& info );
  372. void ProcessDispDecalWorkItem( DispDecalWorkItem_t& wi );
  373. // Methods related to the surface bounds cache
  374. void ComputeSurfaceBounds( SurfaceBounds_t* pBounds, SurfaceHandle_t nSurfID );
  375. const SurfaceBounds_t* GetSurfaceBounds( SurfaceHandle_t nSurfID );
  376. bool IsShadowNearSurface( ShadowHandle_t h, SurfaceHandle_t nSurfID, const VMatrix* pModelToWorld, const VMatrix* pWorldToModel );
  377. private:
  378. // List of all shadows (one per cast shadow)
  379. // Align it so the Ray in the Shadow_t is aligned
  380. CUtlLinkedList< Shadow_t, ShadowHandle_t, false, int, CUtlMemoryAligned< UtlLinkedListElem_t< Shadow_t, ShadowHandle_t >, 16 > > m_Shadows;
  381. // List of all shadow decals (one per surface hit by a shadow)
  382. CUtlLinkedList< ShadowDecal_t, ShadowDecalHandle_t, true, int > m_ShadowDecals;
  383. // List of all shadow decals associated with a particular shadow
  384. CUtlFixedLinkedList< ShadowDecalHandle_t > m_ShadowSurfaces;
  385. // List of queued decals waiting to be rendered....
  386. CUtlVector<ShadowDecalHandle_t> m_RenderQueue;
  387. // Used to assign sort order handles
  388. CUtlLinkedList<SortOrderInfo_t, unsigned short> m_SortOrderIds;
  389. // A cache of shadow vertex data...
  390. CUtlLinkedList<ShadowVertexCache_t, unsigned short> m_VertexCache;
  391. // This is temporary, not saved off....
  392. CUtlVector<ShadowVertexCache_t> m_TempVertexCache;
  393. // Vertex data
  394. CUtlLinkedList<ShadowVertexSmallList_t, unsigned short> m_SmallVertexList;
  395. CUtlLinkedList<ShadowVertexLargeList_t, unsigned short> m_LargeVertexList;
  396. // Model-shadow association
  397. CBidirectionalSet< ModelInstanceHandle_t, ShadowHandle_t, unsigned short > m_ShadowsOnModels;
  398. // Cache of information for surface bounds
  399. typedef CUtlLinkedList< SurfaceBounds_t, unsigned short, false, int, CUtlMemoryFixed< UtlLinkedListElem_t< SurfaceBounds_t, unsigned short >, SURFACE_BOUNDS_CACHE_COUNT, 16 > > SurfaceBoundsCache_t;
  400. typedef SurfaceBoundsCache_t::IndexType_t SurfaceBoundsCacheIndex_t;
  401. SurfaceBoundsCache_t m_SurfaceBoundsCache;
  402. SurfaceBoundsCacheIndex_t *m_pSurfaceBounds;
  403. // The number of decals we're gonna need to render
  404. int m_DecalsToRender;
  405. typedef CUtlLinkedList< FlashlightInfo_t, unsigned short, false, unsigned short, CUtlMemoryAligned< UtlLinkedListElem_t< FlashlightInfo_t,unsigned short > ,16 > > FlashlightList_t;
  406. FlashlightList_t m_FlashlightStates;
  407. int m_NumWorldMaterialBuckets;
  408. bool m_bInitialized;
  409. //=============================================================================
  410. // HPE_BEGIN:
  411. // [smessick] These used to be dynamically allocated on the stack.
  412. //=============================================================================
  413. CUtlMemory<int> m_ShadowDecalCache;
  414. CUtlMemory<DispShadowHandle_t> m_DispShadowDecalCache;
  415. //=============================================================================
  416. // HPE_END
  417. //=============================================================================
  418. ShadowHandle_t m_hSinglePassFlashlightState;
  419. bool m_bSinglePassFlashlightStateEnabled;
  420. bool m_bShadowsDisabled;
  421. CUtlStack<bool> m_bStack_SinglePassFlashlightStateEnabled;
  422. int m_nSkipShadowForEntIndex;
  423. struct FlashLightScissorStateBackup_t
  424. {
  425. int m_nLeft;
  426. int m_nTop;
  427. int m_nRight;
  428. int m_nBottom;
  429. bool m_bScissor;
  430. #if defined( DBGFLAG_ASSERT )
  431. int m_iFlashLightID;
  432. #endif
  433. };
  434. CUtlVector<FlashLightScissorStateBackup_t> m_ScissorStateBackups;
  435. CUtlVector<int> m_ScissorStateEntryStart;
  436. };
  437. //-----------------------------------------------------------------------------
  438. // Singleton
  439. //-----------------------------------------------------------------------------
  440. static CShadowMgr s_ShadowMgr;
  441. IShadowMgrInternal* g_pShadowMgr = &s_ShadowMgr;
  442. EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CShadowMgr, IShadowMgr,
  443. ENGINE_SHADOWMGR_INTERFACE_VERSION, s_ShadowMgr);
  444. //-----------------------------------------------------------------------------
  445. // Shadows on model instances
  446. //-----------------------------------------------------------------------------
  447. unsigned short& FirstShadowOnModel( ModelInstanceHandle_t h )
  448. {
  449. // See l_studio.cpp
  450. return FirstShadowOnModelInstance( h );
  451. }
  452. unsigned short& FirstModelInShadow( ShadowHandle_t h )
  453. {
  454. return s_ShadowMgr.FirstModelInShadow(h);
  455. }
  456. //-----------------------------------------------------------------------------
  457. // Constructor, destructor
  458. //-----------------------------------------------------------------------------
  459. CShadowMgr::CShadowMgr()
  460. {
  461. m_bShadowsDisabled = false;
  462. m_ShadowSurfaces.SetGrowSize( 4096 );
  463. m_ShadowDecals.SetGrowSize( 4096 );
  464. m_ShadowsOnModels.Init( ::FirstShadowOnModel, ::FirstModelInShadow );
  465. m_NumWorldMaterialBuckets = 0;
  466. m_pSurfaceBounds = NULL;
  467. m_bInitialized = false;
  468. m_hSinglePassFlashlightState = SHADOW_HANDLE_INVALID;
  469. m_bSinglePassFlashlightStateEnabled = IsGameConsole();
  470. m_nSkipShadowForEntIndex = INT_MIN;
  471. ClearShadowRenderList();
  472. //=============================================================================
  473. // HPE_BEGIN:
  474. // [smessick] Initialize the shadow decal caches. These used to be dynamically
  475. // allocated on the stack, but we were getting stack overflows.
  476. //=============================================================================
  477. m_ShadowDecalCache.SetGrowSize( 4096 );
  478. m_DispShadowDecalCache.SetGrowSize( 4096 );
  479. m_ShadowDecalCache.Grow( SHADOW_DECAL_CACHE_COUNT );
  480. m_DispShadowDecalCache.Grow( SHADOW_DECAL_CACHE_COUNT );
  481. //=============================================================================
  482. // HPE_END
  483. //=============================================================================
  484. }
  485. //-----------------------------------------------------------------------------
  486. // Level init, shutdown
  487. //-----------------------------------------------------------------------------
  488. void CShadowMgr::LevelInit( int nSurfCount )
  489. {
  490. if ( m_bInitialized )
  491. return;
  492. m_bInitialized = true;
  493. materials->GetRenderContext()->EnableSinglePassFlashlightMode( m_bSinglePassFlashlightStateEnabled );
  494. m_pSurfaceBounds = new SurfaceBoundsCacheIndex_t[nSurfCount];
  495. // NOTE: Need to memset to 0 if we switch to integer SurfaceBoundsCacheIndex_t here
  496. COMPILE_TIME_ASSERT( sizeof(SurfaceBoundsCacheIndex_t) == 2 );
  497. memset( m_pSurfaceBounds, 0xFF, nSurfCount * sizeof(SurfaceBoundsCacheIndex_t) );
  498. }
  499. void CShadowMgr::LevelShutdown()
  500. {
  501. if ( !m_bInitialized )
  502. return;
  503. if ( m_pSurfaceBounds )
  504. {
  505. delete[] m_pSurfaceBounds;
  506. m_pSurfaceBounds = NULL;
  507. }
  508. m_SurfaceBoundsCache.RemoveAll();
  509. m_bInitialized = false;
  510. }
  511. //-----------------------------------------------------------------------------
  512. // Track growth of shadow-related linked lists, warn when things grow significantly
  513. //-----------------------------------------------------------------------------
  514. #if defined( LEFT4DEAD )
  515. // GrowSpew is causing unnecessary overhead on the L4D 360 build
  516. #define GrowSpew( ... )
  517. #else
  518. static int m_ShadowSurfacesMax = 0, m_ShadowDecalsMax = 0, m_SortOrderIdsMax = 0, m_SmallVertexListMax = 0, m_LargeVertexListMax = 0;
  519. static int m_ShadowsOnModelsMax = 0, m_RenderQueueMax = 0, m_VertexCacheMax = 0, m_TempVertexCacheMax = 0;
  520. static void GrowSpew( int numAlloc, int &maxCounter, const char *array, int spewFreq = 1000 )
  521. {
  522. if ( numAlloc <= maxCounter ) return;
  523. if ( ( maxCounter / spewFreq ) != ( numAlloc / spewFreq ) )
  524. Warning( "Shadow memory (%s) growing [%d]\n", array, numAlloc );
  525. maxCounter = numAlloc;
  526. }
  527. #endif
  528. void CShadowMgr::DisableDropShadows()
  529. {
  530. m_bShadowsDisabled = true;
  531. }
  532. //-----------------------------------------------------------------------------
  533. // Create, destroy material sort order ids...
  534. //-----------------------------------------------------------------------------
  535. void CShadowMgr::SetMaterial( Shadow_t& shadow, IMaterial* pMaterial, IMaterial* pModelMaterial, void *pBindProxy )
  536. {
  537. shadow.m_pMaterial = pMaterial;
  538. shadow.m_pModelMaterial = pModelMaterial;
  539. shadow.m_pBindProxy = pBindProxy;
  540. // We're holding onto this material
  541. if ( pMaterial )
  542. {
  543. pMaterial->IncrementReferenceCount();
  544. }
  545. if ( pModelMaterial )
  546. {
  547. pModelMaterial->IncrementReferenceCount();
  548. }
  549. // Search the sort order handles for an enumeration id match
  550. intp materialEnum = (intp)pMaterial;
  551. for (int i = m_SortOrderIds.Head(); i != m_SortOrderIds.InvalidIndex(); i = m_SortOrderIds.Next(i) )
  552. {
  553. // Found a match, lets increment the refcount of this sort order id
  554. if (m_SortOrderIds[i].m_MaterialEnum == materialEnum)
  555. {
  556. ++m_SortOrderIds[i].m_RefCount;
  557. shadow.m_SortOrder = i;
  558. return;
  559. }
  560. }
  561. // Didn't find it, lets assign a new sort order ID, with a refcount of 1
  562. GrowSpew( m_SortOrderIds.Count(), m_SortOrderIdsMax, "m_SortOrderIds" );
  563. shadow.m_SortOrder = m_SortOrderIds.AddToTail();
  564. m_SortOrderIds[shadow.m_SortOrder].m_MaterialEnum = materialEnum;
  565. m_SortOrderIds[shadow.m_SortOrder].m_RefCount = 1;
  566. // Make sure the render queue has as many entries as the max sort order id.
  567. int count = m_RenderQueue.Count();
  568. GrowSpew( m_RenderQueue.Count(), m_RenderQueueMax, "m_RenderQueue" );
  569. while( count < m_SortOrderIds.MaxElementIndex() )
  570. {
  571. MEM_ALLOC_CREDIT();
  572. m_RenderQueue.AddToTail( SHADOW_DECAL_HANDLE_INVALID );
  573. ++count;
  574. }
  575. }
  576. void CShadowMgr::CleanupMaterial( Shadow_t& shadow )
  577. {
  578. // Decrease the sort order reference count
  579. if (--m_SortOrderIds[shadow.m_SortOrder].m_RefCount <= 0)
  580. {
  581. // No one referencing the sort order number?
  582. // Then lets clean up the sort order id
  583. m_SortOrderIds.Remove(shadow.m_SortOrder);
  584. }
  585. // We're done with this material
  586. if ( shadow.m_pMaterial )
  587. {
  588. shadow.m_pMaterial->DecrementReferenceCount();
  589. }
  590. if ( shadow.m_pModelMaterial )
  591. {
  592. shadow.m_pModelMaterial->DecrementReferenceCount();
  593. }
  594. }
  595. //-----------------------------------------------------------------------------
  596. // For the model shadow list
  597. //-----------------------------------------------------------------------------
  598. unsigned short CShadowMgr::InvalidShadowIndex( )
  599. {
  600. return m_ShadowsOnModels.InvalidIndex();
  601. }
  602. void CShadowMgr::RemoveAllDecalsFromShadow( ShadowHandle_t handle )
  603. {
  604. RemoveAllSurfacesFromShadow( handle );
  605. RemoveAllModelsFromShadow( handle );
  606. }
  607. //-----------------------------------------------------------------------------
  608. // Create, destroy shadows
  609. //-----------------------------------------------------------------------------
  610. ShadowHandle_t CShadowMgr::CreateShadow( IMaterial* pMaterial, IMaterial* pModelMaterial, void* pBindProxy, int creationFlags )
  611. {
  612. return CreateShadowEx( pMaterial, pModelMaterial, pBindProxy, creationFlags, -1 );
  613. }
  614. ShadowHandle_t CShadowMgr::CreateShadowEx( IMaterial* pMaterial, IMaterial* pModelMaterial, void* pBindProxy, int creationFlags, int nEntIndex )
  615. {
  616. #ifndef DEDICATED
  617. ShadowHandle_t h = m_Shadows.AddToTail();
  618. //=============================================================================
  619. // HPE_BEGIN:
  620. // [smessick] Check for overflow.
  621. //=============================================================================
  622. if ( h == m_Shadows.InvalidIndex() )
  623. {
  624. ExecuteNTimes( 10, Warning( "CShadowMgr::CreateShadowEx - overflowed m_Shadows linked list!\n" ) );
  625. return h;
  626. }
  627. //=============================================================================
  628. // HPE_END
  629. //=============================================================================
  630. Shadow_t& shadow = m_Shadows[h];
  631. SetMaterial( shadow, pMaterial, pModelMaterial, pBindProxy );
  632. shadow.m_Flags = creationFlags;
  633. shadow.m_FirstDecal = m_ShadowSurfaces.InvalidIndex();
  634. shadow.m_FirstModel = m_ShadowsOnModels.InvalidIndex();
  635. shadow.m_ProjectionDir.Init( 0, 0, 1 );
  636. shadow.m_TexOrigin.Init( 0, 0 );
  637. shadow.m_TexSize.Init( 1, 1 );
  638. shadow.m_ClipPlaneCount = 0;
  639. shadow.m_FalloffBias = 0;
  640. shadow.m_pFlashlightDepthTexture = NULL;
  641. shadow.m_FlashlightHandle = m_FlashlightStates.InvalidIndex();
  642. shadow.m_nEntIndex = nEntIndex;
  643. if ( ( creationFlags & ( SHADOW_FLASHLIGHT | SHADOW_SIMPLE_PROJECTION ) ) != 0 )
  644. {
  645. shadow.m_FlashlightHandle = m_FlashlightStates.AddToTail();
  646. m_FlashlightStates[shadow.m_FlashlightHandle].m_Shadow = h;
  647. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  648. m_FlashlightStates[ shadow.m_FlashlightHandle ].m_nSplitscreenOwner = ( creationFlags & SHADOW_ANY_SPLITSCREEN_SLOT ) ? -1 : GET_ACTIVE_SPLITSCREEN_SLOT();
  649. if ( !m_bSinglePassFlashlightStateEnabled )
  650. {
  651. AllocFlashlightMaterialBuckets( shadow.m_FlashlightHandle );
  652. }
  653. }
  654. MatrixSetIdentity( shadow.m_WorldToShadow );
  655. return h;
  656. #endif
  657. }
  658. void CShadowMgr::DestroyShadow( ShadowHandle_t handle )
  659. {
  660. CleanupMaterial( m_Shadows[handle] );
  661. RemoveAllSurfacesFromShadow( handle );
  662. RemoveAllModelsFromShadow( handle );
  663. if( m_Shadows[handle].m_FlashlightHandle != m_FlashlightStates.InvalidIndex() )
  664. {
  665. m_FlashlightStates.Remove( m_Shadows[handle].m_FlashlightHandle );
  666. }
  667. m_Shadows.Remove(handle);
  668. }
  669. //-----------------------------------------------------------------------------
  670. // Resets the shadow material (useful for shadow LOD.. doing blobby at distance)
  671. //-----------------------------------------------------------------------------
  672. void CShadowMgr::SetShadowMaterial( ShadowHandle_t handle, IMaterial* pMaterial, IMaterial* pModelMaterial, void* pBindProxy )
  673. {
  674. Shadow_t& shadow = m_Shadows[handle];
  675. if ( (shadow.m_pMaterial != pMaterial) || (shadow.m_pModelMaterial != pModelMaterial) || (shadow.m_pBindProxy != pBindProxy) )
  676. {
  677. CleanupMaterial( shadow );
  678. SetMaterial( shadow, pMaterial, pModelMaterial, pBindProxy );
  679. }
  680. }
  681. //-----------------------------------------------------------------------------
  682. // Sets the texture coordinate range for a shadow...
  683. //-----------------------------------------------------------------------------
  684. void CShadowMgr::SetShadowTexCoord( ShadowHandle_t handle, float x, float y, float w, float h )
  685. {
  686. Shadow_t& shadow = m_Shadows[handle];
  687. shadow.m_TexOrigin.Init( x, y );
  688. shadow.m_TexSize.Init( w, h );
  689. }
  690. //-----------------------------------------------------------------------------
  691. // Set extra clip planes related to shadows...
  692. //-----------------------------------------------------------------------------
  693. void CShadowMgr::ClearExtraClipPlanes( ShadowHandle_t h )
  694. {
  695. m_Shadows[h].m_ClipPlaneCount = 0;
  696. }
  697. void CShadowMgr::AddExtraClipPlane( ShadowHandle_t h, const Vector& normal, float dist )
  698. {
  699. Shadow_t& shadow = m_Shadows[h];
  700. Assert( shadow.m_ClipPlaneCount < MAX_CLIP_PLANE_COUNT );
  701. VectorCopy( normal, shadow.m_ClipPlane[shadow.m_ClipPlaneCount] );
  702. shadow.m_ClipDist[shadow.m_ClipPlaneCount] = dist;
  703. ++shadow.m_ClipPlaneCount;
  704. }
  705. //-----------------------------------------------------------------------------
  706. // Gets at information about a particular shadow
  707. //-----------------------------------------------------------------------------
  708. const ShadowInfo_t& CShadowMgr::GetInfo( ShadowHandle_t handle )
  709. {
  710. return m_Shadows[handle];
  711. }
  712. //-----------------------------------------------------------------------------
  713. // Gets at cache entry...
  714. //-----------------------------------------------------------------------------
  715. ShadowVertex_t* CShadowMgr::GetCachedVerts( const ShadowVertexCache_t& cache )
  716. {
  717. if (cache.m_Count == 0)
  718. return 0 ;
  719. if (cache.m_pVerts)
  720. return cache.m_pVerts;
  721. if (cache.m_Count <= SHADOW_VERTEX_SMALL_CACHE_COUNT)
  722. return m_SmallVertexList[cache.m_CachedVerts].m_Verts;
  723. return m_LargeVertexList[cache.m_CachedVerts].m_Verts;
  724. }
  725. //-----------------------------------------------------------------------------
  726. // Allocates, cleans up vertex cache vertices
  727. //-----------------------------------------------------------------------------
  728. inline ShadowVertex_t* CShadowMgr::AllocateVertices( ShadowVertexCache_t& cache, int count )
  729. {
  730. cache.m_pVerts = 0;
  731. if (count <= SHADOW_VERTEX_SMALL_CACHE_COUNT)
  732. {
  733. cache.m_Count = count;
  734. GrowSpew( m_SmallVertexList.NumAllocated(), m_SmallVertexListMax, "m_SmallVertexList" );
  735. cache.m_CachedVerts = m_SmallVertexList.AddToTail( );
  736. return m_SmallVertexList[cache.m_CachedVerts].m_Verts;
  737. }
  738. else if (count <= SHADOW_VERTEX_LARGE_CACHE_COUNT)
  739. {
  740. cache.m_Count = count;
  741. GrowSpew( m_LargeVertexList.NumAllocated(), m_LargeVertexListMax, "m_LargeVertexList" );
  742. cache.m_CachedVerts = m_LargeVertexList.AddToTail( );
  743. return m_LargeVertexList[cache.m_CachedVerts].m_Verts;
  744. }
  745. cache.m_Count = count;
  746. if (count > 0)
  747. {
  748. cache.m_pVerts = new ShadowVertex_t[count];
  749. }
  750. cache.m_CachedVerts = m_LargeVertexList.InvalidIndex();
  751. return cache.m_pVerts;
  752. }
  753. inline void CShadowMgr::FreeVertices( ShadowVertexCache_t& cache )
  754. {
  755. if (cache.m_Count == 0)
  756. return;
  757. if (cache.m_pVerts)
  758. {
  759. delete[] cache.m_pVerts;
  760. }
  761. else if (cache.m_Count <= SHADOW_VERTEX_SMALL_CACHE_COUNT)
  762. {
  763. m_SmallVertexList.Remove( cache.m_CachedVerts );
  764. }
  765. else
  766. {
  767. m_LargeVertexList.Remove( cache.m_CachedVerts );
  768. }
  769. }
  770. //-----------------------------------------------------------------------------
  771. // Clears out vertices in the temporary cache
  772. //-----------------------------------------------------------------------------
  773. void CShadowMgr::ClearTempCache( )
  774. {
  775. // Clear out the vertices
  776. for (int i = m_TempVertexCache.Count(); --i >= 0; )
  777. {
  778. FreeVertices( m_TempVertexCache[i] );
  779. }
  780. m_TempVertexCache.RemoveAll();
  781. }
  782. //-----------------------------------------------------------------------------
  783. // Adds the surface to the list for this shadow
  784. //-----------------------------------------------------------------------------
  785. bool CShadowMgr::AddDecalToShadowList( ShadowHandle_t handle, ShadowDecalHandle_t decalHandle )
  786. {
  787. // Add the shadow to the list of surfaces affected by this shadow
  788. GrowSpew( m_ShadowSurfaces.NumAllocated(), m_ShadowSurfacesMax, "m_ShadowSurfaces", 8192 );
  789. ShadowSurfaceIndex_t idx = m_ShadowSurfaces.Alloc( true );
  790. if ( idx == m_ShadowSurfaces.InvalidIndex() )
  791. {
  792. ExecuteNTimes( 10, Warning( "CShadowMgr::AddDecalToShadowList - overflowed m_ShadowSurfaces linked list!\n" ) );
  793. return false;
  794. }
  795. m_ShadowSurfaces[idx] = decalHandle;
  796. if ( m_Shadows[handle].m_FirstDecal != m_ShadowSurfaces.InvalidIndex() )
  797. {
  798. m_ShadowSurfaces.LinkBefore( m_Shadows[handle].m_FirstDecal, idx );
  799. }
  800. m_Shadows[handle].m_FirstDecal = idx;
  801. m_ShadowDecals[decalHandle].m_ShadowListIndex = idx;
  802. return true;
  803. }
  804. //-----------------------------------------------------------------------------
  805. // Removes the shadow to the list of surfaces
  806. //-----------------------------------------------------------------------------
  807. void CShadowMgr::RemoveDecalFromShadowList( ShadowHandle_t handle, ShadowDecalHandle_t decalHandle )
  808. {
  809. ShadowSurfaceIndex_t idx = m_ShadowDecals[decalHandle].m_ShadowListIndex;
  810. // Make sure the list of shadow decals for a single shadow is ok
  811. if ( m_Shadows[handle].m_FirstDecal == idx )
  812. {
  813. m_Shadows[handle].m_FirstDecal = m_ShadowSurfaces.Next(idx);
  814. }
  815. // Remove it from the shadow surfaces list
  816. m_ShadowSurfaces.Free(idx);
  817. // Blat out the decal index
  818. m_ShadowDecals[decalHandle].m_ShadowListIndex = m_ShadowSurfaces.InvalidIndex();
  819. }
  820. //-----------------------------------------------------------------------------
  821. // Computes spherical bounds for a surface
  822. //-----------------------------------------------------------------------------
  823. void CShadowMgr::ComputeSurfaceBounds( SurfaceBounds_t* pBounds, SurfaceHandle_t nSurfID )
  824. {
  825. pBounds->m_vecCenter.Init();
  826. pBounds->m_vecMins = ReplicateX4( FLT_MAX );
  827. pBounds->m_vecMaxs = ReplicateX4( -FLT_MAX );
  828. int nCount = MSurf_VertCount( nSurfID );
  829. for ( int i = 0; i < nCount; ++i )
  830. {
  831. int nVertIndex = host_state.worldbrush->vertindices[ MSurf_FirstVertIndex( nSurfID ) + i ];
  832. const Vector &position = host_state.worldbrush->vertexes[ nVertIndex ].position;
  833. pBounds->m_vecCenter += position;
  834. fltx4 pos4 = LoadUnaligned3SIMD( position.Base() );
  835. pBounds->m_vecMins = MinSIMD( pos4, pBounds->m_vecMins );
  836. pBounds->m_vecMaxs = MaxSIMD( pos4, pBounds->m_vecMaxs );
  837. }
  838. fltx4 eps = ReplicateX4( 1e-3 );
  839. pBounds->m_vecMins = SetWToZeroSIMD( SubSIMD( pBounds->m_vecMins, eps ) );
  840. pBounds->m_vecMaxs = SetWToZeroSIMD( AddSIMD( pBounds->m_vecMaxs, eps ) );
  841. pBounds->m_vecCenter /= nCount;
  842. pBounds->m_flRadius = 0.0f;
  843. for ( int i = 0; i < nCount; ++i )
  844. {
  845. int nVertIndex = host_state.worldbrush->vertindices[ MSurf_FirstVertIndex( nSurfID ) + i ];
  846. const Vector &position = host_state.worldbrush->vertexes[ nVertIndex ].position;
  847. float flDistSq = position.DistToSqr( pBounds->m_vecCenter );
  848. if ( flDistSq > pBounds->m_flRadius )
  849. {
  850. pBounds->m_flRadius = flDistSq;
  851. }
  852. }
  853. pBounds->m_flRadius = sqrt( pBounds->m_flRadius );
  854. }
  855. //-----------------------------------------------------------------------------
  856. // Get spherical bounds for a surface
  857. //-----------------------------------------------------------------------------
  858. const CShadowMgr::SurfaceBounds_t* CShadowMgr::GetSurfaceBounds( SurfaceHandle_t surfID )
  859. {
  860. int nSurfaceIndex = MSurf_Index( surfID );
  861. // NOTE: We're not bumping the surface index to the front of the LRU
  862. // here, but I think if we did the cost doing that would exceed the cost
  863. // of anything else in this path.
  864. // If this turns out to not be true, then we should make this a true LRU
  865. if ( m_pSurfaceBounds[nSurfaceIndex] != m_SurfaceBoundsCache.InvalidIndex() )
  866. return &m_SurfaceBoundsCache[ m_pSurfaceBounds[nSurfaceIndex] ];
  867. SurfaceBoundsCacheIndex_t nIndex;
  868. if ( m_SurfaceBoundsCache.Count() >= SURFACE_BOUNDS_CACHE_COUNT )
  869. {
  870. // Retire existing cache entry if we're out of space,
  871. // move it to the head of the LRU cache
  872. nIndex = m_SurfaceBoundsCache.Tail( );
  873. m_SurfaceBoundsCache.Unlink( nIndex );
  874. m_SurfaceBoundsCache.LinkToHead( nIndex );
  875. m_pSurfaceBounds[ m_SurfaceBoundsCache[nIndex].m_nSurfaceIndex ] = m_SurfaceBoundsCache.InvalidIndex();
  876. }
  877. else
  878. {
  879. // Allocate new cache entry if we have more room
  880. nIndex = m_SurfaceBoundsCache.AddToHead( );
  881. }
  882. m_pSurfaceBounds[ nSurfaceIndex ] = nIndex;
  883. // Computes the surface bounds
  884. SurfaceBounds_t &bounds = m_SurfaceBoundsCache[nIndex];
  885. bounds.m_nSurfaceIndex = nSurfaceIndex;
  886. ComputeSurfaceBounds( &bounds, surfID );
  887. return &bounds;
  888. }
  889. //-----------------------------------------------------------------------------
  890. // Is the shadow near the surface?
  891. //-----------------------------------------------------------------------------
  892. bool CShadowMgr::IsShadowNearSurface( ShadowHandle_t h, SurfaceHandle_t nSurfID,
  893. const VMatrix* pModelToWorld, const VMatrix* pWorldToModel )
  894. {
  895. const Shadow_t &shadow = m_Shadows[h];
  896. const SurfaceBounds_t* pBounds = GetSurfaceBounds( nSurfID );
  897. Vector vecSurfCenter;
  898. if ( !pModelToWorld )
  899. {
  900. vecSurfCenter = pBounds->m_vecCenter;
  901. }
  902. else
  903. {
  904. Vector3DMultiplyPosition( *pModelToWorld, pBounds->m_vecCenter, vecSurfCenter );
  905. }
  906. // Sphere check
  907. Vector vecDelta;
  908. VectorSubtract( shadow.m_vecSphereCenter, vecSurfCenter, vecDelta );
  909. float flDistSqr = vecDelta.LengthSqr();
  910. float flMinDistSqr = pBounds->m_flRadius + shadow.m_flSphereRadius;
  911. flMinDistSqr *= flMinDistSqr;
  912. if ( flDistSqr >= flMinDistSqr )
  913. return false;
  914. if ( !pModelToWorld )
  915. return IsBoxIntersectingRay( pBounds->m_vecMins, pBounds->m_vecMaxs, shadow.m_Ray );
  916. Ray_t transformedRay;
  917. Vector3DMultiplyPosition( *pWorldToModel, shadow.m_Ray.m_Start, transformedRay.m_Start );
  918. Vector3DMultiply( *pWorldToModel, shadow.m_Ray.m_Delta, transformedRay.m_Delta );
  919. transformedRay.m_StartOffset = shadow.m_Ray.m_StartOffset;
  920. transformedRay.m_Extents = shadow.m_Ray.m_Extents;
  921. transformedRay.m_IsRay = shadow.m_Ray.m_IsRay;
  922. transformedRay.m_IsSwept = shadow.m_Ray.m_IsSwept;
  923. return IsBoxIntersectingRay( pBounds->m_vecMins, pBounds->m_vecMaxs, transformedRay );
  924. }
  925. //-----------------------------------------------------------------------------
  926. // Adds the shadow decal reference to the surface
  927. //-----------------------------------------------------------------------------
  928. inline ShadowDecalHandle_t CShadowMgr::AddShadowDecalToSurface( SurfaceHandle_t surfID, ShadowHandle_t handle )
  929. {
  930. GrowSpew( m_ShadowDecals.NumAllocated(), m_ShadowDecalsMax, "m_ShadowDecals", 8192 );
  931. ShadowDecalHandle_t decalHandle = m_ShadowDecals.Alloc( true );
  932. if ( decalHandle == m_ShadowDecals.InvalidIndex() )
  933. {
  934. ExecuteNTimes( 10, Warning( "CShadowMgr::AddShadowDecalToSurface - overflowed m_ShadowDecals linked list!\n" ) );
  935. return decalHandle;
  936. }
  937. ShadowDecal_t& decal = m_ShadowDecals[decalHandle];
  938. decal.m_SurfID = surfID;
  939. m_ShadowDecals.LinkBefore( MSurf_ShadowDecals( surfID ), decalHandle );
  940. MSurf_ShadowDecals( surfID ) = decalHandle;
  941. // Hook the shadow into the displacement system....
  942. if ( !SurfaceHasDispInfo( surfID ) )
  943. {
  944. decal.m_DispShadow = DISP_SHADOW_HANDLE_INVALID;
  945. }
  946. else
  947. {
  948. decal.m_DispShadow = MSurf_DispInfo( surfID )->AddShadowDecal( handle );
  949. }
  950. decal.m_Shadow = handle;
  951. decal.m_ShadowVerts = m_VertexCache.InvalidIndex();
  952. decal.m_NextRender = SHADOW_DECAL_HANDLE_INVALID;
  953. decal.m_ShadowListIndex = m_ShadowSurfaces.InvalidIndex();
  954. //=============================================================================
  955. // HPE_BEGIN:
  956. // [smessick] Check the return value of AddDecalToShadowList and make sure
  957. // to delete the newly created shadow decal if there is a failure.
  958. //=============================================================================
  959. if ( !AddDecalToShadowList( handle, decalHandle ) )
  960. {
  961. m_ShadowDecals.Free( decalHandle );
  962. decalHandle = m_ShadowDecals.InvalidIndex();
  963. }
  964. //=============================================================================
  965. // HPE_END
  966. //=============================================================================
  967. return decalHandle;
  968. }
  969. inline void CShadowMgr::RemoveShadowDecalFromSurface( SurfaceHandle_t surfID, ShadowDecalHandle_t decalHandle )
  970. {
  971. // Clean up its shadow verts if it has any
  972. ShadowDecal_t& decal = m_ShadowDecals[decalHandle];
  973. if (decal.m_ShadowVerts != m_VertexCache.InvalidIndex())
  974. {
  975. FreeVertices( m_VertexCache[decal.m_ShadowVerts] );
  976. m_VertexCache.Remove(decal.m_ShadowVerts);
  977. decal.m_ShadowVerts = m_VertexCache.InvalidIndex();
  978. }
  979. // Clean up displacement...
  980. if ( decal.m_DispShadow != DISP_SHADOW_HANDLE_INVALID )
  981. {
  982. MSurf_DispInfo( decal.m_SurfID )->RemoveShadowDecal( decal.m_DispShadow );
  983. }
  984. // Make sure the list of shadow decals on a surface is set up correctly
  985. if ( MSurf_ShadowDecals( surfID ) == decalHandle )
  986. {
  987. MSurf_ShadowDecals( surfID ) = m_ShadowDecals.Next(decalHandle);
  988. }
  989. RemoveDecalFromShadowList( decal.m_Shadow, decalHandle );
  990. // Kill the shadow decal
  991. m_ShadowDecals.Free( decalHandle );
  992. }
  993. void CShadowMgr::AddSurfaceToFlashlightMaterialBuckets( ShadowHandle_t handle, SurfaceHandle_t surfID )
  994. {
  995. if ( m_bSinglePassFlashlightStateEnabled )
  996. return;
  997. // Make sure that this is a flashlight.
  998. Assert( m_Shadows[handle].m_Flags & ( SHADOW_FLASHLIGHT | SHADOW_SIMPLE_PROJECTION ) );
  999. // Get the flashlight id for this particular shadow handle and make sure that it's valid.
  1000. FlashlightHandle_t flashlightID = m_Shadows[handle].m_FlashlightHandle;
  1001. Assert( flashlightID != m_FlashlightStates.InvalidIndex() );
  1002. if ( m_FlashlightStates[ flashlightID ].m_nSplitscreenOwner >= 0 )
  1003. {
  1004. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  1005. if ( m_FlashlightStates[ flashlightID ].m_nSplitscreenOwner != GET_ACTIVE_SPLITSCREEN_SLOT() )
  1006. return;
  1007. }
  1008. m_FlashlightStates[flashlightID].m_MaterialBuckets.AddElement( MSurf_MaterialSortID( surfID ), surfID );
  1009. }
  1010. //-----------------------------------------------------------------------------
  1011. // Adds the shadow decal reference to the surface
  1012. // This causes a shadow decal to be made
  1013. //-----------------------------------------------------------------------------
  1014. void CShadowMgr::AddSurfaceToShadow( ShadowHandle_t handle, SurfaceHandle_t surfID )
  1015. {
  1016. // FIXME: We could make this work, but there's a perf cost...
  1017. // Basically, we'd need to have a separate rendering batch for
  1018. // each translucent material the shadow is projected onto. The
  1019. // material alpha would have to be taken into account, so that
  1020. // no multiplication occurs where the alpha == 0
  1021. // FLASHLIGHTFIXME: get rid of some of these checks for the ones that will work just fine with the flashlight.
  1022. bool bIsFlashlight = ( ( m_Shadows[handle].m_Flags & ( SHADOW_FLASHLIGHT | SHADOW_SIMPLE_PROJECTION ) ) != 0 );
  1023. if ( !bIsFlashlight && MSurf_Flags(surfID) & (SURFDRAW_TRANS | SURFDRAW_ALPHATEST | SURFDRAW_NOSHADOWS) )
  1024. return;
  1025. #if 0
  1026. // Make sure the surface has the shadow on it exactly once...
  1027. ShadowDecalHandle_t dh = MSurf_ShadowDecals( surfID );
  1028. while (dh != m_ShadowDecals.InvalidIndex() )
  1029. {
  1030. Assert ( m_ShadowDecals[dh].m_Shadow != handle );
  1031. dh = m_ShadowDecals.Next(dh);
  1032. }
  1033. #endif
  1034. // Create a shadow decal for this surface and add it to the surface
  1035. AddShadowDecalToSurface( surfID, handle );
  1036. }
  1037. void CShadowMgr::RemoveSurfaceFromShadow( ShadowHandle_t handle, SurfaceHandle_t surfID )
  1038. {
  1039. // Find the decal associated with the handle that lies on the surface
  1040. // FIXME: Linear search; bleah.
  1041. // Luckily the search is probably over only a couple items at most
  1042. // Linear searching over the shadow surfaces so we can remove the entry
  1043. // in the shadow surface list if we find a match
  1044. ASSERT_SURF_VALID( surfID );
  1045. ShadowSurfaceIndex_t i = m_Shadows[handle].m_FirstDecal;
  1046. while ( i != m_ShadowSurfaces.InvalidIndex() )
  1047. {
  1048. ShadowDecalHandle_t decalHandle = m_ShadowSurfaces[i];
  1049. if ( m_ShadowDecals[decalHandle].m_SurfID == surfID )
  1050. {
  1051. // Found a match! There should be at most one shadow decal
  1052. // associated with a particular shadow per surface
  1053. RemoveShadowDecalFromSurface( surfID, decalHandle );
  1054. // FIXME: Could check the shadow doesn't appear again in the list
  1055. return;
  1056. }
  1057. i = m_ShadowSurfaces.Next(i);
  1058. }
  1059. #ifdef _DEBUG
  1060. // Here, the shadow didn't have the surface in its list
  1061. // let's make sure the surface doesn't think it's got the shadow in its list
  1062. ShadowDecalHandle_t dh = MSurf_ShadowDecals( surfID );
  1063. while (dh != m_ShadowDecals.InvalidIndex() )
  1064. {
  1065. Assert ( m_ShadowDecals[dh].m_Shadow != handle );
  1066. dh = m_ShadowDecals.Next(dh);
  1067. }
  1068. #endif
  1069. }
  1070. void CShadowMgr::RemoveAllSurfacesFromShadow( ShadowHandle_t handle )
  1071. {
  1072. // Iterate over all the decals associated with a particular shadow
  1073. // Remove the decals from the surfaces they are associated with
  1074. ShadowSurfaceIndex_t i = m_Shadows[handle].m_FirstDecal;
  1075. ShadowSurfaceIndex_t next;
  1076. while ( i != m_ShadowSurfaces.InvalidIndex() )
  1077. {
  1078. ShadowDecalHandle_t decalHandle = m_ShadowSurfaces[i];
  1079. next = m_ShadowSurfaces.Next(i);
  1080. RemoveShadowDecalFromSurface( m_ShadowDecals[decalHandle].m_SurfID, decalHandle );
  1081. i = next;
  1082. }
  1083. m_Shadows[handle].m_FirstDecal = m_ShadowSurfaces.InvalidIndex();
  1084. }
  1085. void CShadowMgr::RemoveAllShadowsFromSurface( SurfaceHandle_t surfID )
  1086. {
  1087. // Iterate over all the decals associated with a particular shadow
  1088. // Remove the decals from the surfaces they are associated with
  1089. ShadowDecalHandle_t dh = MSurf_ShadowDecals( surfID );
  1090. while (dh != m_ShadowDecals.InvalidIndex() )
  1091. {
  1092. // Remove this shadow from the surface
  1093. ShadowDecalHandle_t next = m_ShadowDecals.Next(dh);
  1094. // Remove the surface from the shadow
  1095. RemoveShadowDecalFromSurface( m_ShadowDecals[dh].m_SurfID, dh );
  1096. dh = next;
  1097. }
  1098. MSurf_ShadowDecals( surfID ) = m_ShadowDecals.InvalidIndex();
  1099. }
  1100. //-----------------------------------------------------------------------------
  1101. // Shadow/model association
  1102. //-----------------------------------------------------------------------------
  1103. void CShadowMgr::AddShadowToModel( ShadowHandle_t handle, ModelInstanceHandle_t model )
  1104. {
  1105. // FIXME: Add culling here based on the model bbox
  1106. // and the shadow bbox
  1107. // FIXME:
  1108. /*
  1109. // Trivial bbox reject.
  1110. Vector bbMin, bbMax;
  1111. pDisp->GetBoundingBox( bbMin, bbMax );
  1112. if( decalinfo->m_Position.x - decalinfo->m_Size < bbMax.x && decalinfo->m_Position.x + decalinfo->m_Size > bbMin.x &&
  1113. decalinfo->m_Position.y - decalinfo->m_Size < bbMax.y && decalinfo->m_Position.y + decalinfo->m_Size > bbMin.y &&
  1114. decalinfo->m_Position.z - decalinfo->m_Size < bbMax.z && decalinfo->m_Position.z + decalinfo->m_Size > bbMin.z )
  1115. */
  1116. if ( model == MODEL_INSTANCE_INVALID )
  1117. {
  1118. // async data not loaded yet
  1119. return;
  1120. }
  1121. if( r_flashlightrender.GetBool()==false )
  1122. return;
  1123. GrowSpew( m_ShadowsOnModels.NumAllocated(), m_ShadowsOnModelsMax, "m_ShadowsOnModels" );
  1124. m_ShadowsOnModels.AddElementToBucket( model, handle );
  1125. }
  1126. void CShadowMgr::RemoveAllShadowsFromModel( ModelInstanceHandle_t model )
  1127. {
  1128. if( model != MODEL_INSTANCE_INVALID )
  1129. {
  1130. m_ShadowsOnModels.RemoveBucket( model );
  1131. }
  1132. }
  1133. int CShadowMgr::GetNumShadowsOnModel( ModelInstanceHandle_t instance )
  1134. {
  1135. if (instance == MODEL_INSTANCE_INVALID || r_shadows.GetInt() == 0 || m_bShadowsDisabled )
  1136. {
  1137. // no shadows
  1138. return 0;
  1139. }
  1140. int i = m_ShadowsOnModels.FirstElement( instance );
  1141. int nCount = 0;
  1142. // TODO: Add method to query num elements in a bucket to CUtlBidirectionalSet
  1143. while ( i != m_ShadowsOnModels.InvalidIndex() )
  1144. {
  1145. nCount++;
  1146. i = m_ShadowsOnModels.NextElement(i);
  1147. }
  1148. return nCount;
  1149. }
  1150. int CShadowMgr::GetShadowsOnModel( ModelInstanceHandle_t instance, ShadowHandle_t* pShadowArray, bool bNormalShadows, bool bFlashlightShadows )
  1151. {
  1152. if (instance == MODEL_INSTANCE_INVALID || r_shadows.GetInt() == 0 || m_bShadowsDisabled )
  1153. {
  1154. // no shadows
  1155. return 0;
  1156. }
  1157. int i = m_ShadowsOnModels.FirstElement( instance );
  1158. int nCount = 0;
  1159. while ( i != m_ShadowsOnModels.InvalidIndex() )
  1160. {
  1161. Shadow_t& shadow = m_Shadows[m_ShadowsOnModels.Element(i)];
  1162. bool bFlashlight = ( ( shadow.m_Flags & ( SHADOW_FLASHLIGHT | SHADOW_SIMPLE_PROJECTION ) ) != 0 );
  1163. if ( ( bFlashlight && bFlashlightShadows ) ||
  1164. ( !bFlashlight && bNormalShadows ) )
  1165. {
  1166. *pShadowArray = m_ShadowsOnModels.Element(i);
  1167. pShadowArray++;
  1168. nCount++;
  1169. }
  1170. i = m_ShadowsOnModels.NextElement(i);
  1171. }
  1172. return nCount;
  1173. }
  1174. void CShadowMgr::RemoveAllModelsFromShadow( ShadowHandle_t handle )
  1175. {
  1176. m_ShadowsOnModels.RemoveElement( handle );
  1177. }
  1178. //-----------------------------------------------------------------------------
  1179. // Shadow state...
  1180. //-----------------------------------------------------------------------------
  1181. void CShadowMgr::SetModelShadowState( ModelInstanceHandle_t instance )
  1182. {
  1183. #ifndef DEDICATED
  1184. VPROF_( "CShadowMgr::SetModelShadowState", 2, VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, false, 0 );
  1185. g_pStudioRender->ClearAllShadows();
  1186. if ( ( instance == MODEL_INSTANCE_INVALID ) || ( r_shadows.GetInt() == 0 ) || m_bShadowsDisabled )
  1187. return;
  1188. bool bWireframe = r_shadowwireframe.GetBool();
  1189. for ( int i = m_ShadowsOnModels.FirstElement( instance ); i != m_ShadowsOnModels.InvalidIndex(); i = m_ShadowsOnModels.NextElement( i ) )
  1190. {
  1191. Shadow_t& shadow = m_Shadows[m_ShadowsOnModels.Element(i)];
  1192. if ( shadow.m_Flags & ( SHADOW_FLASHLIGHT | SHADOW_SIMPLE_PROJECTION ) )
  1193. {
  1194. if ( m_FlashlightStates[ shadow.m_FlashlightHandle ].m_nSplitscreenOwner >= 0 )
  1195. {
  1196. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  1197. if ( m_FlashlightStates[ shadow.m_FlashlightHandle ].m_nSplitscreenOwner != GET_ACTIVE_SPLITSCREEN_SLOT() )
  1198. {
  1199. continue;
  1200. }
  1201. }
  1202. }
  1203. if ( !bWireframe )
  1204. {
  1205. if ( shadow.m_Flags & ( SHADOW_FLASHLIGHT | SHADOW_SIMPLE_PROJECTION ) )
  1206. {
  1207. // NULL means that the models material should be used.
  1208. // This is what we want in the case of the flashlight
  1209. // since we need to render the models material again with different lighting.
  1210. // Need to add something here to specify which flashlight.
  1211. g_pStudioRender->AddShadow( NULL, NULL, &m_FlashlightStates[shadow.m_FlashlightHandle].m_FlashlightState, &shadow.m_WorldToShadow, shadow.m_pFlashlightDepthTexture );
  1212. }
  1213. else if ( r_shadows_gamecontrol.GetInt() != 0 )
  1214. {
  1215. g_pStudioRender->AddShadow( shadow.m_pModelMaterial, shadow.m_pBindProxy );
  1216. }
  1217. }
  1218. else if ( ( shadow.m_Flags & ( SHADOW_FLASHLIGHT | SHADOW_SIMPLE_PROJECTION ) ) || r_shadows_gamecontrol.GetInt() != 0 )
  1219. {
  1220. g_pStudioRender->AddShadow( g_pMaterialMRMWireframe, NULL );
  1221. }
  1222. }
  1223. #endif
  1224. }
  1225. bool CShadowMgr::ModelHasShadows( ModelInstanceHandle_t instance )
  1226. {
  1227. if ( instance != MODEL_INSTANCE_INVALID )
  1228. {
  1229. if ( m_ShadowsOnModels.FirstElement(instance) != m_ShadowsOnModels.InvalidIndex() )
  1230. return true;
  1231. }
  1232. return false;
  1233. }
  1234. //-----------------------------------------------------------------------------
  1235. // Builds shadow state information for a set of instances
  1236. //-----------------------------------------------------------------------------
  1237. int CShadowMgr::SetupFlashlightRenderInstanceInfo( ShadowHandle_t *pShadowHandle, uint32 *pModelUsageMask, int nUsageStride, int nInstanceCount, const ModelInstanceHandle_t *pInstance )
  1238. {
  1239. CMatRenderContextPtr pRenderContext( materials );
  1240. int nFlashlightCount = 0;
  1241. #ifndef DEDICATED
  1242. if ( ( SinglePassFlashlightModeEnabled() && !pRenderContext->IsCullingEnabledForSinglePassFlashlight() ) || !r_shadows.GetInt() )
  1243. return 0;
  1244. for ( int i = 0; i < nInstanceCount; ++i, pModelUsageMask = (uint32*)( (char*)pModelUsageMask + nUsageStride ) )
  1245. {
  1246. ModelInstanceHandle_t instance = pInstance[i];
  1247. *pModelUsageMask = 0;
  1248. if ( instance == MODEL_INSTANCE_INVALID )
  1249. continue;
  1250. int j = m_ShadowsOnModels.FirstElement( instance );
  1251. for ( ; j != m_ShadowsOnModels.InvalidIndex(); j = m_ShadowsOnModels.NextElement(j) )
  1252. {
  1253. ShadowHandle_t hFlashlight = m_ShadowsOnModels.Element(j);
  1254. Shadow_t& shadow = m_Shadows[ hFlashlight ];
  1255. if ( ( shadow.m_Flags & ( SHADOW_FLASHLIGHT | SHADOW_SIMPLE_PROJECTION ) ) == 0 )
  1256. continue;
  1257. if ( m_FlashlightStates[ shadow.m_FlashlightHandle ].m_nSplitscreenOwner >= 0 )
  1258. {
  1259. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  1260. if ( m_FlashlightStates[ shadow.m_FlashlightHandle ].m_nSplitscreenOwner != GET_ACTIVE_SPLITSCREEN_SLOT() )
  1261. continue;
  1262. }
  1263. // FIXME: is there a faster method?
  1264. int nFlashlightIndex;
  1265. for ( nFlashlightIndex = 0; nFlashlightIndex < nFlashlightCount; ++nFlashlightIndex )
  1266. {
  1267. if ( pShadowHandle[nFlashlightIndex] == hFlashlight )
  1268. break;
  1269. }
  1270. // Indicate the model is using this flashlight
  1271. *pModelUsageMask |= (1 << nFlashlightIndex);
  1272. if ( nFlashlightIndex != nFlashlightCount )
  1273. continue;
  1274. // Flashlight not found, add unique flashlight
  1275. pShadowHandle[nFlashlightIndex] = hFlashlight;
  1276. ++nFlashlightCount;
  1277. }
  1278. }
  1279. #endif
  1280. return nFlashlightCount;
  1281. }
  1282. void CShadowMgr::GetFlashlightRenderInfo( FlashlightInstance_t *pFlashlightState, int nCount, const ShadowHandle_t *pHandles )
  1283. {
  1284. bool bWireframe = r_shadowwireframe.GetBool();
  1285. for ( int i = 0; i < nCount; ++i )
  1286. {
  1287. const Shadow_t& shadow = m_Shadows[ pHandles[i] ];
  1288. FlashlightInstance_t &flashlight = pFlashlightState[i];
  1289. flashlight.m_FlashlightState = m_FlashlightStates[ shadow.m_FlashlightHandle ].m_FlashlightState;
  1290. flashlight.m_WorldToTexture = shadow.m_WorldToShadow;
  1291. flashlight.m_pDebugMaterial = bWireframe ? g_pMaterialMRMWireframe : NULL;
  1292. flashlight.m_pFlashlightDepthTexture = shadow.m_pFlashlightDepthTexture;
  1293. }
  1294. }
  1295. //-----------------------------------------------------------------------------
  1296. // Applies the shadow to a surface
  1297. //-----------------------------------------------------------------------------
  1298. void CShadowMgr::ApplyShadowToSurface( ShadowBuildInfo_t& build, SurfaceHandle_t surfID )
  1299. {
  1300. // We've found a potential surface to add to the shadow
  1301. // At this point, we want to do fast culling to see whether we actually
  1302. // should apply the shadow or not before actually adding it to any lists
  1303. // FIXME: implement
  1304. // Put the texture extents into shadow space; see if there's an intersection
  1305. // If not, we can early out
  1306. // To do this, we're gonna want to project the surface into the space of the decal
  1307. // Therefore, we want to produce a surface->world transformation, and a
  1308. // world->shadow/light space transformation
  1309. // Then we transform the surface points into shadow space and apply the projection
  1310. // in shadow space.
  1311. /*
  1312. // Get the texture associated with this surface
  1313. mtexinfo_t* tex = pSurface->texinfo;
  1314. Vector4D &textureU = tex->textureVecsTexelsPerWorldUnits[0];
  1315. Vector4D &textureV = tex->textureVecsTexelsPerWorldUnits[1];
  1316. // project decal center into the texture space of the surface
  1317. float s = DotProduct( decalinfo->m_Position, textureU.AsVector3D() ) +
  1318. textureU.w - surf->textureMins[0];
  1319. float t = DotProduct( decalinfo->m_Position, textureV.AsVector3D() ) +
  1320. textureV.w - surf->textureMins[1];
  1321. */
  1322. // Don't do any more computation at the moment, only do it if
  1323. // we end up rendering the surface later on
  1324. AddSurfaceToShadow( build.m_Shadow, surfID );
  1325. }
  1326. //-----------------------------------------------------------------------------
  1327. // Applies the shadow to a displacement
  1328. //-----------------------------------------------------------------------------
  1329. void CShadowMgr::ApplyShadowToDisplacement( ShadowBuildInfo_t& build, IDispInfo *pDispInfo, bool bIsFlashlight )
  1330. {
  1331. // Avoid noshadow displacements
  1332. if ( !bIsFlashlight && ( MSurf_Flags( pDispInfo->GetParent() ) & SURFDRAW_NOSHADOWS ) )
  1333. return;
  1334. // Trivial bbox reject.
  1335. Vector bbMin, bbMax;
  1336. pDispInfo->GetBoundingBox( bbMin, bbMax );
  1337. if ( !bIsFlashlight )
  1338. {
  1339. if ( !IsBoxIntersectingSphere( bbMin, bbMax, build.m_vecSphereCenter, build.m_flSphereRadius ) )
  1340. return;
  1341. }
  1342. else
  1343. {
  1344. if( GetFlashlightFrustum( build.m_Shadow ).CullBox( bbMin, bbMax ) )
  1345. return;
  1346. }
  1347. SurfaceHandle_t surfID = pDispInfo->GetParent();
  1348. if ( surfID->m_bDynamicShadowsEnabled == false && !bIsFlashlight )
  1349. return;
  1350. AddSurfaceToShadow( build.m_Shadow, surfID );
  1351. }
  1352. //-----------------------------------------------------------------------------
  1353. // Allows us to disable particular shadows
  1354. //-----------------------------------------------------------------------------
  1355. void CShadowMgr::EnableShadow( ShadowHandle_t handle, bool bEnable )
  1356. {
  1357. if (!bEnable)
  1358. {
  1359. // We need to remove the shadow from all surfaces it may currently be in
  1360. RemoveAllSurfacesFromShadow( handle );
  1361. RemoveAllModelsFromShadow( handle );
  1362. m_Shadows[handle].m_Flags |= SHADOW_DISABLED;
  1363. }
  1364. else
  1365. {
  1366. // FIXME: Could make this recompute the cache...
  1367. m_Shadows[handle].m_Flags &= ~SHADOW_DISABLED;
  1368. }
  1369. }
  1370. //-----------------------------------------------------------------------------
  1371. // Purpose: Set the darkness falloff bias
  1372. // Input : shadow -
  1373. // ucBias -
  1374. //-----------------------------------------------------------------------------
  1375. void CShadowMgr::SetFalloffBias( ShadowHandle_t shadow, unsigned char ucBias )
  1376. {
  1377. m_Shadows[shadow].m_FalloffBias = ucBias;
  1378. }
  1379. //-----------------------------------------------------------------------------
  1380. // Recursive routine to find surface to apply a decal to. World coordinates of
  1381. // the decal are passed in r_recalpos like the rest of the engine. This should
  1382. // be called through R_DecalShoot()
  1383. //-----------------------------------------------------------------------------
  1384. void CShadowMgr::ProjectShadow( ShadowHandle_t handle, const Vector &origin,
  1385. const Vector& projectionDir, const VMatrix& worldToShadow, const Vector2D& size,
  1386. int nLeafCount, const int *pLeafList,
  1387. float maxHeight, float falloffOffset, float falloffAmount, const Vector &vecCasterOrigin )
  1388. {
  1389. VPROF_BUDGET( "CShadowMgr::ProjectShadow", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  1390. // First, we need to remove the shadow from all surfaces it may
  1391. // currently be in; in other words we're invalidating the shadow surface cache
  1392. RemoveAllSurfacesFromShadow( handle );
  1393. RemoveAllModelsFromShadow( handle );
  1394. // Don't bother with this shadow if it's disabled
  1395. Shadow_t &shadow = m_Shadows[handle];
  1396. if ( shadow.m_Flags & SHADOW_DISABLED )
  1397. return;
  1398. // Don't compute the surface cache if shadows are off..
  1399. if ( !r_shadows.GetInt() || m_bShadowsDisabled )
  1400. return;
  1401. // Set the falloff coefficient
  1402. shadow.m_FalloffOffset = falloffOffset;
  1403. VectorCopy( projectionDir, shadow.m_ProjectionDir );
  1404. // We need to know about surfaces in leaves hit by the ray...
  1405. // We'd like to stop iterating as soon as the entire swept volume
  1406. // enters a solid leaf; that may be hard to determine. Instead,
  1407. // we should stop iterating when the ray center enters a solid leaf?
  1408. AssertFloatEquals( projectionDir.LengthSqr(), 1.0f, 1e-3 );
  1409. // The maximum ray distance is equal to the distance it takes the
  1410. // falloff to get to 15%.
  1411. shadow.m_MaxDist = maxHeight; //sqrt( coeff / 0.10f ) + falloffOffset;
  1412. shadow.m_FalloffAmount = falloffAmount;
  1413. MatrixCopy( worldToShadow, shadow.m_WorldToShadow );
  1414. // Compute a rough bounding sphere for the ray
  1415. float flRadius = sqrt( size.x * size.x + size.y * size.y ) * 0.5f;
  1416. VectorMA( origin, 0.5f * maxHeight, projectionDir, shadow.m_vecSphereCenter );
  1417. shadow.m_flSphereRadius = 0.5f * maxHeight + flRadius;
  1418. Vector vecEndPoint;
  1419. Vector vecMins( -flRadius, -flRadius, -flRadius );
  1420. Vector vecMaxs( flRadius, flRadius, flRadius );
  1421. VectorMA( origin, maxHeight, projectionDir, vecEndPoint );
  1422. shadow.m_Ray.Init( origin, vecEndPoint, vecMins, vecMaxs );
  1423. // No more work necessary if it hits no leaves
  1424. if ( nLeafCount == 0 )
  1425. return;
  1426. // We're hijacking the surface vis frame to make sure we enumerate
  1427. // surfaces only once;
  1428. ++r_surfacevisframe;
  1429. // Clear out the displacement tags also
  1430. DispInfo_ClearAllTags( host_state.worldbrush->hDispInfos );
  1431. ShadowBuildInfo_t build;
  1432. build.m_Shadow = handle;
  1433. build.m_RayStart = origin;
  1434. build.m_pVis = NULL;
  1435. build.m_vecSphereCenter = shadow.m_vecSphereCenter;
  1436. build.m_flSphereRadius = shadow.m_flSphereRadius;
  1437. VectorCopy( projectionDir, build.m_ProjectionDirection );
  1438. // Enumerate leaves
  1439. for ( int i = 0; i < nLeafCount; ++i )
  1440. {
  1441. // NOTE: Scope specifier eliminates virtual function call
  1442. CShadowMgr::EnumerateLeaf( pLeafList[i], (intp)&build );
  1443. }
  1444. }
  1445. void DrawFrustum( Frustum_t &frustum )
  1446. {
  1447. const int maxPoints = 8;
  1448. int i;
  1449. for( i = 0; i < FRUSTUM_NUMPLANES; i++ )
  1450. {
  1451. Vector points[maxPoints];
  1452. Vector points2[maxPoints];
  1453. Vector normal;
  1454. float dist;
  1455. frustum.GetPlane( i, &normal, &dist );
  1456. int numPoints = PolyFromPlane( points, normal, dist );
  1457. Assert( numPoints <= maxPoints );
  1458. Vector *in, *out;
  1459. in = points;
  1460. out = points2;
  1461. int j;
  1462. for( j = 0; j < FRUSTUM_NUMPLANES; j++ )
  1463. {
  1464. if( i == j )
  1465. {
  1466. continue;
  1467. }
  1468. frustum.GetPlane( j, &normal, &dist );
  1469. numPoints = ClipPolyToPlane( in, numPoints, out, normal, dist );
  1470. Assert( numPoints <= maxPoints );
  1471. V_swap( in, out );
  1472. }
  1473. int c;
  1474. for( c = 0; c < numPoints; c++ )
  1475. {
  1476. CDebugOverlay::AddLineOverlay( in[c], in[(c+1)%numPoints], 0, 255, 0, 255, true, 0.0f );
  1477. }
  1478. }
  1479. }
  1480. //static void LineDrawHelper( const Vector &startShadowSpace, const Vector &endShadowSpace,
  1481. // const VMatrix &shadowToWorld, unsigned char r, unsigned char g,
  1482. // unsigned char b, bool ignoreZ )
  1483. //{
  1484. // Vector startWorldSpace, endWorldSpace;
  1485. // Vector3DMultiplyPositionProjective( shadowToWorld, startShadowSpace, startWorldSpace );
  1486. // Vector3DMultiplyPositionProjective( shadowToWorld, endShadowSpace, endWorldSpace );
  1487. //
  1488. // CDebugOverlay::AddLineOverlay( startWorldSpace,
  1489. // endWorldSpace,
  1490. // r, g, b, ignoreZ
  1491. // , 0.0 );
  1492. //}
  1493. void CShadowMgr::ProjectFlashlight( ShadowHandle_t handle, const VMatrix& worldToShadow, int nLeafCount, const int *pLeafList )
  1494. {
  1495. VPROF_BUDGET( "CShadowMgr::ProjectFlashlight", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  1496. CMatRenderContextPtr pRenderContext( materials );
  1497. Shadow_t& shadow = m_Shadows[handle];
  1498. if ( !m_bSinglePassFlashlightStateEnabled || pRenderContext->IsCullingEnabledForSinglePassFlashlight() )
  1499. {
  1500. // First, we need to remove the shadow from all surfaces it may
  1501. // currently be in; in other words we're invalidating the shadow surface cache
  1502. RemoveAllSurfacesFromShadow( handle );
  1503. RemoveAllModelsFromShadow( handle );
  1504. m_FlashlightStates[ shadow.m_FlashlightHandle ].m_OccluderBuckets.Flush();
  1505. }
  1506. // Don't bother with this shadow if it's disabled
  1507. if ( m_Shadows[handle].m_Flags & SHADOW_DISABLED )
  1508. return;
  1509. // Don't compute the surface cache if shadows are off..
  1510. if ( !r_shadows.GetInt() )
  1511. return;
  1512. MatrixCopy( worldToShadow, shadow.m_WorldToShadow );
  1513. // We need this for our various bounding computations
  1514. VMatrix shadowToWorld;
  1515. MatrixInverseGeneral( shadow.m_WorldToShadow, shadowToWorld );
  1516. // Set up the frustum for the flashlight so that we can cull each leaf against it.
  1517. Assert( shadow.m_Flags & ( SHADOW_FLASHLIGHT | SHADOW_SIMPLE_PROJECTION ) );
  1518. Frustum_t &frustum = m_FlashlightStates[shadow.m_FlashlightHandle].m_Frustum;
  1519. FrustumPlanesFromMatrix( shadowToWorld, frustum );
  1520. CalculateSphereFromProjectionMatrixInverse( shadowToWorld, &shadow.m_vecSphereCenter, &shadow.m_flSphereRadius );
  1521. if ( nLeafCount == 0 )
  1522. return;
  1523. // Don't need to walk the surface list w/ single pass flashlights
  1524. if ( m_bSinglePassFlashlightStateEnabled )
  1525. return;
  1526. // We're hijacking the surface vis frame to make sure we enumerate
  1527. // surfaces only once;
  1528. ++r_surfacevisframe;
  1529. // Clear out the displacement tags also
  1530. DispInfo_ClearAllTags( host_state.worldbrush->hDispInfos );
  1531. ShadowBuildInfo_t build;
  1532. build.m_Shadow = handle;
  1533. build.m_RayStart = m_FlashlightStates[shadow.m_FlashlightHandle].m_FlashlightState.m_vecLightOrigin;
  1534. build.m_pVis = NULL;
  1535. build.m_vecSphereCenter = shadow.m_vecSphereCenter;
  1536. build.m_flSphereRadius = shadow.m_flSphereRadius;
  1537. for ( int i = 0; i < nLeafCount; ++i )
  1538. {
  1539. // NOTE: Scope specifier eliminates virtual function call
  1540. CShadowMgr::EnumerateLeaf( pLeafList[i], (intp)&build );
  1541. }
  1542. }
  1543. //-----------------------------------------------------------------------------
  1544. // Applies the flashlight to all surfaces in the leaf
  1545. //-----------------------------------------------------------------------------
  1546. void CShadowMgr::ApplyFlashlightToLeaf( const Shadow_t &shadow, mleaf_t* pLeaf, ShadowBuildInfo_t* pBuild )
  1547. {
  1548. // Get the bounds of the leaf so that we can test it against the flashlight frustum.
  1549. Vector leafMins, leafMaxs;
  1550. VectorAdd( pLeaf->m_vecCenter, pLeaf->m_vecHalfDiagonal, leafMaxs );
  1551. VectorSubtract( pLeaf->m_vecCenter, pLeaf->m_vecHalfDiagonal, leafMins );
  1552. // The flashlight frustum didn't intersect the bounding box for this leaf! Get outta here!
  1553. if( GetFlashlightFrustum( pBuild->m_Shadow ).CullBox( leafMins, leafMaxs ) )
  1554. return;
  1555. // Iterate over all surfaces in the leaf, check for backfacing
  1556. // and apply the shadow to the surface if it's not backfaced.
  1557. // Note that this really only indicates that the shadow may potentially
  1558. // sit on the surface; when we render, we'll actually do the clipping
  1559. // computation and at that point we'll remove surfaces that don't
  1560. // actually hit the surface
  1561. bool bCullDepth = r_flashlightculldepth.GetBool();
  1562. SurfaceHandle_t *pHandle = &host_state.worldbrush->marksurfaces[pLeaf->firstmarksurface];
  1563. for ( int i = 0; i < pLeaf->nummarksurfaces; i++ )
  1564. {
  1565. SurfaceHandle_t surfID = pHandle[i];
  1566. // only process each surface once;
  1567. if( MSurf_VisFrame( surfID ) == r_surfacevisframe )
  1568. continue;
  1569. MSurf_VisFrame( surfID ) = r_surfacevisframe;
  1570. Assert( !MSurf_DispInfo( surfID ) );
  1571. // perspective projection
  1572. // world-space vertex
  1573. int vertIndex = host_state.worldbrush->vertindices[MSurf_FirstVertIndex( surfID )];
  1574. Vector& worldPos = host_state.worldbrush->vertexes[vertIndex].position;
  1575. // Get the lookdir
  1576. Vector lookdir;
  1577. VectorSubtract( worldPos, pBuild->m_RayStart, lookdir );
  1578. VectorNormalize( lookdir );
  1579. const cplane_t &surfPlane = MSurf_Plane( surfID );
  1580. // Now apply the spherical cull
  1581. float flDist = DotProduct( surfPlane.normal, pBuild->m_vecSphereCenter ) - surfPlane.dist;
  1582. if ( fabs(flDist) >= pBuild->m_flSphereRadius )
  1583. continue;
  1584. ApplyShadowToSurface( *pBuild, surfID );
  1585. // Backface cull
  1586. if( bCullDepth )
  1587. {
  1588. if ( (MSurf_Flags( surfID ) & SURFDRAW_NOCULL) == 0 )
  1589. {
  1590. if ( DotProduct(surfPlane.normal, lookdir) < SHADOW_BACKFACE_EPSILON )
  1591. continue;
  1592. }
  1593. else
  1594. {
  1595. // Avoid edge-on shadows regardless.
  1596. float dot = DotProduct(surfPlane.normal, lookdir);
  1597. if (fabs(dot) < SHADOW_BACKFACE_EPSILON)
  1598. continue;
  1599. }
  1600. }
  1601. FlashlightInfo_t &flashlightInfo = m_FlashlightStates[ shadow.m_FlashlightHandle ];
  1602. flashlightInfo.m_OccluderBuckets.AddElement( MSurf_MaterialSortID( surfID ), surfID );
  1603. }
  1604. }
  1605. //-----------------------------------------------------------------------------
  1606. // Applies a shadow to all surfaces in the leaf
  1607. //-----------------------------------------------------------------------------
  1608. void CShadowMgr::ApplyShadowToLeaf( const Shadow_t &shadow, mleaf_t* RESTRICT pLeaf, ShadowBuildInfo_t* RESTRICT pBuild )
  1609. {
  1610. // Iterate over all surfaces in the leaf, check for backfacing
  1611. // and apply the shadow to the surface if it's not backfaced.
  1612. // Note that this really only indicates that the shadow may potentially
  1613. // sit on the surface; when we render, we'll actually do the clipping
  1614. // computation and at that point we'll remove surfaces that don't
  1615. // actually hit the surface
  1616. SurfaceHandle_t *pHandle = &host_state.worldbrush->marksurfaces[pLeaf->firstmarksurface];
  1617. for ( int i = 0; i < pLeaf->nummarksurfaces; i++ )
  1618. {
  1619. SurfaceHandleRestrict_t surfID = pHandle[i];
  1620. // only process each surface once;
  1621. if( MSurf_VisFrame( surfID ) == r_surfacevisframe )
  1622. continue;
  1623. MSurf_VisFrame( surfID ) = r_surfacevisframe;
  1624. Assert( !MSurf_DispInfo( surfID ) );
  1625. // If this surface has specifically had dynamic shadows disabled on it, then get out!
  1626. if ( !MSurf_AreDynamicShadowsEnabled( surfID ) )
  1627. continue;
  1628. // Backface cull
  1629. const cplane_t * RESTRICT pSurfPlane = &MSurf_Plane( surfID );
  1630. bool bInFront;
  1631. if ( (MSurf_Flags( surfID ) & SURFDRAW_NOCULL) == 0 )
  1632. {
  1633. if ( DotProduct( pSurfPlane->normal, pBuild->m_ProjectionDirection) > -SHADOW_BACKFACE_EPSILON )
  1634. continue;
  1635. bInFront = true;
  1636. }
  1637. else
  1638. {
  1639. // Avoid edge-on shadows regardless.
  1640. float dot = DotProduct( pSurfPlane->normal, pBuild->m_ProjectionDirection );
  1641. if (fabs(dot) < SHADOW_BACKFACE_EPSILON)
  1642. continue;
  1643. bInFront = (dot < 0);
  1644. }
  1645. // Here, it's front facing...
  1646. // Discard stuff on the wrong side of the ray start
  1647. if (bInFront)
  1648. {
  1649. if ( DotProduct( pSurfPlane->normal, pBuild->m_RayStart) < pSurfPlane->dist )
  1650. continue;
  1651. }
  1652. else
  1653. {
  1654. if ( DotProduct( pSurfPlane->normal, pBuild->m_RayStart) > pSurfPlane->dist )
  1655. continue;
  1656. }
  1657. // Now apply the spherical cull
  1658. float flDist = DotProduct( pSurfPlane->normal, pBuild->m_vecSphereCenter ) - pSurfPlane->dist;
  1659. if ( fabs(flDist) >= pBuild->m_flSphereRadius )
  1660. continue;
  1661. ApplyShadowToSurface( *pBuild, surfID );
  1662. }
  1663. }
  1664. #define BIT_SET( a, b ) ((a)[(b)>>3] & (1<<((b)&7)))
  1665. //-----------------------------------------------------------------------------
  1666. // Applies a projected texture to all surfaces in the leaf
  1667. //-----------------------------------------------------------------------------
  1668. bool CShadowMgr::EnumerateLeaf( int leaf, intp context )
  1669. {
  1670. VPROF( "CShadowMgr::EnumerateLeaf" );
  1671. ShadowBuildInfo_t* pBuild = (ShadowBuildInfo_t*)context;
  1672. // Skip this leaf if it's not visible from the shadow caster
  1673. if ( pBuild->m_pVis )
  1674. {
  1675. int cluster = CM_LeafCluster( leaf );
  1676. if ( !BIT_SET( pBuild->m_pVis, cluster ) )
  1677. return true;
  1678. }
  1679. const Shadow_t &shadow = m_Shadows[pBuild->m_Shadow];
  1680. mleaf_t* pLeaf = &host_state.worldbrush->leafs[leaf];
  1681. bool bIsFlashlight;
  1682. if( shadow.m_Flags & ( SHADOW_FLASHLIGHT | SHADOW_SIMPLE_PROJECTION ) )
  1683. {
  1684. bIsFlashlight = true;
  1685. ApplyFlashlightToLeaf( shadow, pLeaf, pBuild );
  1686. }
  1687. else
  1688. {
  1689. bIsFlashlight = false;
  1690. ApplyShadowToLeaf( shadow, pLeaf, pBuild );
  1691. }
  1692. // Add the decal to each displacement in the leaf it touches.
  1693. for ( int i = 0; i < pLeaf->dispCount; i++ )
  1694. {
  1695. IDispInfo *pDispInfo = MLeaf_Disaplcement( pLeaf, i );
  1696. // Make sure the decal hasn't already been added to it.
  1697. if( pDispInfo->GetTag() )
  1698. continue;
  1699. pDispInfo->SetTag();
  1700. ApplyShadowToDisplacement( *pBuild, pDispInfo, bIsFlashlight );
  1701. }
  1702. return true;
  1703. }
  1704. //-----------------------------------------------------------------------------
  1705. // Adds a shadow to a brush model
  1706. //-----------------------------------------------------------------------------
  1707. void CShadowMgr::AddShadowToBrushModel( ShadowHandle_t handle, model_t* pModel,
  1708. const Vector& origin, const QAngle& angles )
  1709. {
  1710. // Don't compute the surface cache if shadows are off..
  1711. if ( !r_shadows.GetInt() )
  1712. return;
  1713. const Shadow_t * RESTRICT pShadow = &m_Shadows[handle];
  1714. // Transform the shadow ray direction into model space
  1715. Vector shadowDirInModelSpace;
  1716. bool bIsFlashlight = ( pShadow->m_Flags & ( SHADOW_FLASHLIGHT | SHADOW_SIMPLE_PROJECTION ) ) != 0;
  1717. if( !bIsFlashlight )
  1718. {
  1719. // FLASHLIGHTFIXME: should do backface culling for projective light sources.
  1720. matrix3x4_t worldToModel;
  1721. AngleIMatrix( angles, worldToModel );
  1722. VectorRotate( pShadow->m_ProjectionDir, worldToModel, shadowDirInModelSpace );
  1723. }
  1724. // Just add all non-backfacing brush surfaces to the list of potential
  1725. // surfaces that we may be casting a shadow onto.
  1726. SurfaceHandleRestrict_t surfID = SurfaceHandleFromIndex( pModel->brush.firstmodelsurface, pModel->brush.pShared );
  1727. for (int i=0; i<pModel->brush.nummodelsurfaces; ++i, ++surfID)
  1728. {
  1729. // Don't bother with nodraw surfaces
  1730. int nFlags = MSurf_Flags( surfID );
  1731. if ( nFlags & SURFDRAW_NODRAW )
  1732. continue;
  1733. if( !bIsFlashlight )
  1734. {
  1735. // FLASHLIGHTFIXME: should do backface culling for projective light sources.
  1736. // Don't bother with backfacing surfaces
  1737. if ( (nFlags & SURFDRAW_NOCULL) == 0 )
  1738. {
  1739. const cplane_t * RESTRICT pSurfPlane = &MSurf_Plane( surfID );
  1740. float dot = DotProduct( shadowDirInModelSpace, pSurfPlane->normal );
  1741. if ( dot > 0 )
  1742. continue;
  1743. }
  1744. }
  1745. // FIXME: We may want to do some more high-level per-surface culling
  1746. // If so, it'll be added to ApplyShadowToSurface. Call it instead.
  1747. AddSurfaceToShadow( handle, surfID );
  1748. }
  1749. }
  1750. //-----------------------------------------------------------------------------
  1751. // Removes all shadows from a brush model
  1752. //-----------------------------------------------------------------------------
  1753. void CShadowMgr::RemoveAllShadowsFromBrushModel( model_t* pModel )
  1754. {
  1755. SurfaceHandle_t surfID = SurfaceHandleFromIndex( pModel->brush.firstmodelsurface, pModel->brush.pShared );
  1756. for (int i=0; i<pModel->brush.nummodelsurfaces; ++i, ++surfID)
  1757. {
  1758. RemoveAllShadowsFromSurface( surfID );
  1759. }
  1760. }
  1761. //-----------------------------------------------------------------------------
  1762. // Adds the shadow decals on the surface to a queue of things to render
  1763. //-----------------------------------------------------------------------------
  1764. void CShadowMgr::AddShadowsOnSurfaceToRenderList( ShadowDecalHandle_t decalHandle )
  1765. {
  1766. // Don't compute the surface cache if shadows are off..
  1767. if ( !r_shadows.GetInt() )
  1768. return;
  1769. // Add all surface decals into the appropriate render lists
  1770. while ( decalHandle != m_ShadowDecals.InvalidIndex() )
  1771. {
  1772. ShadowDecal_t& shadowDecal = m_ShadowDecals[decalHandle];
  1773. if ( m_Shadows[shadowDecal.m_Shadow].m_Flags & ( SHADOW_FLASHLIGHT | SHADOW_SIMPLE_PROJECTION ) )
  1774. {
  1775. AddSurfaceToFlashlightMaterialBuckets( shadowDecal.m_Shadow, shadowDecal.m_SurfID );
  1776. // We've got one more decal to render
  1777. ++m_DecalsToRender;
  1778. }
  1779. else if ( ( r_shadows_gamecontrol.GetInt() != 0 ) &&
  1780. ( m_nSkipShadowForEntIndex != m_Shadows[shadowDecal.m_Shadow].m_nEntIndex ) )
  1781. {
  1782. // For shadow rendering, hook the decal into the render list based on the shadow material, not the surface material.
  1783. int sortOrder = m_Shadows[shadowDecal.m_Shadow].m_SortOrder;
  1784. m_ShadowDecals[decalHandle].m_NextRender = m_RenderQueue[sortOrder];
  1785. m_RenderQueue[sortOrder] = decalHandle;
  1786. // We've got one more decal to render
  1787. ++m_DecalsToRender;
  1788. }
  1789. decalHandle = m_ShadowDecals.Next(decalHandle);
  1790. }
  1791. }
  1792. void CShadowMgr::ClearShadowRenderList()
  1793. {
  1794. COMPILE_TIME_ASSERT( sizeof(ShadowDecalHandle_t) == 2 );
  1795. // Clear out the render list
  1796. if (m_RenderQueue.Count() > 0)
  1797. {
  1798. memset( m_RenderQueue.Base(), 0xFF, m_RenderQueue.Count() * sizeof(ShadowDecalHandle_t) );
  1799. }
  1800. m_DecalsToRender = 0;
  1801. // Clear all lists pertaining to flashlight decals that need to be rendered.
  1802. ClearAllFlashlightMaterialBuckets();
  1803. }
  1804. void CShadowMgr::RenderShadows( IMatRenderContext *pRenderContext, const VMatrix* pModelToWorld )
  1805. {
  1806. VPROF_BUDGET( "CShadowMgr::RenderShadows", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  1807. // Iterate through all sort ids and render for regular shadows, which get their materials from the shadow material.
  1808. #if PIX_ENABLE
  1809. bool bFound = false;
  1810. #endif
  1811. for ( int i = 0; i < m_RenderQueue.Count(); i++ )
  1812. {
  1813. if ( m_RenderQueue[i] != m_ShadowDecals.InvalidIndex() )
  1814. {
  1815. #if PIX_ENABLE
  1816. if ( !bFound )
  1817. {
  1818. bFound = true;
  1819. pRenderContext->BeginPIXEvent( PIX_VALVE_ORANGE, "DECAL_SHADOWS" );
  1820. }
  1821. #endif
  1822. RenderShadowList( pRenderContext, m_RenderQueue[i], pModelToWorld );
  1823. }
  1824. }
  1825. #if PIX_ENABLE
  1826. if ( bFound )
  1827. {
  1828. pRenderContext->EndPIXEvent();
  1829. }
  1830. #endif
  1831. }
  1832. void CShadowMgr::RenderProjectedTextures( IMatRenderContext *pRenderContext, const VMatrix* pModelToWorld )
  1833. {
  1834. VPROF_BUDGET( "CShadowMgr::RenderProjectedTextures", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  1835. RenderFlashlights( true, false, pModelToWorld );
  1836. RenderShadows( pRenderContext, pModelToWorld );
  1837. // Clear out the render list, we've rendered it now
  1838. ClearShadowRenderList();
  1839. }
  1840. //-----------------------------------------------------------------------------
  1841. // A 2D sutherland-hodgman clipper
  1842. //-----------------------------------------------------------------------------
  1843. class CClipTop
  1844. {
  1845. public:
  1846. static inline bool Inside( ShadowVertex_t const& vert ) { return vert.m_ShadowSpaceTexCoord.y < 1;}
  1847. static inline float Clip( const Vector& one, const Vector& two ) { return (1 - one.y) / (two.y - one.y);}
  1848. static inline bool IsPlane() {return false;}
  1849. static inline bool IsAbove() {return false;}
  1850. };
  1851. class CClipLeft
  1852. {
  1853. public:
  1854. static inline bool Inside( ShadowVertex_t const& vert ) { return vert.m_ShadowSpaceTexCoord.x > 0;}
  1855. static inline float Clip( const Vector& one, const Vector& two ) { return one.x / (one.x - two.x);}
  1856. static inline bool IsPlane() {return false;}
  1857. static inline bool IsAbove() {return false;}
  1858. };
  1859. class CClipRight
  1860. {
  1861. public:
  1862. static inline bool Inside( ShadowVertex_t const& vert ) {return vert.m_ShadowSpaceTexCoord.x < 1;}
  1863. static inline float Clip( const Vector& one, const Vector& two ) {return (1 - one.x) / (two.x - one.x);}
  1864. static inline bool IsPlane() {return false;}
  1865. static inline bool IsAbove() {return false;}
  1866. };
  1867. class CClipBottom
  1868. {
  1869. public:
  1870. static inline bool Inside( ShadowVertex_t const& vert ) {return vert.m_ShadowSpaceTexCoord.y > 0;}
  1871. static inline float Clip( const Vector& one, const Vector& two ) {return one.y / (one.y - two.y);}
  1872. static inline bool IsPlane() {return false;}
  1873. static inline bool IsAbove() {return false;}
  1874. };
  1875. class CClipAbove
  1876. {
  1877. public:
  1878. static inline bool Inside( ShadowVertex_t const& vert ) {return vert.m_ShadowSpaceTexCoord.z > 0;}
  1879. static inline float Clip( const Vector& one, const Vector& two ) {return one.z / (one.z - two.z);}
  1880. static inline bool IsPlane() {return false;}
  1881. static inline bool IsAbove() {return true;}
  1882. };
  1883. class CClipPlane
  1884. {
  1885. public:
  1886. inline bool Inside( ShadowVertex_t const& vert )
  1887. {
  1888. return DotProduct( vert.m_Position, *m_pNormal ) < m_Dist;
  1889. }
  1890. inline float Clip( const Vector& one, const Vector& two )
  1891. {
  1892. Vector dir;
  1893. VectorSubtract( two, one, dir );
  1894. return IntersectRayWithPlane( one, dir, *m_pNormal, m_Dist );
  1895. }
  1896. static inline bool IsAbove() {return false;}
  1897. static inline bool IsPlane() {return true;}
  1898. void SetPlane( const Vector& normal, float dist )
  1899. {
  1900. m_pNormal = &normal;
  1901. m_Dist = dist;
  1902. }
  1903. private:
  1904. const Vector *m_pNormal;
  1905. float m_Dist;
  1906. };
  1907. static inline void ClampTexCoord( ShadowVertex_t *pInVertex, ShadowVertex_t *pOutVertex )
  1908. {
  1909. if ( fabs(pInVertex->m_ShadowSpaceTexCoord[0]) < 1e-3 )
  1910. pOutVertex->m_ShadowSpaceTexCoord[0] = 0.0f;
  1911. else if ( fabs(pInVertex->m_ShadowSpaceTexCoord[0] - 1.0f) < 1e-3 )
  1912. pOutVertex->m_ShadowSpaceTexCoord[0] = 1.0f;
  1913. if ( fabs(pInVertex->m_ShadowSpaceTexCoord[1]) < 1e-3 )
  1914. pOutVertex->m_ShadowSpaceTexCoord[1] = 0.0f;
  1915. else if ( fabs(pInVertex->m_ShadowSpaceTexCoord[1] - 1.0f) < 1e-3 )
  1916. pOutVertex->m_ShadowSpaceTexCoord[1] = 1.0f;
  1917. }
  1918. template <class Clipper>
  1919. static inline void Intersect( ShadowVertex_t* pStart, ShadowVertex_t* pEnd, ShadowVertex_t* pOut, bool startInside, Clipper& clipper )
  1920. {
  1921. // Clip the edge to the clip plane
  1922. float t;
  1923. if (!Clipper::IsPlane())
  1924. {
  1925. if (!Clipper::IsAbove())
  1926. {
  1927. // This is the path the we always take for perspective light volumes.
  1928. t = clipper.Clip( pStart->m_ShadowSpaceTexCoord, pEnd->m_ShadowSpaceTexCoord );
  1929. VectorLerp( pStart->m_ShadowSpaceTexCoord, pEnd->m_ShadowSpaceTexCoord, t, pOut->m_ShadowSpaceTexCoord );
  1930. }
  1931. else
  1932. {
  1933. t = clipper.Clip( pStart->m_ShadowSpaceTexCoord, pEnd->m_ShadowSpaceTexCoord );
  1934. VectorLerp( pStart->m_ShadowSpaceTexCoord, pEnd->m_ShadowSpaceTexCoord, t, pOut->m_ShadowSpaceTexCoord );
  1935. // This is a special thing we do here to avoid hard-edged shadows
  1936. if (startInside)
  1937. ClampTexCoord( pEnd, pOut );
  1938. else
  1939. ClampTexCoord( pStart, pOut );
  1940. }
  1941. }
  1942. else
  1943. {
  1944. t = clipper.Clip( pStart->m_Position, pEnd->m_Position );
  1945. VectorLerp( pStart->m_ShadowSpaceTexCoord, pEnd->m_ShadowSpaceTexCoord, t, pOut->m_ShadowSpaceTexCoord );
  1946. }
  1947. VectorLerp( pStart->m_Position, pEnd->m_Position, t, pOut->m_Position );
  1948. }
  1949. template <class Clipper>
  1950. static void ShadowClip( ShadowClipState_t& clip, Clipper& clipper )
  1951. {
  1952. if ( clip.m_ClipCount == 0 )
  1953. return;
  1954. // Ye Olde Sutherland-Hodgman clipping algorithm
  1955. int numOutVerts = 0;
  1956. ShadowVertex_t** pSrcVert = (ShadowVertex_t **)clip.m_ppClipVertices[clip.m_CurrVert];
  1957. ShadowVertex_t** pDestVert = (ShadowVertex_t **)clip.m_ppClipVertices[!clip.m_CurrVert];
  1958. int numVerts = clip.m_ClipCount;
  1959. ShadowVertex_t* pStart = pSrcVert[numVerts-1];
  1960. bool startInside = clipper.Inside( *pStart );
  1961. for (int i = 0; i < numVerts; ++i)
  1962. {
  1963. ShadowVertex_t* pEnd = pSrcVert[i];
  1964. bool endInside = clipper.Inside( *pEnd );
  1965. if (endInside)
  1966. {
  1967. if (!startInside)
  1968. {
  1969. // Started outside, ended inside, need to clip the edge
  1970. if ( clip.m_TempCount >= SHADOW_VERTEX_TEMP_COUNT )
  1971. return;
  1972. // Allocate a new clipped vertex
  1973. pDestVert[numOutVerts] = &clip.m_pTempVertices[clip.m_TempCount++];
  1974. // Clip the edge to the clip plane
  1975. Intersect( pStart, pEnd, pDestVert[numOutVerts], startInside, clipper );
  1976. ++numOutVerts;
  1977. }
  1978. pDestVert[numOutVerts++] = pEnd;
  1979. }
  1980. else
  1981. {
  1982. if (startInside)
  1983. {
  1984. // Started inside, ended outside, need to clip the edge
  1985. if ( clip.m_TempCount >= SHADOW_VERTEX_TEMP_COUNT )
  1986. return;
  1987. // Allocate a new clipped vertex
  1988. pDestVert[numOutVerts] = &clip.m_pTempVertices[clip.m_TempCount++];
  1989. // Clip the edge to the clip plane
  1990. Intersect( pStart, pEnd, pDestVert[numOutVerts], startInside, clipper );
  1991. ++numOutVerts;
  1992. }
  1993. }
  1994. pStart = pEnd;
  1995. startInside = endInside;
  1996. }
  1997. // Switch source lists
  1998. clip.m_CurrVert = 1 - clip.m_CurrVert;
  1999. clip.m_ClipCount = numOutVerts;
  2000. Assert( clip.m_ClipCount <= SHADOW_VERTEX_TEMP_COUNT );
  2001. }
  2002. //-----------------------------------------------------------------------------
  2003. // Project vertices into shadow space
  2004. //-----------------------------------------------------------------------------
  2005. // a version of this function where I promise that src1, dst, and src2 are all different
  2006. FORCEINLINE void Vector3DMultiplyPositionNoAlias( const VMatrix * RESTRICT src1,
  2007. const Vector * RESTRICT src2,
  2008. Vector * RESTRICT dst )
  2009. {
  2010. (*dst)[0] = (*src1)[0][0] * (*src2).x + (*src1)[0][1] * (*src2).y + (*src1)[0][2] * (*src2).z + (*src1)[0][3];
  2011. (*dst)[1] = (*src1)[1][0] * (*src2).x + (*src1)[1][1] * (*src2).y + (*src1)[1][2] * (*src2).z + (*src1)[1][3];
  2012. (*dst)[2] = (*src1)[2][0] * (*src2).x + (*src1)[2][1] * (*src2).y + (*src1)[2][2] * (*src2).z + (*src1)[2][3];
  2013. }
  2014. bool CShadowMgr::ProjectVerticesIntoShadowSpace( const VMatrix * RESTRICT modelToShadow,
  2015. float maxDist, int count, Vector** RESTRICT ppPosition, ShadowClipState_t& clip )
  2016. {
  2017. bool insideVolume = false;
  2018. // init to frustum box
  2019. Vector mins( 1.0f, 1.0f, maxDist );
  2020. Vector maxs( 0.0f, 0.0f, 0.0f );
  2021. // Create vertices to clip to...
  2022. for (int i = 0; i < count; ++i )
  2023. {
  2024. Assert( ppPosition[i] );
  2025. Vector * RESTRICT pPos = ppPosition[i];
  2026. VectorCopy( *pPos, clip.m_pTempVertices[i].m_Position );
  2027. // Project the points into shadow texture space
  2028. Vector * RESTRICT pShadowSpacePos = &clip.m_pTempVertices[i].m_ShadowSpaceTexCoord;
  2029. Vector3DMultiplyPositionNoAlias( modelToShadow, pPos, pShadowSpacePos );
  2030. // Update AABB for polygon
  2031. #ifdef _X360
  2032. // This should be a little better for the 360 than VectorMin()/Max()
  2033. mins.x = fsel( pShadowSpacePos->x - mins.x, mins.x, pShadowSpacePos->x );
  2034. mins.y = fsel( pShadowSpacePos->y - mins.y, mins.x, pShadowSpacePos->y );
  2035. mins.z = fsel( pShadowSpacePos->z - mins.z, mins.x, pShadowSpacePos->z );
  2036. maxs.x = fsel( pShadowSpacePos->x - maxs.x, pShadowSpacePos->x, maxs.x );
  2037. maxs.y = fsel( pShadowSpacePos->y - maxs.y, pShadowSpacePos->y, maxs.y );
  2038. maxs.z = fsel( pShadowSpacePos->z - maxs.z, pShadowSpacePos->z, maxs.z );
  2039. #else
  2040. VectorMin( mins, *pShadowSpacePos, mins );
  2041. VectorMax( maxs, *pShadowSpacePos, maxs );
  2042. #endif
  2043. // Set up clipping coords...
  2044. clip.m_ppClipVertices[0][i] = &clip.m_pTempVertices[i];
  2045. }
  2046. // early out if AABB doesn't intersect frustum box
  2047. insideVolume = !( ( mins.x >= 1.0f ) || ( maxs.x <= 0.0f ) || ( mins.y >= 1.0f ) ||
  2048. ( maxs.y <= 0.0f ) || ( mins.z >= maxDist ) || ( maxs.z <= 0.0f ) );
  2049. clip.m_TempCount = clip.m_ClipCount = count;
  2050. clip.m_CurrVert = 0;
  2051. return insideVolume;
  2052. }
  2053. //-----------------------------------------------------------------------------
  2054. // Projects + clips shadows
  2055. //-----------------------------------------------------------------------------
  2056. int CShadowMgr::ProjectAndClipVertices( const Shadow_t& shadow, const VMatrix& worldToShadow,
  2057. const VMatrix *pWorldToModel, int count, Vector** ppPosition, ShadowVertex_t*** ppOutVertex, ShadowClipState_t& clip )
  2058. {
  2059. VPROF( "ProjectAndClipVertices" );
  2060. if ( !ProjectVerticesIntoShadowSpace( &worldToShadow, shadow.m_MaxDist, count, ppPosition, clip ) )
  2061. return 0;
  2062. // Clippers...
  2063. CClipTop top;
  2064. CClipBottom bottom;
  2065. CClipLeft left;
  2066. CClipRight right;
  2067. CClipAbove above;
  2068. CClipPlane plane;
  2069. // Sutherland-hodgman clip
  2070. ShadowClip( clip, top );
  2071. ShadowClip( clip, bottom );
  2072. ShadowClip( clip, left );
  2073. ShadowClip( clip, right );
  2074. if ( shadow.m_ClipPlaneCount == 0 )
  2075. {
  2076. // only clip above if we don't have any extra clip planes that prevent back-casting
  2077. ShadowClip( clip, above );
  2078. }
  2079. // Planes to suppress back-casting
  2080. for (int i = 0; i < shadow.m_ClipPlaneCount; ++i)
  2081. {
  2082. if ( pWorldToModel )
  2083. {
  2084. cplane_t worldPlane, modelPlane;
  2085. worldPlane.normal = shadow.m_ClipPlane[i];
  2086. worldPlane.dist = shadow.m_ClipDist[i];
  2087. MatrixTransformPlane( *pWorldToModel, worldPlane, modelPlane );
  2088. plane.SetPlane( modelPlane.normal, modelPlane.dist );
  2089. }
  2090. else
  2091. {
  2092. plane.SetPlane( shadow.m_ClipPlane[i], shadow.m_ClipDist[i] );
  2093. }
  2094. ShadowClip( clip, plane );
  2095. }
  2096. if (clip.m_ClipCount < 3)
  2097. return 0;
  2098. // Return a pointer to the array of clipped vertices...
  2099. Assert(ppOutVertex);
  2100. *ppOutVertex = (ShadowVertex_t **)clip.m_ppClipVertices[clip.m_CurrVert];
  2101. return clip.m_ClipCount;
  2102. }
  2103. //-----------------------------------------------------------------------------
  2104. // Accessor for use by the displacements
  2105. //-----------------------------------------------------------------------------
  2106. int CShadowMgr::ProjectAndClipVertices( ShadowHandle_t handle, int count,
  2107. Vector** ppPosition, ShadowVertex_t*** ppOutVertex )
  2108. {
  2109. static ShadowClipState_t clip;
  2110. return ProjectAndClipVertices( m_Shadows[handle],
  2111. m_Shadows[handle].m_WorldToShadow, NULL, count, ppPosition, ppOutVertex, clip );
  2112. }
  2113. //-----------------------------------------------------------------------------
  2114. // Thread-safe version
  2115. //-----------------------------------------------------------------------------
  2116. int CShadowMgr::ProjectAndClipVerticesEx( ShadowHandle_t handle, int count,
  2117. Vector** ppPosition, ShadowVertex_t*** ppOutVertex, ShadowClipState_t& clip )
  2118. {
  2119. return ProjectAndClipVertices( m_Shadows[handle],
  2120. m_Shadows[handle].m_WorldToShadow, NULL, count, ppPosition, ppOutVertex, clip );
  2121. }
  2122. //-----------------------------------------------------------------------------
  2123. // Copies vertex info from the clipped vertices
  2124. //-----------------------------------------------------------------------------
  2125. // This version treats texcoords as Vector
  2126. inline void CShadowMgr::CopyClippedVertices( int count, ShadowVertex_t** ppSrcVert, ShadowVertex_t* pDstVert, const Vector &vToAdd )
  2127. {
  2128. for (int i = 0; i < count; ++i)
  2129. {
  2130. pDstVert[i].m_Position = ppSrcVert[i]->m_Position + vToAdd;
  2131. pDstVert[i].m_ShadowSpaceTexCoord = ppSrcVert[i]->m_ShadowSpaceTexCoord;
  2132. // Make sure it's been clipped
  2133. Assert( ppSrcVert[i]->m_ShadowSpaceTexCoord[0] >= -1e-3f );
  2134. Assert( ppSrcVert[i]->m_ShadowSpaceTexCoord[0] - 1.0f <= 1e-3f );
  2135. Assert( ppSrcVert[i]->m_ShadowSpaceTexCoord[1] >= -1e-3f );
  2136. Assert( ppSrcVert[i]->m_ShadowSpaceTexCoord[1] - 1.0f <= 1e-3f );
  2137. }
  2138. }
  2139. //-----------------------------------------------------------------------------
  2140. // Does the actual work of computing shadow vertices
  2141. //-----------------------------------------------------------------------------
  2142. bool CShadowMgr::ComputeShadowVertices( ShadowDecal_t& decal,
  2143. const VMatrix* pModelToWorld, const VMatrix *pWorldToModel, ShadowVertexCache_t* pVertexCache )
  2144. {
  2145. VPROF( "CShadowMgr::ComputeShadowVertices" );
  2146. // Prepare for the clipping
  2147. Vector **ppVec = (Vector**)stackalloc( MSurf_VertCount( decal.m_SurfID ) * sizeof(Vector*) );
  2148. for (int i = 0; i < MSurf_VertCount( decal.m_SurfID ); ++i )
  2149. {
  2150. int vertIndex = host_state.worldbrush->vertindices[MSurf_FirstVertIndex( decal.m_SurfID )+i];
  2151. ppVec[i] = &host_state.worldbrush->vertexes[vertIndex].position;
  2152. }
  2153. // Compute the modelToShadow transform.
  2154. // In the case of the world, just use worldToShadow...
  2155. VMatrix* pModelToShadow = &m_Shadows[decal.m_Shadow].m_WorldToShadow;
  2156. VMatrix temp;
  2157. if ( pModelToWorld )
  2158. {
  2159. MatrixMultiply( *pModelToShadow, *pModelToWorld, temp );
  2160. pModelToShadow = &temp;
  2161. }
  2162. else
  2163. {
  2164. pWorldToModel = NULL;
  2165. }
  2166. // Create vertices to clip to...
  2167. ShadowVertex_t** ppSrcVert;
  2168. ShadowClipState_t clip;
  2169. int clipCount = ProjectAndClipVertices( m_Shadows[decal.m_Shadow], *pModelToShadow, pWorldToModel,
  2170. MSurf_VertCount( decal.m_SurfID ), ppVec, &ppSrcVert, clip );
  2171. if (clipCount == 0)
  2172. {
  2173. pVertexCache->m_Count = 0;
  2174. return false;
  2175. }
  2176. // Allocate the vertices we're going to use for the decal
  2177. ShadowVertex_t* pDstVert = AllocateVertices( *pVertexCache, clipCount );
  2178. Assert( pDstVert );
  2179. // Copy the clipped vertices into the cache
  2180. const Vector &vNormal = MSurf_Plane( decal.m_SurfID ).normal;
  2181. CopyClippedVertices( clipCount, ppSrcVert, pDstVert, vNormal * OVERLAY_AVOID_FLICKER_NORMAL_OFFSET );
  2182. // Indicate which shadow this is related to
  2183. pVertexCache->m_Shadow = decal.m_Shadow;
  2184. return true;
  2185. }
  2186. //-----------------------------------------------------------------------------
  2187. // Should we cache vertices?
  2188. //-----------------------------------------------------------------------------
  2189. inline bool CShadowMgr::ShouldCacheVertices( const ShadowDecal_t& decal )
  2190. {
  2191. return (m_Shadows[decal.m_Shadow].m_Flags & SHADOW_CACHE_VERTS) != 0;
  2192. }
  2193. //-----------------------------------------------------------------------------
  2194. // Generates a list displacement shadow vertices to render
  2195. //-----------------------------------------------------------------------------
  2196. inline bool CShadowMgr::GenerateDispShadowRenderInfo( ShadowDecal_t& decal, ShadowRenderInfo_t& info )
  2197. {
  2198. //=============================================================================
  2199. // HPE_BEGIN:
  2200. // [smessick] Added an overflow condition for the max disp decal cache.
  2201. //=============================================================================
  2202. if ( info.m_DispCount >= MAX_SHADOW_DECAL_CACHE_COUNT )
  2203. {
  2204. info.m_DispCount = MAX_SHADOW_DECAL_CACHE_COUNT;
  2205. return true;
  2206. }
  2207. //=============================================================================
  2208. // HPE_END
  2209. //=============================================================================
  2210. int v, i;
  2211. if ( !MSurf_DispInfo( decal.m_SurfID )->ComputeShadowFragments( decal.m_DispShadow, v, i ) )
  2212. return false;
  2213. // Catch overflows....
  2214. if ( ( info.m_VertexCount + v >= info.m_nMaxVertices ) || ( info.m_IndexCount + i >= info.m_nMaxIndices ) )
  2215. return true;
  2216. info.m_VertexCount += v;
  2217. info.m_IndexCount += i;
  2218. info.m_pDispCache[info.m_DispCount++] = decal.m_DispShadow;
  2219. return true;
  2220. }
  2221. //-----------------------------------------------------------------------------
  2222. // Generates a list shadow vertices to render
  2223. //-----------------------------------------------------------------------------
  2224. inline bool CShadowMgr::GenerateNormalShadowRenderInfo( IMatRenderContext *pRenderContext, ShadowDecal_t& decal, ShadowRenderInfo_t& info )
  2225. {
  2226. //=============================================================================
  2227. // HPE_BEGIN:
  2228. // [smessick] Check for cache overflow.
  2229. //=============================================================================
  2230. if ( info.m_Count >= MAX_SHADOW_DECAL_CACHE_COUNT )
  2231. {
  2232. info.m_Count = MAX_SHADOW_DECAL_CACHE_COUNT;
  2233. return true;
  2234. }
  2235. //=============================================================================
  2236. // HPE_END
  2237. //=============================================================================
  2238. // Look for a cache hit
  2239. ShadowVertexCache_t* pVertexCache;
  2240. if (decal.m_ShadowVerts != m_VertexCache.InvalidIndex())
  2241. {
  2242. // Ok, we've already computed the data, lets use it
  2243. info.m_pCache[info.m_Count] = decal.m_ShadowVerts;
  2244. pVertexCache = &m_VertexCache[decal.m_ShadowVerts];
  2245. }
  2246. else
  2247. {
  2248. // Attempt to cull the surface
  2249. bool bIsNear = IsShadowNearSurface( decal.m_Shadow, decal.m_SurfID, info.m_pModelToWorld, &info.m_WorldToModel );
  2250. if ( !bIsNear )
  2251. return false;
  2252. // In this case, we gotta recompute the shadow decal vertices
  2253. // and maybe even store it into the cache....
  2254. bool shouldCacheVerts = ShouldCacheVertices( decal );
  2255. if (shouldCacheVerts)
  2256. {
  2257. GrowSpew( m_VertexCache.NumAllocated(), m_VertexCacheMax, "m_VertexCache" );
  2258. decal.m_ShadowVerts = m_VertexCache.AddToTail();
  2259. info.m_pCache[info.m_Count] = decal.m_ShadowVerts;
  2260. pVertexCache = &m_VertexCache[decal.m_ShadowVerts];
  2261. }
  2262. else
  2263. {
  2264. GrowSpew( m_TempVertexCache.NumAllocated(), m_TempVertexCacheMax, "m_TempVertexCache" );
  2265. int i = m_TempVertexCache.AddToTail();
  2266. info.m_pCache[info.m_Count] = -i-1;
  2267. pVertexCache = &m_TempVertexCache[i];
  2268. Assert( info.m_pCache[info.m_Count] < 0 );
  2269. }
  2270. // Compute the shadow vertices
  2271. // If no vertices were created, indicate this surface should be removed from the cache
  2272. if ( !ComputeShadowVertices( decal, info.m_pModelToWorld, &info.m_WorldToModel, pVertexCache ) )
  2273. return false;
  2274. }
  2275. // Catch overflows....
  2276. int nAdditionalIndices = 3 * (pVertexCache->m_Count - 2);
  2277. if ( ( info.m_VertexCount + pVertexCache->m_Count >= info.m_nMaxVertices ) ||
  2278. ( info.m_IndexCount + nAdditionalIndices >= info.m_nMaxIndices ) )
  2279. {
  2280. return true;
  2281. }
  2282. // Update vertex, index, and decal counts
  2283. info.m_VertexCount += pVertexCache->m_Count;
  2284. info.m_IndexCount += nAdditionalIndices;
  2285. ++info.m_Count;
  2286. return true;
  2287. }
  2288. //-----------------------------------------------------------------------------
  2289. // Generates a list shadow vertices to render
  2290. //-----------------------------------------------------------------------------
  2291. void CShadowMgr::GenerateShadowRenderInfo( IMatRenderContext *pRenderContext, ShadowDecalHandle_t decalHandle, ShadowRenderInfo_t& info )
  2292. {
  2293. VPROF_BUDGET( __FUNCTION__, VPROF_BUDGETGROUP_SHADOW_RENDERING );
  2294. info.m_VertexCount = 0;
  2295. info.m_IndexCount = 0;
  2296. info.m_Count = 0;
  2297. info.m_DispCount = 0;
  2298. // Keep the lists only full of valid decals; that way we can preserve
  2299. // the render lists in the case that we discover a shadow isn't needed.
  2300. ShadowDecalHandle_t next;
  2301. for ( ; decalHandle != m_ShadowDecals.InvalidIndex(); decalHandle = next )
  2302. {
  2303. ShadowDecal_t& decal = m_ShadowDecals[decalHandle];
  2304. next = m_ShadowDecals[decalHandle].m_NextRender;
  2305. // Skip translucent shadows [ don't add their verts + indices to the render lists ]
  2306. Shadow_t &shadow = m_Shadows[ decal.m_Shadow ];
  2307. if ( shadow.m_FalloffBias == 255 )
  2308. continue;
  2309. bool keepShadow = true;
  2310. if ( decal.m_DispShadow != DISP_SHADOW_HANDLE_INVALID )
  2311. {
  2312. // Handle shadows on displacements...
  2313. keepShadow = GenerateDispShadowRenderInfo( decal, info );
  2314. }
  2315. else
  2316. {
  2317. // Handle shadows on normal surfaces
  2318. keepShadow = GenerateNormalShadowRenderInfo( pRenderContext, decal, info );
  2319. }
  2320. // Retire the surface if the shadow didn't actually hit it
  2321. if ( !keepShadow && ShouldCacheVertices( decal ) )
  2322. {
  2323. // If no triangles were generated
  2324. // (the decal was completely clipped off)
  2325. // In this case, remove the decal from the surface cache
  2326. // so next time it'll be faster (for cached decals)
  2327. RemoveShadowDecalFromSurface( decal.m_SurfID, decalHandle );
  2328. }
  2329. }
  2330. }
  2331. void CShadowMgr::GenerateShadowRenderInfoThreaded( IMatRenderContext *pRenderContext, ShadowDecalHandle_t decalHandle, ShadowRenderInfo_t& info )
  2332. {
  2333. info.m_VertexCount = 0;
  2334. info.m_IndexCount = 0;
  2335. info.m_Count = 0;
  2336. info.m_DispCount = 0;
  2337. DispDecalWorkItem_t* pDispDecalWorkItems = static_cast<DispDecalWorkItem_t*>( stackalloc( m_DecalsToRender * sizeof( DispDecalWorkItem_t ) ) );
  2338. int nNumDispDecals = 0;
  2339. // Keep the lists only full of valid decals; that way we can preserve
  2340. // the render lists in the case that we discover a shadow isn't needed.
  2341. ShadowDecalHandle_t next;
  2342. for ( ; decalHandle != m_ShadowDecals.InvalidIndex(); decalHandle = next )
  2343. {
  2344. ShadowDecal_t& decal = m_ShadowDecals[decalHandle];
  2345. next = m_ShadowDecals[decalHandle].m_NextRender;
  2346. // Skip translucent shadows [ don't add their verts + indices to the render lists ]
  2347. Shadow_t &shadow = m_Shadows[ decal.m_Shadow ];
  2348. if ( shadow.m_FalloffBias == 255 )
  2349. continue;
  2350. bool keepShadow = false;
  2351. if ( decal.m_DispShadow != DISP_SHADOW_HANDLE_INVALID )
  2352. {
  2353. pDispDecalWorkItems[nNumDispDecals].h = decalHandle;
  2354. nNumDispDecals++;
  2355. continue;
  2356. }
  2357. else
  2358. {
  2359. // Handle shadows on normal surfaces
  2360. keepShadow = GenerateNormalShadowRenderInfo( pRenderContext, decal, info );
  2361. }
  2362. // Retire the surface if the shadow didn't actually hit it
  2363. if ( !keepShadow && ShouldCacheVertices( decal ) )
  2364. {
  2365. // If no triangles were generated
  2366. // (the decal was completely clipped off)
  2367. // In this case, remove the decal from the surface cache
  2368. // so next time it'll be faster (for cached decals)
  2369. RemoveShadowDecalFromSurface( decal.m_SurfID, decalHandle );
  2370. }
  2371. }
  2372. // threaded displacement decal processing
  2373. ParallelProcess( pDispDecalWorkItems, nNumDispDecals, this, &CShadowMgr::ProcessDispDecalWorkItem );
  2374. // now go through list of results and do the additional processing from GenereateDispShadowRenderInfo
  2375. for ( int i = 0; i < nNumDispDecals; i++ )
  2376. {
  2377. DispDecalWorkItem_t& wi = pDispDecalWorkItems[i];
  2378. //ProcessDispDecalWorkItem( wi );
  2379. ShadowDecal_t& decal = m_ShadowDecals[ wi.h ];
  2380. if ( pDispDecalWorkItems[i].bKeepShadow )
  2381. {
  2382. // Catch overflows....
  2383. if ( ( info.m_VertexCount + wi.vertCount >= info.m_nMaxVertices ) || ( info.m_IndexCount + wi.indexCount >= info.m_nMaxIndices ) )
  2384. continue;
  2385. info.m_VertexCount += wi.vertCount;
  2386. info.m_IndexCount += wi.indexCount;
  2387. info.m_pDispCache[info.m_DispCount++] = decal.m_DispShadow;
  2388. }
  2389. else
  2390. {
  2391. if ( ShouldCacheVertices( decal ) )
  2392. {
  2393. RemoveShadowDecalFromSurface( decal.m_SurfID, wi.h );
  2394. }
  2395. }
  2396. }
  2397. }
  2398. void CShadowMgr::ProcessDispDecalWorkItem( DispDecalWorkItem_t& wi )
  2399. {
  2400. // Handle shadows on displacements...
  2401. ShadowDecal_t& decal = m_ShadowDecals[wi.h];
  2402. wi.bKeepShadow = MSurf_DispInfo( decal.m_SurfID )->ComputeShadowFragments( decal.m_DispShadow, wi.vertCount, wi.indexCount );
  2403. /*
  2404. int v, i;
  2405. if ( ! )
  2406. return false;
  2407. } */
  2408. }
  2409. //-----------------------------------------------------------------------------
  2410. // Computes information for rendering
  2411. //-----------------------------------------------------------------------------
  2412. void CShadowMgr::ComputeRenderInfo( ShadowDecalRenderInfo_t* pInfo, ShadowHandle_t handle ) const
  2413. {
  2414. const ShadowInfo_t& i = m_Shadows[handle];
  2415. pInfo->m_vTexOrigin = i.m_TexOrigin;
  2416. pInfo->m_vTexSize = i.m_TexSize;
  2417. pInfo->m_flFalloffOffset = 0.7f * i.m_FalloffOffset; // pull the offset in a little to hide the shadow darkness discontinuity
  2418. pInfo->m_flFalloffAmount = i.m_FalloffAmount;
  2419. pInfo->m_flFalloffBias = i.m_FalloffBias;
  2420. float flFalloffDist = i.m_MaxDist - pInfo->m_flFalloffOffset;
  2421. pInfo->m_flOOZFalloffDist = ( flFalloffDist > 0.0f ) ? 1.0f / flFalloffDist : 1.0f;
  2422. // for use in the shader
  2423. pInfo->m_vShadowFalloffParams.x = -pInfo->m_flFalloffOffset * pInfo->m_flOOZFalloffDist;
  2424. pInfo->m_vShadowFalloffParams.y = pInfo->m_flOOZFalloffDist;
  2425. pInfo->m_vShadowFalloffParams.z = 1.0f/255.0f * i.m_FalloffBias;
  2426. // we assume that shadow.m_flFalloffAmount is constant
  2427. }
  2428. //-----------------------------------------------------------------------------
  2429. // Adds normal shadows to the mesh builder
  2430. //-----------------------------------------------------------------------------
  2431. int CShadowMgr::AddNormalShadowsToMeshBuilder( CMeshBuilder& meshBuilder, ShadowRenderInfo_t& info )
  2432. {
  2433. // Step through the cache and add all shadows on normal surfaces
  2434. ShadowDecalRenderInfo_t shadow;
  2435. int baseIndex = 0;
  2436. for (int i = 0; i < info.m_Count; ++i)
  2437. {
  2438. // Two loops here, basically to minimize the # of if statements we need
  2439. ShadowVertexCache_t* pVertexCache;
  2440. if (info.m_pCache[i] < 0)
  2441. {
  2442. pVertexCache = &m_TempVertexCache[-info.m_pCache[i]-1];
  2443. }
  2444. else
  2445. {
  2446. pVertexCache = &m_VertexCache[info.m_pCache[i]];
  2447. }
  2448. ShadowVertex_t* pVerts = GetCachedVerts( *pVertexCache );
  2449. g_pShadowMgr->ComputeRenderInfo( &shadow, pVertexCache->m_Shadow );
  2450. int j;
  2451. Vector2D texCoord;
  2452. int vCount = pVertexCache->m_Count - 2;
  2453. if ( vCount <= 0 )
  2454. continue;
  2455. for ( j = 0; j < vCount; ++j, ++pVerts )
  2456. {
  2457. // Transform + offset the texture coords
  2458. Vector2DMultiply( pVerts->m_ShadowSpaceTexCoord.AsVector2D(), shadow.m_vTexSize, texCoord );
  2459. texCoord += shadow.m_vTexOrigin;
  2460. meshBuilder.Position3fv( pVerts->m_Position.Base() );
  2461. meshBuilder.TexCoord3f( 0, texCoord.x, texCoord.y, pVerts->m_ShadowSpaceTexCoord.z );
  2462. meshBuilder.TexCoord3fv( 1, shadow.m_vShadowFalloffParams.Base() );
  2463. meshBuilder.AdvanceVertexF<VTX_HAVEPOS, 2>();
  2464. meshBuilder.FastIndex( baseIndex );
  2465. meshBuilder.FastIndex( j + baseIndex + 1 );
  2466. meshBuilder.FastIndex( j + baseIndex + 2 );
  2467. }
  2468. Vector2DMultiply( pVerts->m_ShadowSpaceTexCoord.AsVector2D(), shadow.m_vTexSize, texCoord );
  2469. texCoord += shadow.m_vTexOrigin;
  2470. meshBuilder.Position3fv( pVerts->m_Position.Base() );
  2471. meshBuilder.TexCoord3f( 0, texCoord.x, texCoord.y, pVerts->m_ShadowSpaceTexCoord.z );
  2472. meshBuilder.TexCoord3fv( 1, shadow.m_vShadowFalloffParams.Base() );
  2473. meshBuilder.AdvanceVertexF<VTX_HAVEPOS, 2>();
  2474. ++pVerts;
  2475. Vector2DMultiply( pVerts->m_ShadowSpaceTexCoord.AsVector2D(), shadow.m_vTexSize, texCoord );
  2476. texCoord += shadow.m_vTexOrigin;
  2477. meshBuilder.Position3fv( pVerts->m_Position.Base() );
  2478. meshBuilder.TexCoord3f( 0, texCoord.x, texCoord.y, pVerts->m_ShadowSpaceTexCoord.z );
  2479. meshBuilder.TexCoord3fv( 1, shadow.m_vShadowFalloffParams.Base() );
  2480. meshBuilder.AdvanceVertexF<VTX_HAVEPOS, 2>();
  2481. // Update the base index
  2482. baseIndex += vCount + 2;
  2483. }
  2484. return baseIndex;
  2485. }
  2486. //-----------------------------------------------------------------------------
  2487. // Adds displacement shadows to the mesh builder
  2488. //-----------------------------------------------------------------------------
  2489. int CShadowMgr::AddDisplacementShadowsToMeshBuilder( CMeshBuilder& meshBuilder,
  2490. ShadowRenderInfo_t& info, int baseIndex )
  2491. {
  2492. if ( !r_DrawDisp.GetBool() )
  2493. return baseIndex;
  2494. // Step through the cache and add all shadows on displacement surfaces
  2495. for (int i = 0; i < info.m_DispCount; ++i)
  2496. {
  2497. baseIndex = DispInfo_AddShadowsToMeshBuilder( meshBuilder, info.m_pDispCache[i], baseIndex );
  2498. }
  2499. return baseIndex;
  2500. }
  2501. //-----------------------------------------------------------------------------
  2502. // The following methods will display debugging info in the middle of each shadow decal
  2503. //-----------------------------------------------------------------------------
  2504. static void DrawShadowID( ShadowHandle_t shadowHandle, const Vector &vecCentroid )
  2505. {
  2506. #ifndef DEDICATED
  2507. char buf[32];
  2508. Q_snprintf(buf, sizeof( buf ), "%d", shadowHandle );
  2509. CDebugOverlay::AddTextOverlay( vecCentroid, 0, buf );
  2510. #endif
  2511. }
  2512. void CShadowMgr::RenderDebuggingInfo( const ShadowRenderInfo_t &info, ShadowDebugFunc_t func )
  2513. {
  2514. // Step through the cache and add all shadows on normal surfaces
  2515. for (int i = 0; i < info.m_Count; ++i)
  2516. {
  2517. ShadowVertexCache_t* pVertexCache;
  2518. if (info.m_pCache[i] < 0)
  2519. {
  2520. pVertexCache = &m_TempVertexCache[-info.m_pCache[i]-1];
  2521. }
  2522. else
  2523. {
  2524. pVertexCache = &m_VertexCache[info.m_pCache[i]];
  2525. }
  2526. ShadowVertex_t* pVerts = GetCachedVerts( *pVertexCache );
  2527. Vector vecNormal;
  2528. float flTotalArea = 0.0f;
  2529. Vector vecCentroid(0,0,0);
  2530. Vector vecApex = pVerts[0].m_Position;
  2531. int vCount = pVertexCache->m_Count;
  2532. for ( int j = 0; j < vCount - 2; ++j )
  2533. {
  2534. Vector v1 = pVerts[j + 1].m_Position;
  2535. Vector v2 = pVerts[j + 2].m_Position;
  2536. CrossProduct( v2 - v1, v1 - vecApex, vecNormal );
  2537. float flArea = vecNormal.Length();
  2538. flTotalArea += flArea;
  2539. vecCentroid += (vecApex + v1 + v2) * flArea / 3.0f;
  2540. }
  2541. if (flTotalArea)
  2542. {
  2543. vecCentroid /= flTotalArea;
  2544. }
  2545. func( pVertexCache->m_Shadow, vecCentroid );
  2546. }
  2547. }
  2548. //-----------------------------------------------------------------------------
  2549. // Renders shadows that all share a material enumeration
  2550. //-----------------------------------------------------------------------------
  2551. void CShadowMgr::RenderShadowList( IMatRenderContext *pRenderContext, ShadowDecalHandle_t decalHandle, const VMatrix* pModelToWorld )
  2552. {
  2553. //=============================================================================
  2554. // HPE_BEGIN:
  2555. // [smessick] Make sure we don't overflow our caches.
  2556. //=============================================================================
  2557. if ( m_DecalsToRender > m_ShadowDecalCache.Count() )
  2558. {
  2559. // Don't grow past the MAX_SHADOW_DECAL_CACHE_COUNT cap.
  2560. int diff = MIN( m_DecalsToRender, MAX_SHADOW_DECAL_CACHE_COUNT ) - m_ShadowDecalCache.Count();
  2561. if ( diff > 0 )
  2562. {
  2563. // Grow the cache.
  2564. m_ShadowDecalCache.Grow( diff );
  2565. DevMsg( "[CShadowMgr::RenderShadowList] growing shadow decal cache (decals: %d, cache: %d, diff: %d).\n", m_DecalsToRender, m_ShadowDecalCache.Count(), diff );
  2566. }
  2567. }
  2568. if ( m_DecalsToRender > m_DispShadowDecalCache.Count() )
  2569. {
  2570. // Don't grow past the MAX_SHADOW_DECAL_CACHE_COUNT cap.
  2571. int diff = MIN( m_DecalsToRender, MAX_SHADOW_DECAL_CACHE_COUNT ) - m_DispShadowDecalCache.Count();
  2572. if ( diff > 0 )
  2573. {
  2574. // Grow the cache.
  2575. m_DispShadowDecalCache.Grow( diff );
  2576. DevMsg( "[CShadowMgr::RenderShadowList] growing disp shadow decal cache (decals: %d, cache: %d, diff: %d).\n", m_DecalsToRender, m_DispShadowDecalCache.Count(), diff );
  2577. }
  2578. }
  2579. //=============================================================================
  2580. // HPE_END
  2581. //=============================================================================
  2582. // Set the render state...
  2583. Shadow_t& shadow = m_Shadows[m_ShadowDecals[decalHandle].m_Shadow];
  2584. if ( r_shadowwireframe.GetInt() == 0 )
  2585. {
  2586. pRenderContext->Bind( shadow.m_pMaterial, shadow.m_pBindProxy );
  2587. }
  2588. else
  2589. {
  2590. pRenderContext->Bind( g_materialWorldWireframe );
  2591. }
  2592. // Blow away the temporary vertex cache (for normal surfaces)
  2593. ClearTempCache();
  2594. // Set up rendering info structure
  2595. ShadowRenderInfo_t info;
  2596. //=============================================================================
  2597. // HPE_BEGIN:
  2598. // [smessick] This code used to create the cache dynamically on the stack.
  2599. //=============================================================================
  2600. info.m_pCache = m_ShadowDecalCache.Base();
  2601. info.m_pDispCache = m_DispShadowDecalCache.Base();
  2602. //=============================================================================
  2603. // HPE_END
  2604. //=============================================================================
  2605. info.m_pModelToWorld = pModelToWorld;
  2606. if ( pModelToWorld )
  2607. {
  2608. MatrixInverseTR( *pModelToWorld, info.m_WorldToModel );
  2609. }
  2610. info.m_nMaxIndices = pRenderContext->GetMaxIndicesToRender();
  2611. info.m_nMaxVertices = pRenderContext->GetMaxVerticesToRender( shadow.m_pMaterial );
  2612. // Iterate over all decals in the decal list and generate polygon lists
  2613. // Creating them from scratch if their shadow poly cache is invalid
  2614. if ( r_threaded_shadow_clip.GetBool() )
  2615. {
  2616. GenerateShadowRenderInfoThreaded(pRenderContext, decalHandle, info);
  2617. }
  2618. else
  2619. {
  2620. GenerateShadowRenderInfo(pRenderContext, decalHandle, info);
  2621. }
  2622. Assert( info.m_Count <= m_DecalsToRender );
  2623. Assert( info.m_DispCount <= m_DecalsToRender );
  2624. //=============================================================================
  2625. // HPE_BEGIN:
  2626. // [smessick] Also check against the max.
  2627. //=============================================================================
  2628. Assert( info.m_Count <= m_ShadowDecalCache.Count() &&
  2629. info.m_Count <= MAX_SHADOW_DECAL_CACHE_COUNT );
  2630. Assert( info.m_DispCount <= m_DispShadowDecalCache.Count() &&
  2631. info.m_DispCount <= MAX_SHADOW_DECAL_CACHE_COUNT );
  2632. //=============================================================================
  2633. // HPE_END
  2634. //=============================================================================
  2635. // Now that the vertex lists are created, render them
  2636. IMesh* pMesh = pRenderContext->GetDynamicMesh();
  2637. CMeshBuilder meshBuilder;
  2638. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, info.m_VertexCount, info.m_IndexCount );
  2639. // Add in shadows from both normal surfaces + displacement surfaces
  2640. int baseIndex = AddNormalShadowsToMeshBuilder( meshBuilder, info );
  2641. AddDisplacementShadowsToMeshBuilder( meshBuilder, info, baseIndex );
  2642. meshBuilder.End();
  2643. pMesh->Draw();
  2644. if (r_shadowids.GetInt() != 0)
  2645. {
  2646. RenderDebuggingInfo( info, DrawShadowID );
  2647. }
  2648. }
  2649. //-----------------------------------------------------------------------------
  2650. // Set the number of world material buckets. This should get called on level load.
  2651. //-----------------------------------------------------------------------------
  2652. void CShadowMgr::SetNumWorldMaterialBuckets( int numMaterialSortBins )
  2653. {
  2654. m_NumWorldMaterialBuckets = numMaterialSortBins;
  2655. FlashlightHandle_t flashlightID;
  2656. for( flashlightID = m_FlashlightStates.Head();
  2657. flashlightID != m_FlashlightStates.InvalidIndex();
  2658. flashlightID = m_FlashlightStates.Next( flashlightID ) )
  2659. {
  2660. m_FlashlightStates[flashlightID].m_MaterialBuckets.SetNumMaterialSortIDs( numMaterialSortBins );
  2661. m_FlashlightStates[flashlightID].m_OccluderBuckets.SetNumMaterialSortIDs( numMaterialSortBins );
  2662. }
  2663. ClearAllFlashlightMaterialBuckets();
  2664. }
  2665. //-----------------------------------------------------------------------------
  2666. // Per frame call to clear all of the flashlight world material buckets.
  2667. //-----------------------------------------------------------------------------
  2668. void CShadowMgr::ClearAllFlashlightMaterialBuckets( void )
  2669. {
  2670. if ( m_bSinglePassFlashlightStateEnabled )
  2671. return;
  2672. FlashlightHandle_t flashlightID;
  2673. for( flashlightID = m_FlashlightStates.Head();
  2674. flashlightID != m_FlashlightStates.InvalidIndex();
  2675. flashlightID = m_FlashlightStates.Next( flashlightID ) )
  2676. {
  2677. m_FlashlightStates[flashlightID].m_MaterialBuckets.Flush();
  2678. }
  2679. }
  2680. //-----------------------------------------------------------------------------
  2681. // Allocate world material buckets for a particular flashlight. This should get called on flashlight creation.
  2682. //-----------------------------------------------------------------------------
  2683. void CShadowMgr::AllocFlashlightMaterialBuckets( FlashlightHandle_t flashlightID )
  2684. {
  2685. Assert( m_FlashlightStates.MaxElementIndex() >= flashlightID );
  2686. m_FlashlightStates[flashlightID].m_MaterialBuckets.SetNumMaterialSortIDs( m_NumWorldMaterialBuckets );
  2687. m_FlashlightStates[flashlightID].m_OccluderBuckets.SetNumMaterialSortIDs( m_NumWorldMaterialBuckets );
  2688. }
  2689. //-----------------------------------------------------------------------------
  2690. // Update a particular flashlight's state.
  2691. //-----------------------------------------------------------------------------
  2692. void CShadowMgr::UpdateFlashlightState( ShadowHandle_t shadowHandle, const FlashlightState_t &lightState )
  2693. {
  2694. m_FlashlightStates[m_Shadows[shadowHandle].m_FlashlightHandle].m_FlashlightState = lightState;
  2695. }
  2696. void CShadowMgr::SetFlashlightDepthTexture( ShadowHandle_t shadowHandle, ITexture *pFlashlightDepthTexture, unsigned char ucShadowStencilBit )
  2697. {
  2698. m_Shadows[shadowHandle].m_pFlashlightDepthTexture = pFlashlightDepthTexture;
  2699. m_Shadows[shadowHandle].m_ucShadowStencilBit = ucShadowStencilBit;
  2700. }
  2701. bool ScreenSpaceRectFromPoints( IMatRenderContext *pRenderContext, Vector vClippedPolygons[8][10], int *pNumPoints, int nNumPolygons, int *nLeft, int *nTop, int *nRight, int *nBottom )
  2702. {
  2703. if( nNumPolygons == 0 )
  2704. return false;
  2705. VMatrix matView, matProj, matViewProj;
  2706. pRenderContext->GetMatrix( MATERIAL_VIEW, &matView );
  2707. pRenderContext->GetMatrix( MATERIAL_PROJECTION, &matProj );
  2708. MatrixMultiply( matProj, matView, matViewProj );
  2709. float fMinX, fMaxX, fMinY, fMaxY; // Init bounding rect
  2710. fMinX = fMinY = FLT_MAX;
  2711. fMaxX = fMaxY = -FLT_MAX;
  2712. for ( int i=0; i<nNumPolygons; i++ )
  2713. {
  2714. for ( int j=0; j<pNumPoints[i]; j++ )
  2715. {
  2716. Vector vScreenSpacePoint;
  2717. matViewProj.V3Mul( vClippedPolygons[i][j], vScreenSpacePoint ); // Transform from World to screen space
  2718. fMinX = fpmin( fMinX, vScreenSpacePoint.x ); // Update mins/maxes
  2719. fMaxX = fpmax( fMaxX, vScreenSpacePoint.x ); //
  2720. fMinY = fpmin( fMinY, -vScreenSpacePoint.y ); // These are in -1 to +1 range
  2721. fMaxY = fpmax( fMaxY, -vScreenSpacePoint.y ); //
  2722. }
  2723. }
  2724. // Get render target dimensions
  2725. int nWidth, nHeight;
  2726. g_pMaterialSystem->GetBackBufferDimensions( nWidth, nHeight );
  2727. // Convert to render target pixel units
  2728. *nLeft = ((fMinX * 0.5f + 0.5f) * (float) nWidth ) - 1;
  2729. *nTop = ((fMinY * 0.5f + 0.5f) * (float) nHeight) - 1;
  2730. *nRight = ((fMaxX * 0.5f + 0.5f) * (float) nWidth ) + 1;
  2731. *nBottom = ((fMaxY * 0.5f + 0.5f) * (float) nHeight) + 1;
  2732. // Clamp to render target dimensions
  2733. *nLeft = clamp( *nLeft, 0, nWidth );
  2734. *nTop = clamp( *nTop, 0, nHeight );
  2735. *nRight = clamp( *nRight, 0, nWidth );
  2736. *nBottom = clamp( *nBottom, 0, nHeight );
  2737. // Scale and bias to fit current viewport
  2738. int nViewportX, nViewportY, nViewportWidth, nViewportHeight;
  2739. pRenderContext->GetViewport( nViewportX, nViewportY, nViewportWidth, nViewportHeight );
  2740. float flScaleX = ( float )( nViewportWidth ) / ( float )nWidth;
  2741. float flScaleY = ( float )( nViewportHeight ) / ( float )nHeight;
  2742. *nLeft = ( int )( ( float )( *nLeft ) * flScaleX ) + nViewportX;
  2743. *nRight = ( int )( ( float )( *nRight ) * flScaleX ) + nViewportX;
  2744. *nTop = ( int )( ( float )( *nTop ) * flScaleY ) + nViewportY;
  2745. *nBottom = ( int )( ( float )( *nBottom ) * flScaleY ) + nViewportY;
  2746. Assert( (*nLeft <= *nRight) && (*nTop <= *nBottom) );
  2747. // Do we have an actual subrect of the whole screen?
  2748. bool bWithinBounds = ((*nLeft > 0 ) || (*nTop > 0) || (*nRight < nWidth) || (*nBottom < nHeight));
  2749. // Compute valid area
  2750. nWidth = (*nRight - *nLeft);
  2751. nHeight = (*nBottom - *nTop);
  2752. int nArea = ( nWidth > 0 ) && ( nHeight > 0 ) ? nWidth * nHeight : 0;
  2753. // Valid rect?
  2754. return bWithinBounds && (nArea > 0);
  2755. }
  2756. // Turn this optimization off by default
  2757. static ConVar r_flashlightclip("r_flashlightclip", "0", FCVAR_CHEAT );
  2758. static ConVar r_flashlightdrawclip("r_flashlightdrawclip", "0", FCVAR_CHEAT );
  2759. static ConVar r_flashlightscissor( "r_flashlightscissor", "0", FCVAR_MATERIAL_SYSTEM_THREAD );
  2760. void ConstructNearAndFarPolygons( Vector *pVecNearPlane, Vector *pVecFarPlane, float flPlaneEpsilon )
  2761. {
  2762. const CViewSetup &view = g_EngineRenderer->ViewGetCurrent();
  2763. float fovY = CalcFovY( view.fov, view.m_flAspectRatio );
  2764. // Compute near and far plane half-width and half-height
  2765. float flTanHalfAngleRadians = tan( view.fov * ( 0.5f * M_PI / 180.0f ) );
  2766. float flHalfNearWidth = flTanHalfAngleRadians * ( view.zNear + flPlaneEpsilon );
  2767. float flHalfFarWidth = flTanHalfAngleRadians * ( view.zFar - flPlaneEpsilon );
  2768. flTanHalfAngleRadians = tan( fovY * ( 0.5f * M_PI / 180.0f ) );
  2769. float flHalfNearHeight = flTanHalfAngleRadians * ( view.zNear + flPlaneEpsilon );
  2770. float flHalfFarHeight = flTanHalfAngleRadians * ( view.zFar - flPlaneEpsilon );
  2771. // World-space orientation of viewer
  2772. Vector vForward, vRight, vUp;
  2773. AngleVectors( view.angles, &vForward, &vRight, &vUp );
  2774. vForward.NormalizeInPlace();
  2775. vRight.NormalizeInPlace();
  2776. vUp.NormalizeInPlace();
  2777. // Center of near and far planes in world space
  2778. Vector vCenterNear = view.origin + vForward * ( view.zNear + flPlaneEpsilon );
  2779. Vector vCenterFar = view.origin + vForward * ( view.zFar - flPlaneEpsilon );
  2780. pVecNearPlane[0] = vCenterNear - ( vRight * flHalfNearWidth ) - ( vUp * flHalfNearHeight );
  2781. pVecNearPlane[1] = vCenterNear - ( vRight * flHalfNearWidth ) + ( vUp * flHalfNearHeight );
  2782. pVecNearPlane[2] = vCenterNear + ( vRight * flHalfNearWidth ) + ( vUp * flHalfNearHeight );
  2783. pVecNearPlane[3] = vCenterNear + ( vRight * flHalfNearWidth ) - ( vUp * flHalfNearHeight );
  2784. pVecFarPlane[0] = vCenterNear - ( vRight * flHalfFarWidth ) - ( vUp * flHalfFarHeight );
  2785. pVecFarPlane[1] = vCenterNear + ( vRight * flHalfFarWidth ) - ( vUp * flHalfFarHeight );
  2786. pVecFarPlane[2] = vCenterNear + ( vRight * flHalfFarWidth ) + ( vUp * flHalfFarHeight );
  2787. pVecFarPlane[3] = vCenterNear - ( vRight * flHalfFarWidth ) + ( vUp * flHalfFarHeight );
  2788. }
  2789. void DrawDebugPolygon( int nNumVerts, Vector *pVecPoints, bool bFrontFacing, bool bNearPlane )
  2790. {
  2791. int r=0, g=0, b=0;
  2792. if ( bFrontFacing )
  2793. b = 255;
  2794. else
  2795. r = 255;
  2796. if ( bNearPlane ) // Draw near plane green for visualization
  2797. {
  2798. r = b = 0;
  2799. g = 255;
  2800. }
  2801. // Draw triangles fanned out from vertex zero
  2802. for (int i=1; i<(nNumVerts-1); i++)
  2803. {
  2804. Vector v0 = pVecPoints[0];
  2805. Vector v1 = pVecPoints[bFrontFacing ? i : i+1];
  2806. Vector v2 = pVecPoints[bFrontFacing ? i+1 : i];
  2807. CDebugOverlay::AddTriangleOverlay(v0, v1, v2, r, g, b, 20, true, 0 );
  2808. }
  2809. // Draw solid lines around the polygon
  2810. for (int i=0; i<nNumVerts; i++)
  2811. {
  2812. Vector v0 = pVecPoints[i];
  2813. Vector v1 = pVecPoints[ (i+1) % nNumVerts];
  2814. CDebugOverlay::AddLineOverlay( v0, v1, 255, 255, 255, 255, false, 0);
  2815. }
  2816. }
  2817. void DrawPolygonToStencil( IMatRenderContext *pRenderContext, int nNumVerts, Vector *pVecPoints, bool bFrontFacing, bool bNearPlane )
  2818. {
  2819. IMaterial *pMaterial = materials->FindMaterial( "engine/writestencil", TEXTURE_GROUP_OTHER, true );
  2820. pRenderContext->Bind( pMaterial );
  2821. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  2822. pRenderContext->MatrixMode( MATERIAL_MODEL );
  2823. pRenderContext->PushMatrix();
  2824. pRenderContext->LoadIdentity();
  2825. CMeshBuilder meshBuilder;
  2826. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nNumVerts-2 );
  2827. // Fan out from vertex zero
  2828. for (int i=1; i<(nNumVerts-1); i++)
  2829. {
  2830. meshBuilder.Position3f( pVecPoints[0].x, pVecPoints[0].y, pVecPoints[0].z );
  2831. meshBuilder.AdvanceVertexF<VTX_HAVEPOS, 0>();
  2832. int index = bFrontFacing ? i : i+1;
  2833. meshBuilder.Position3f( pVecPoints[index].x, pVecPoints[index].y, pVecPoints[index].z );
  2834. meshBuilder.AdvanceVertexF<VTX_HAVEPOS, 0>();
  2835. index = bFrontFacing ? i+1 : i;
  2836. meshBuilder.Position3f( pVecPoints[index].x, pVecPoints[index].y, pVecPoints[index].z );
  2837. meshBuilder.AdvanceVertexF<VTX_HAVEPOS, 0>();
  2838. }
  2839. meshBuilder.End( false, true );
  2840. pRenderContext->MatrixMode( MATERIAL_MODEL );
  2841. pRenderContext->PopMatrix();
  2842. }
  2843. // Determine if two Vectors are sufficiently close (Manhattan-ish distance, not Euclidean)
  2844. bool SufficientlyClose( Vector v1, Vector v2, float flEpsilon )
  2845. {
  2846. if ( fabs( v1.x - v2.x ) > flEpsilon ) // Bail if x components are sufficiently different
  2847. return false;
  2848. if ( fabs( v1.y - v2.y ) > flEpsilon ) // Bail if y components are sufficiently different
  2849. return false;
  2850. if ( fabs( v1.z - v2.z ) > flEpsilon ) // Bail if z components are sufficiently different
  2851. return false;
  2852. return true;
  2853. }
  2854. int ClipPlaneToFrustum( Vector *pInPoints, Vector *pOutPoints, Vector *pVecWorldFrustumPoints )
  2855. {
  2856. Vector vClipPing[10]; // Vector lists to ping-pong between while clipping
  2857. Vector vClipPong[10]; //
  2858. bool bPing = true; // Ping holds the latest polygon
  2859. vClipPing[0] = pInPoints[0]; // Copy into Ping
  2860. vClipPing[1] = pInPoints[1];
  2861. vClipPing[2] = pInPoints[2];
  2862. vClipPing[3] = pInPoints[3];
  2863. int nNumPoints = 4;
  2864. for ( int i=0; i < 6; i++ )
  2865. {
  2866. Vector vNormal;
  2867. float flDist;
  2868. if ( nNumPoints < 3 ) // If we're already clipped away, bail out entirely
  2869. break;
  2870. Vector *pClipPolygon = pVecWorldFrustumPoints+(4*i); // Polygon defining clip plane
  2871. ComputeTrianglePlane( pClipPolygon[0], pClipPolygon[1], pClipPolygon[2], vNormal, flDist ); // Compute plane normal and dist
  2872. if ( bPing )
  2873. nNumPoints = ClipPolyToPlane( vClipPing, nNumPoints, vClipPong, vNormal, flDist ); // Clip Ping into Pong
  2874. else
  2875. nNumPoints = ClipPolyToPlane( vClipPong, nNumPoints, vClipPing, vNormal, flDist ); // Clip Pong into Ping
  2876. bPing = !bPing; // Flip buffers
  2877. }
  2878. if ( nNumPoints < 3)
  2879. return 0;
  2880. if ( bPing )
  2881. memcpy( pOutPoints, vClipPing, nNumPoints * sizeof(Vector) );
  2882. else
  2883. memcpy( pOutPoints, vClipPong, nNumPoints * sizeof(Vector) );
  2884. return nNumPoints;
  2885. }
  2886. void CShadowMgr::SetStencilAndScissor( IMatRenderContext *pRenderContext, FlashlightInfo_t &flashlightInfo, bool bUseStencil )
  2887. {
  2888. VMatrix matFlashlightToWorld;
  2889. MatrixInverseGeneral( m_Shadows[flashlightInfo.m_Shadow].m_WorldToShadow, matFlashlightToWorld );
  2890. // Eight points defining the frustum in Flashlight space
  2891. Vector vFrustumPoints[24] = { Vector(0.0f, 0.0f, 0.0f), Vector(1.0f, 0.0f, 0.0f), Vector(1.0f, 1.0f, 0.0f), Vector(0.0f, 1.0f, 0.0f), // Near
  2892. Vector(0.0f, 0.0f, 1.0f), Vector(0.0f, 1.0f, 1.0f), Vector(1.0f, 1.0f, 1.0f), Vector(1.0f, 0.0f, 1.0f), // Far
  2893. Vector(1.0f, 0.0f, 0.0f), Vector(1.0f, 0.0f, 1.0f), Vector(1.0f, 1.0f, 1.0f), Vector(1.0f, 1.0f, 0.0f), // Right
  2894. Vector(0.0f, 0.0f, 0.0f), Vector(0.0f, 1.0f, 0.0f), Vector(0.0f, 1.0f, 1.0f), Vector(0.0f, 0.0f, 1.0f), // Left
  2895. Vector(0.0f, 1.0f, 0.0f), Vector(1.0f, 1.0f, 0.0f), Vector(1.0f, 1.0f, 1.0f), Vector(0.0f, 1.0f, 1.0f), // Bottom
  2896. Vector(0.0f, 0.0f, 0.0f), Vector(0.0f, 0.0f, 1.0f), Vector(1.0f, 0.0f, 1.0f), Vector(1.0f, 0.0f, 0.0f)}; // Top
  2897. // Transform points to world space
  2898. Vector vWorldFrustumPoints[24];
  2899. for ( int i=0; i < 24; i++ )
  2900. {
  2901. matFlashlightToWorld.V3Mul( vFrustumPoints[i], vWorldFrustumPoints[i] );
  2902. }
  2903. // Express near and far planes of View frustum in world space
  2904. Vector vNearNormal, vFarNormal;
  2905. float flNearDist, flFarDist;
  2906. const float flPlaneEpsilon = 0.4f;
  2907. const CViewSetup &view = g_EngineRenderer->ViewGetCurrent();
  2908. Vector vForward;
  2909. AngleVectors( view.angles, &vForward, NULL, NULL );
  2910. float flIntercept = DotProduct( view.origin, vForward );
  2911. vFarNormal = -vForward;
  2912. vNearNormal = vForward;
  2913. flNearDist = (view.zNear + flPlaneEpsilon) + flIntercept;
  2914. flFarDist = -(view.zFar - flPlaneEpsilon + flIntercept);
  2915. Vector vTempFace[5];
  2916. Vector vClippedFace[6];
  2917. Vector vClippedPolygons[8][10]; // Array of up to eight polygons (10 verts is more than enough for each)
  2918. int nNumVertices[8]; // Number vertices on each of the of clipped polygons
  2919. int nNumPolygons = 0; // How many polygons have survived the clip
  2920. // Clip each face individually to near and far planes
  2921. for ( int i=0; i < 6; i++ )
  2922. {
  2923. Vector *inVerts = vWorldFrustumPoints+(4*i); // Series of quadrilateral inputs
  2924. Vector *tempVerts = vTempFace;
  2925. Vector *outVerts = vClippedFace;
  2926. int nClipCount = ClipPolyToPlane( inVerts, 4, tempVerts, vNearNormal, flNearDist ); // need to set fOnPlaneEpsilon?
  2927. if ( nClipCount > 2 ) // If the polygon survived the near clip, try the far as well
  2928. {
  2929. nClipCount = ClipPolyToPlane( tempVerts, nClipCount, outVerts, vFarNormal, flFarDist ); // need to set fOnPlaneEpsilon?
  2930. if ( nClipCount > 2 ) // If we still have a poly after clipping to both planes, add it to the list
  2931. {
  2932. memcpy( vClippedPolygons[nNumPolygons], outVerts, nClipCount * sizeof (Vector) );
  2933. nNumVertices[nNumPolygons] = nClipCount;
  2934. nNumPolygons++;
  2935. }
  2936. }
  2937. }
  2938. // Construct polygons for near and far planes
  2939. Vector vNearPlane[4], vFarPlane[4];
  2940. ConstructNearAndFarPolygons( vNearPlane, vFarPlane, flPlaneEpsilon );
  2941. bool bNearPlane = false;
  2942. // Clip near plane to flashlight frustum and tack on to list
  2943. int nClipCount = ClipPlaneToFrustum( vNearPlane, vClippedPolygons[nNumPolygons], vWorldFrustumPoints );
  2944. if ( nClipCount > 2 ) // If the near plane clipped and resulted in a polygon, take note in the polygon list
  2945. {
  2946. nNumVertices[nNumPolygons] = nClipCount;
  2947. nNumPolygons++;
  2948. bNearPlane = true;
  2949. }
  2950. /*
  2951. TODO: do we even need to do the far plane?
  2952. // Clip near plane to flashlight frustum and tack on to list
  2953. nClipCount = ClipPlaneToFrustum( vFarPlane, vClippedPolygons[nNumPolygons], vWorldFrustumPoints );
  2954. if ( nClipCount > 2 ) // If the near plane clipped and resulted in a polygon, take note in the polygon list
  2955. {
  2956. nNumVertices[nNumPolygons] = nClipCount;
  2957. nNumPolygons++;
  2958. }
  2959. */
  2960. // Fuse positions of any verts which are within epsilon
  2961. for (int i=0; i<nNumPolygons; i++) // For each polygon
  2962. {
  2963. for (int j=0; j<nNumVertices[i]; j++) // For each vertex
  2964. {
  2965. for (int k=i+1; k<nNumPolygons; k++) // For each later polygon
  2966. {
  2967. for (int m=0; m<nNumVertices[k]; m++) // For each vertex
  2968. {
  2969. if ( SufficientlyClose(vClippedPolygons[i][j], vClippedPolygons[k][m], 0.1f) )
  2970. {
  2971. vClippedPolygons[k][m] = vClippedPolygons[i][j];
  2972. }
  2973. }
  2974. }
  2975. }
  2976. }
  2977. // Calculate scissoring rect
  2978. flashlightInfo.m_FlashlightState.m_bScissor = false;
  2979. if ( r_flashlightscissor.GetBool() && (nNumPolygons > 0) )
  2980. {
  2981. int nLeft, nTop, nRight, nBottom;
  2982. flashlightInfo.m_FlashlightState.m_bScissor = ScreenSpaceRectFromPoints( pRenderContext, vClippedPolygons, nNumVertices, nNumPolygons, &nLeft, &nTop, &nRight, &nBottom );
  2983. if ( flashlightInfo.m_FlashlightState.m_bScissor )
  2984. {
  2985. flashlightInfo.m_FlashlightState.m_nLeft = nLeft;
  2986. flashlightInfo.m_FlashlightState.m_nTop = nTop;
  2987. flashlightInfo.m_FlashlightState.m_nRight = nRight;
  2988. flashlightInfo.m_FlashlightState.m_nBottom = nBottom;
  2989. }
  2990. }
  2991. if ( r_flashlightdrawclip.GetBool() && r_flashlightclip.GetBool() && bUseStencil )
  2992. {
  2993. // Draw back facing debug polygons
  2994. for (int i=0; i<nNumPolygons; i++)
  2995. {
  2996. DrawDebugPolygon( nNumVertices[i], vClippedPolygons[i], false, false );
  2997. }
  2998. /*
  2999. // Draw front facing debug polygons
  3000. for (int i=0; i<nNumPolygons; i++)
  3001. {
  3002. DrawDebugPolygon( nNumVertices[i], vClippedPolygons[i], true, bNearPlane && (i == nNumPolygons-1) );
  3003. }
  3004. */
  3005. }
  3006. if ( r_flashlightclip.GetBool() && bUseStencil )
  3007. {
  3008. /*
  3009. // The traditional settings...
  3010. // Set up to set stencil bit on front facing polygons
  3011. pRenderContext->SetStencilEnable( true );
  3012. pRenderContext->SetStencilFailOperation( STENCILOPERATION_KEEP ); // Stencil fails
  3013. pRenderContext->SetStencilZFailOperation( STENCILOPERATION_KEEP ); // Stencil passes but depth fails
  3014. pRenderContext->SetStencilPassOperation( STENCILOPERATION_REPLACE ); // Z and stencil both pass
  3015. pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_ALWAYS ); // Stencil always pass
  3016. pRenderContext->SetStencilReferenceValue( m_Shadows[flashlightInfo.m_Shadow].m_ucShadowStencilBit );
  3017. pRenderContext->SetStencilTestMask( m_Shadows[flashlightInfo.m_Shadow].m_ucShadowStencilBit );
  3018. pRenderContext->SetStencilWriteMask( m_Shadows[flashlightInfo.m_Shadow].m_ucShadowStencilBit ); // Bit mask which is specific to this shadow
  3019. */
  3020. // Just blast front faces into the stencil buffer no matter what...
  3021. ShaderStencilState_t state;
  3022. state.m_bEnable = true;
  3023. state.m_FailOp = SHADER_STENCILOP_KEEP; // Stencil fails
  3024. state.m_ZFailOp = SHADER_STENCILOP_SET_TO_REFERENCE; // Stencil passes but depth fails
  3025. state.m_PassOp = SHADER_STENCILOP_SET_TO_REFERENCE; // Z and stencil both pass
  3026. state.m_CompareFunc = SHADER_STENCILFUNC_ALWAYS; // Stencil always pass
  3027. state.m_nReferenceValue = m_Shadows[flashlightInfo.m_Shadow].m_ucShadowStencilBit;
  3028. state.m_nTestMask = m_Shadows[flashlightInfo.m_Shadow].m_ucShadowStencilBit;
  3029. state.m_nWriteMask =m_Shadows[flashlightInfo.m_Shadow].m_ucShadowStencilBit; // Bit mask which is specific to this shadow
  3030. pRenderContext->SetStencilState( state );
  3031. for ( int i=0; i<nNumPolygons; i++ ) // Set the stencil bit on front facing
  3032. {
  3033. DrawPolygonToStencil( pRenderContext, nNumVertices[i], vClippedPolygons[i], true, false );
  3034. }
  3035. /*
  3036. pRenderContext->SetStencilReferenceValue( 0x00000000 ); // All bits cleared
  3037. for (int i=0; i<nNumPolygons; i++) // Clear the stencil bit on back facing
  3038. {
  3039. DrawPolygonToStencil( nNumVertices[i], vClippedPolygons[i], false, false );
  3040. }
  3041. */
  3042. ShaderStencilState_t stateDisable;
  3043. stateDisable.m_bEnable = false;
  3044. pRenderContext->SetStencilState( stateDisable );
  3045. }
  3046. }
  3047. //---------------------------------------------------------------------------------------
  3048. // Set masking stencil bits for all flashlights
  3049. //---------------------------------------------------------------------------------------
  3050. void CShadowMgr::SetFlashlightStencilMasks( bool bDoMasking )
  3051. {
  3052. VPROF_BUDGET( "CShadowMgr::SetFlashlightStencilMasks", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  3053. if ( m_bSinglePassFlashlightStateEnabled )
  3054. return;
  3055. // Bail out if we're not doing any of these optimizations
  3056. if ( !( r_flashlightclip.GetBool() || r_flashlightscissor.GetBool()) )
  3057. return;
  3058. FlashlightHandle_t flashlightID = m_FlashlightStates.Head();
  3059. if ( flashlightID == m_FlashlightStates.InvalidIndex() )
  3060. return;
  3061. CMatRenderContextPtr pRenderContext( materials );
  3062. for( ;
  3063. flashlightID != m_FlashlightStates.InvalidIndex();
  3064. flashlightID = m_FlashlightStates.Next( flashlightID ) )
  3065. {
  3066. FlashlightInfo_t &flashlightInfo = m_FlashlightStates[flashlightID];
  3067. if ( flashlightInfo.m_nSplitscreenOwner >= 0 )
  3068. {
  3069. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  3070. if ( flashlightInfo.m_nSplitscreenOwner != GET_ACTIVE_SPLITSCREEN_SLOT() )
  3071. continue;
  3072. }
  3073. SetStencilAndScissor( pRenderContext, flashlightInfo, m_Shadows[flashlightInfo.m_Shadow].m_pFlashlightDepthTexture != NULL );
  3074. }
  3075. }
  3076. void CShadowMgr::PushFlashlightScissorBounds( void )
  3077. {
  3078. m_ScissorStateEntryStart.AddToTail( m_ScissorStateBackups.Count() ); //push the location of the end of our current backup set
  3079. FlashlightHandle_t flashlightID = m_FlashlightStates.Head();
  3080. if ( flashlightID != m_FlashlightStates.InvalidIndex() )
  3081. {
  3082. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  3083. int iSplitScreenSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  3084. //count the number of entries we need
  3085. int iStateCount = 0;
  3086. for( ;
  3087. flashlightID != m_FlashlightStates.InvalidIndex();
  3088. flashlightID = m_FlashlightStates.Next( flashlightID ) )
  3089. {
  3090. FlashlightInfo_t &flashlightInfo = m_FlashlightStates[flashlightID];
  3091. if ( flashlightInfo.m_nSplitscreenOwner >= 0 )
  3092. {
  3093. if ( flashlightInfo.m_nSplitscreenOwner != iSplitScreenSlot )
  3094. continue;
  3095. }
  3096. ++iStateCount;
  3097. }
  3098. //add the entry space
  3099. int iWriteSlot = m_ScissorStateBackups.Count();
  3100. m_ScissorStateBackups.AddMultipleToTail( iStateCount );
  3101. FlashLightScissorStateBackup_t *pBackups = m_ScissorStateBackups.Base();
  3102. //write out the entries
  3103. flashlightID = m_FlashlightStates.Head();
  3104. for( ;
  3105. flashlightID != m_FlashlightStates.InvalidIndex();
  3106. flashlightID = m_FlashlightStates.Next( flashlightID ) )
  3107. {
  3108. FlashlightInfo_t &flashlightInfo = m_FlashlightStates[flashlightID];
  3109. if ( flashlightInfo.m_nSplitscreenOwner >= 0 )
  3110. {
  3111. if ( flashlightInfo.m_nSplitscreenOwner != iSplitScreenSlot )
  3112. continue;
  3113. }
  3114. //write out state here
  3115. pBackups[iWriteSlot].m_bScissor = flashlightInfo.m_FlashlightState.m_bScissor;
  3116. pBackups[iWriteSlot].m_nLeft = flashlightInfo.m_FlashlightState.m_nLeft;
  3117. pBackups[iWriteSlot].m_nTop = flashlightInfo.m_FlashlightState.m_nTop;
  3118. pBackups[iWriteSlot].m_nRight = flashlightInfo.m_FlashlightState.m_nRight;
  3119. pBackups[iWriteSlot].m_nBottom = flashlightInfo.m_FlashlightState.m_nBottom;
  3120. #if defined( DBGFLAG_ASSERT )
  3121. pBackups[iWriteSlot].m_iFlashLightID = flashlightID;
  3122. #endif
  3123. ++iWriteSlot;
  3124. }
  3125. }
  3126. }
  3127. void CShadowMgr::PopFlashlightScissorBounds( void )
  3128. {
  3129. int iPopStart = m_ScissorStateEntryStart.Tail();
  3130. m_ScissorStateEntryStart.RemoveMultipleFromTail( 1 );
  3131. if( iPopStart == m_ScissorStateBackups.Count() )
  3132. return; //nothing in the backup
  3133. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  3134. int iSplitScreenSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  3135. int iReadSlot = iPopStart;
  3136. FlashLightScissorStateBackup_t *pBackups = m_ScissorStateBackups.Base();
  3137. //read back the entries
  3138. FlashlightHandle_t flashlightID = m_FlashlightStates.Head();
  3139. for( ;
  3140. flashlightID != m_FlashlightStates.InvalidIndex();
  3141. flashlightID = m_FlashlightStates.Next( flashlightID ) )
  3142. {
  3143. FlashlightInfo_t &flashlightInfo = m_FlashlightStates[flashlightID];
  3144. if ( flashlightInfo.m_nSplitscreenOwner >= 0 )
  3145. {
  3146. if ( flashlightInfo.m_nSplitscreenOwner != iSplitScreenSlot )
  3147. continue;
  3148. }
  3149. //need a more complex restore system if this ever fails
  3150. Assert( pBackups[iReadSlot].m_iFlashLightID == flashlightID );
  3151. //read back state here
  3152. flashlightInfo.m_FlashlightState.m_bScissor = pBackups[iReadSlot].m_bScissor;
  3153. flashlightInfo.m_FlashlightState.m_nLeft = pBackups[iReadSlot].m_nLeft;
  3154. flashlightInfo.m_FlashlightState.m_nTop = pBackups[iReadSlot].m_nTop;
  3155. flashlightInfo.m_FlashlightState.m_nRight = pBackups[iReadSlot].m_nRight;
  3156. flashlightInfo.m_FlashlightState.m_nBottom = pBackups[iReadSlot].m_nBottom;
  3157. ++iReadSlot;
  3158. }
  3159. m_ScissorStateBackups.RemoveMultipleFromTail( m_ScissorStateBackups.Count() - iPopStart );
  3160. }
  3161. void CShadowMgr::DisableStencilAndScissorMasking( IMatRenderContext *pRenderContext, const FlashlightInfo_t &flashlightInfo, bool bDoMasking )
  3162. {
  3163. if ( r_flashlightclip.GetBool() )
  3164. {
  3165. ShaderStencilState_t state;
  3166. state.m_bEnable = false;
  3167. pRenderContext->SetStencilState( state );
  3168. }
  3169. // Bail out if we're not doing any of these optimizations
  3170. if ( !( r_flashlightclip.GetBool() || r_flashlightscissor.GetBool()) || !bDoMasking )
  3171. return;
  3172. // We only scissor when rendering to the back buffer
  3173. if ( pRenderContext->GetRenderTarget() == NULL )
  3174. {
  3175. if ( r_flashlightscissor.GetBool() && flashlightInfo.m_FlashlightState.m_bScissor )
  3176. {
  3177. pRenderContext->PopScissorRect();
  3178. }
  3179. }
  3180. }
  3181. //---------------------------------------------------------------------------------------
  3182. // Enable/Disable masking based on stencil bit
  3183. //---------------------------------------------------------------------------------------
  3184. void CShadowMgr::EnableStencilAndScissorMasking( IMatRenderContext *pRenderContext, const FlashlightInfo_t &flashlightInfo, bool bDoMasking )
  3185. {
  3186. // Bail out if we're not doing any of these optimizations
  3187. if ( !( r_flashlightclip.GetBool() || r_flashlightscissor.GetBool()) || !bDoMasking )
  3188. return;
  3189. // Only turn on scissor when rendering to the back buffer
  3190. if ( pRenderContext->GetRenderTarget() == NULL )
  3191. {
  3192. // Only do the stencil optimization when shadow depth mapping
  3193. if ( r_flashlightclip.GetBool() && m_Shadows[flashlightInfo.m_Shadow].m_pFlashlightDepthTexture != NULL )
  3194. {
  3195. unsigned char ucShadowStencilBit = m_Shadows[flashlightInfo.m_Shadow].m_ucShadowStencilBit;
  3196. ShaderStencilState_t state;
  3197. state.m_bEnable = true;
  3198. state.m_FailOp = SHADER_STENCILOP_KEEP; // Stencil fails
  3199. state.m_ZFailOp = SHADER_STENCILOP_KEEP; // Stencil passes but depth fails
  3200. state.m_PassOp = SHADER_STENCILOP_KEEP; // Z and stencil both pass
  3201. state.m_CompareFunc = SHADER_STENCILFUNC_EQUAL; // Stencil always pass
  3202. state.m_nReferenceValue = ucShadowStencilBit; // Bit must be set
  3203. state.m_nTestMask = ucShadowStencilBit; // Specific bit
  3204. state.m_nWriteMask = 0x00000000; // Specific bit
  3205. pRenderContext->SetStencilState( state );
  3206. }
  3207. // Scissor even if we're not shadow depth mapping
  3208. if ( r_flashlightscissor.GetBool() && flashlightInfo.m_FlashlightState.m_bScissor )
  3209. {
  3210. pRenderContext->PushScissorRect( flashlightInfo.m_FlashlightState.m_nLeft, flashlightInfo.m_FlashlightState.m_nTop,
  3211. flashlightInfo.m_FlashlightState.m_nRight, flashlightInfo.m_FlashlightState.m_nBottom );
  3212. }
  3213. }
  3214. }
  3215. //---------------------------------------------------------------------------------------
  3216. // Sets the render states necessary to render a flashlight
  3217. //---------------------------------------------------------------------------------------
  3218. void CShadowMgr::SetFlashlightRenderState( ShadowHandle_t handle )
  3219. {
  3220. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  3221. if ( handle == SHADOW_HANDLE_INVALID )
  3222. {
  3223. pRenderContext->SetFlashlightMode( false );
  3224. return;
  3225. }
  3226. const Shadow_t &shadow = m_Shadows[handle];
  3227. pRenderContext->SetFlashlightMode( true );
  3228. const FlashlightInfo_t &flashlightInfo = m_FlashlightStates[ shadow.m_FlashlightHandle ];
  3229. pRenderContext->SetFlashlightStateEx( flashlightInfo.m_FlashlightState, shadow.m_WorldToShadow, shadow.m_pFlashlightDepthTexture );
  3230. }
  3231. //---------------------------------------------------------------------------------------
  3232. // Render all of the world and displacement surfaces that need to be drawn for flashlights
  3233. //---------------------------------------------------------------------------------------
  3234. void CShadowMgr::RenderFlashlights( bool bDoMasking, bool bDoSimpleProjections, const VMatrix* pModelToWorld )
  3235. {
  3236. #ifndef DEDICATED
  3237. VPROF_BUDGET( "CShadowMgr::RenderFlashlights", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  3238. if ( m_bSinglePassFlashlightStateEnabled )
  3239. return;
  3240. if( r_flashlightrender.GetBool()==false && bDoSimpleProjections == false )
  3241. return;
  3242. // Draw the projective light sources, which get their material
  3243. // from the surface and not from the shadow.
  3244. // Tell the materialsystem that we are drawing additive flashlight lighting.
  3245. FlashlightHandle_t flashlightID = m_FlashlightStates.Head();
  3246. if ( flashlightID == m_FlashlightStates.InvalidIndex() )
  3247. return;
  3248. bool bWireframe = r_shadowwireframe.GetBool();
  3249. CMatRenderContextPtr pRenderContext( materials );
  3250. PIXEVENT( pRenderContext, "CShadowMgr::RenderFlashlights()" );
  3251. int nSearchFlags = SHADOW_SIMPLE_PROJECTION;
  3252. if ( bDoSimpleProjections == false )
  3253. {
  3254. pRenderContext->SetFlashlightMode( true );
  3255. nSearchFlags = SHADOW_FLASHLIGHT;
  3256. }
  3257. else
  3258. {
  3259. pRenderContext->SetFlashlightMode( false );
  3260. bDoMasking = false;
  3261. }
  3262. // PORTAL 2 PAINT RENDERING
  3263. CUtlVectorFixedGrowable< SurfaceHandle_t, 64 > paintableSurfaces;
  3264. CUtlVectorFixedGrowable< int, 16 > batchPaintableSurfaceCount;
  3265. CUtlVectorFixedGrowable< int, 16 > batchPaintableSurfaceIndexCount;
  3266. CUtlVectorFixedGrowable< FlashlightInfo_t *, 16 > flashlightInfos;
  3267. for( ;
  3268. flashlightID != m_FlashlightStates.InvalidIndex();
  3269. flashlightID = m_FlashlightStates.Next( flashlightID ) )
  3270. {
  3271. FlashlightInfo_t &flashlightInfo = m_FlashlightStates[flashlightID];
  3272. if ( ( m_Shadows[flashlightInfo.m_Shadow].m_Flags & ( SHADOW_FLASHLIGHT | SHADOW_SIMPLE_PROJECTION ) ) != nSearchFlags )
  3273. {
  3274. continue;
  3275. }
  3276. if ( flashlightInfo.m_nSplitscreenOwner >= 0 )
  3277. {
  3278. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  3279. if ( flashlightInfo.m_nSplitscreenOwner != GET_ACTIVE_SPLITSCREEN_SLOT() )
  3280. continue;
  3281. }
  3282. CMaterialsBuckets<SurfaceHandle_t> &materialBuckets = flashlightInfo.m_MaterialBuckets;
  3283. CMaterialsBuckets<SurfaceHandle_t>::SortIDHandle_t sortIDHandle = materialBuckets.GetFirstUsedSortID();
  3284. if ( sortIDHandle == materialBuckets.InvalidSortIDHandle() )
  3285. continue;
  3286. flashlightInfos.AddToTail( &flashlightInfo );
  3287. pRenderContext->SetFlashlightStateEx(flashlightInfo.m_FlashlightState, m_Shadows[flashlightInfo.m_Shadow].m_WorldToShadow, m_Shadows[flashlightInfo.m_Shadow].m_pFlashlightDepthTexture );
  3288. EnableStencilAndScissorMasking( pRenderContext, flashlightInfo, bDoMasking );
  3289. for( ; sortIDHandle != materialBuckets.InvalidSortIDHandle();
  3290. sortIDHandle = materialBuckets.GetNextUsedSortID( sortIDHandle ) )
  3291. {
  3292. int nBatchIndex = batchPaintableSurfaceCount.Count();
  3293. batchPaintableSurfaceCount.AddToTail( 0 );
  3294. batchPaintableSurfaceIndexCount.AddToTail( 0 );
  3295. int sortID = materialBuckets.GetSortID( sortIDHandle );
  3296. if( bWireframe )
  3297. {
  3298. pRenderContext->Bind( g_materialWorldWireframe );
  3299. }
  3300. else
  3301. {
  3302. if ( bDoSimpleProjections == false )
  3303. {
  3304. pRenderContext->Bind( materialSortInfoArray[sortID].material );
  3305. pRenderContext->BindLightmapPage( materialSortInfoArray[sortID].lightmapPageID );
  3306. }
  3307. else
  3308. {
  3309. pRenderContext->Bind( flashlightInfo.m_FlashlightState.m_pProjectedMaterial );
  3310. }
  3311. }
  3312. CMaterialsBuckets<SurfaceHandle_t>::ElementHandle_t elemHandle;
  3313. // Figure out how many indices we have.
  3314. int numIndices = 0;
  3315. for( elemHandle = materialBuckets.GetElementListHead( sortID );
  3316. elemHandle != materialBuckets.InvalidElementHandle();
  3317. elemHandle = materialBuckets.GetElementListNext( elemHandle ) )
  3318. {
  3319. SurfaceHandle_t surfID = materialBuckets.GetElement( elemHandle );
  3320. // PORTAL 2 PAINT RENDERING
  3321. if ( !SurfaceHasDispInfo( surfID ) && !bWireframe && ( MSurf_Flags( surfID ) & SURFDRAW_PAINTED ) )
  3322. {
  3323. paintableSurfaces.AddToTail( surfID );
  3324. ++ batchPaintableSurfaceCount[ nBatchIndex ];
  3325. int nVertCount, nIndexCount;
  3326. Shader_GetSurfVertexAndIndexCount( surfID, &nVertCount, &nIndexCount );
  3327. batchPaintableSurfaceIndexCount[ nBatchIndex ] += nIndexCount;
  3328. }
  3329. if( !SurfaceHasDispInfo( surfID ) )
  3330. {
  3331. numIndices += 3 * ( MSurf_VertCount( surfID ) - 2 );
  3332. }
  3333. }
  3334. if( numIndices > 0 )
  3335. {
  3336. // NOTE: If we ever need to make this faster, we could get larger
  3337. // batches here.
  3338. // Draw this batch.
  3339. IMesh *pMesh = pRenderContext->GetDynamicMesh( false, g_WorldStaticMeshes[sortID], 0 );
  3340. CMeshBuilder meshBuilder;
  3341. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 0, numIndices );
  3342. for( elemHandle = materialBuckets.GetElementListHead( sortID );
  3343. elemHandle != materialBuckets.InvalidElementHandle();
  3344. elemHandle = materialBuckets.GetElementListNext( elemHandle ) )
  3345. {
  3346. SurfaceHandle_t surfID = materialBuckets.GetElement( elemHandle );
  3347. if( !SurfaceHasDispInfo( surfID ) )
  3348. {
  3349. BuildIndicesForWorldSurface( meshBuilder, surfID, host_state.worldbrush );
  3350. }
  3351. }
  3352. // close out the index buffer
  3353. meshBuilder.End( false, true );
  3354. }
  3355. // NOTE: If we ever need to make this faster, we could get larger batches here.
  3356. // Draw displacements
  3357. for( elemHandle = materialBuckets.GetElementListHead( sortID );
  3358. elemHandle != materialBuckets.InvalidElementHandle();
  3359. elemHandle = materialBuckets.GetElementListNext( elemHandle ) )
  3360. {
  3361. SurfaceHandle_t surfID = materialBuckets.GetElement( elemHandle );
  3362. if( SurfaceHasDispInfo( surfID ) )
  3363. {
  3364. CDispInfo *pDisp = ( CDispInfo * )MSurf_DispInfo( surfID );
  3365. Assert( pDisp );
  3366. if( bWireframe )
  3367. {
  3368. pDisp->SpecifyDynamicMesh();
  3369. }
  3370. else
  3371. {
  3372. Assert( pDisp && pDisp->m_pMesh && pDisp->m_pMesh->m_pMesh );
  3373. pDisp->m_pMesh->m_pMesh->Draw( pDisp->m_iIndexOffset, pDisp->m_nIndices );
  3374. }
  3375. }
  3376. }
  3377. }
  3378. DisableStencilAndScissorMasking( pRenderContext, flashlightInfo, bDoMasking );
  3379. }
  3380. // PORTAL 2 PAINT RENDERING
  3381. if ( paintableSurfaces.Count() )
  3382. {
  3383. pRenderContext->SetRenderingPaint( true );
  3384. PIXEVENT( pRenderContext, "Paint" );
  3385. int nBatchIndex = 0;
  3386. int nSurfaceIndex = 0;
  3387. for ( int i = 0; i < flashlightInfos.Count(); i++ )
  3388. {
  3389. FlashlightInfo_t &flashlightInfo = *( flashlightInfos[ i ] );
  3390. CMaterialsBuckets<SurfaceHandle_t> &materialBuckets = flashlightInfo.m_MaterialBuckets;
  3391. CMaterialsBuckets<SurfaceHandle_t>::SortIDHandle_t sortIDHandle = materialBuckets.GetFirstUsedSortID();
  3392. pRenderContext->SetFlashlightStateEx(flashlightInfo.m_FlashlightState, m_Shadows[flashlightInfo.m_Shadow].m_WorldToShadow, m_Shadows[flashlightInfo.m_Shadow].m_pFlashlightDepthTexture );
  3393. EnableStencilAndScissorMasking( pRenderContext, flashlightInfo, bDoMasking );
  3394. for( ; sortIDHandle != materialBuckets.InvalidSortIDHandle();
  3395. sortIDHandle = materialBuckets.GetNextUsedSortID( sortIDHandle ) )
  3396. {
  3397. int sortID = materialBuckets.GetSortID( sortIDHandle );
  3398. int nSurfaceCount = batchPaintableSurfaceCount[ nBatchIndex ];
  3399. if ( nSurfaceCount > 0 )
  3400. {
  3401. if ( bDoSimpleProjections == false )
  3402. {
  3403. pRenderContext->Bind( materialSortInfoArray[sortID].material );
  3404. pRenderContext->BindLightmapPage( materialSortInfoArray[sortID].lightmapPageID );
  3405. }
  3406. else
  3407. {
  3408. pRenderContext->Bind( flashlightInfo.m_FlashlightState.m_pProjectedMaterial );
  3409. }
  3410. IMesh *pMesh = pRenderContext->GetDynamicMesh( false, g_WorldStaticMeshes[sortID], 0 );
  3411. CMeshBuilder meshBuilder;
  3412. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 0, batchPaintableSurfaceIndexCount[ nBatchIndex ] );
  3413. for ( int i = 0; i < nSurfaceCount; ++ i, ++ nSurfaceIndex )
  3414. {
  3415. BuildIndicesForWorldSurface( meshBuilder, paintableSurfaces[ nSurfaceIndex ], host_state.worldbrush );
  3416. }
  3417. meshBuilder.End( false, true );
  3418. }
  3419. ++ nBatchIndex;
  3420. }
  3421. DisableStencilAndScissorMasking( pRenderContext, flashlightInfo, bDoMasking );
  3422. }
  3423. pRenderContext->SetRenderingPaint( false );
  3424. }
  3425. // Tell the materialsystem that we are finished drawing additive flashlight lighting.
  3426. if ( bDoSimpleProjections == false )
  3427. {
  3428. pRenderContext->SetFlashlightMode( false );
  3429. }
  3430. else
  3431. {
  3432. pRenderContext->SetFlashlightMode( false );
  3433. }
  3434. #endif
  3435. }
  3436. const Frustum_t &CShadowMgr::GetFlashlightFrustum( ShadowHandle_t handle )
  3437. {
  3438. Assert( m_Shadows[handle].m_Flags & ( SHADOW_FLASHLIGHT | SHADOW_SIMPLE_PROJECTION ) );
  3439. Assert( m_Shadows[handle].m_FlashlightHandle != m_Shadows.InvalidIndex() );
  3440. return m_FlashlightStates[m_Shadows[handle].m_FlashlightHandle].m_Frustum;
  3441. }
  3442. const FlashlightState_t &CShadowMgr::GetFlashlightState( ShadowHandle_t handle )
  3443. {
  3444. Assert( m_Shadows[handle].m_Flags & ( SHADOW_FLASHLIGHT | SHADOW_SIMPLE_PROJECTION ) );
  3445. Assert( m_Shadows[handle].m_FlashlightHandle != m_Shadows.InvalidIndex() );
  3446. return m_FlashlightStates[m_Shadows[handle].m_FlashlightHandle].m_FlashlightState;
  3447. }
  3448. void CShadowMgr::DrawVolumetrics()
  3449. {
  3450. VPROF_BUDGET( "CShadowMgr::DrawVolumetrics", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  3451. FlashlightHandle_t flashlightID = m_FlashlightStates.Head();
  3452. if ( flashlightID == m_FlashlightStates.InvalidIndex() )
  3453. return;
  3454. CMatRenderContextPtr pRenderContext( materials );
  3455. for( ; flashlightID != m_FlashlightStates.InvalidIndex();
  3456. flashlightID = m_FlashlightStates.Next( flashlightID ) )
  3457. {
  3458. FlashlightInfo_t &flashlightInfo = m_FlashlightStates[flashlightID];
  3459. if ( flashlightInfo.m_nSplitscreenOwner >= 0 )
  3460. {
  3461. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  3462. if ( flashlightInfo.m_nSplitscreenOwner != GET_ACTIVE_SPLITSCREEN_SLOT() )
  3463. continue;
  3464. }
  3465. FlashlightState_t &flashlightState = flashlightInfo.m_FlashlightState;
  3466. // If this flashlight isn't volumetric, bail out here
  3467. if ( !flashlightState.m_bVolumetric || ( flashlightState.m_flVolumetricIntensity <= 0.0f ) )
  3468. continue;
  3469. bool foundVar;
  3470. IMaterial *pMaterial = materials->FindMaterial( "engine/lightshaft", TEXTURE_GROUP_OTHER, true );
  3471. IMaterialVar *pCookieTextureVar = pMaterial->FindVar( "$COOKIETEXTURE", &foundVar, false );
  3472. IMaterialVar *pNoiseTextureVar = pMaterial->FindVar( "$NOISETEXTURE", &foundVar, false );
  3473. IMaterialVar *pCookieFrameNumVar = pMaterial->FindVar( "$COOKIEFRAMENUM", &foundVar, false );
  3474. IMaterialVar *pShadowDepthTextureVar = pMaterial->FindVar( "$SHADOWDEPTHTEXTURE", &foundVar, false );
  3475. IMaterialVar *pWorldToTextureVar = pMaterial->FindVar( "$WORLDTOTEXTURE", &foundVar, false );
  3476. IMaterialVar *pFlashlightColorVar = pMaterial->FindVar( "$FLASHLIGHTCOLOR", &foundVar, false );
  3477. IMaterialVar *pAttenFactorsVar = pMaterial->FindVar( "$ATTENFACTORS", &foundVar, false );
  3478. IMaterialVar *pOriginFarZVar = pMaterial->FindVar( "$ORIGINFARZ", &foundVar, false );
  3479. IMaterialVar *pQuatOrientation = pMaterial->FindVar( "$QUATORIENTATION", &foundVar, false );
  3480. IMaterialVar *pShadowFilterSizeVar = pMaterial->FindVar( "$SHADOWFILTERSIZE", &foundVar, false );
  3481. IMaterialVar *pShadowAttenVar = pMaterial->FindVar( "$SHADOWATTEN", &foundVar, false );
  3482. IMaterialVar *pShadowJitterSeedVar = pMaterial->FindVar( "$SHADOWJITTERSEED", &foundVar, false );
  3483. IMaterialVar *pUberlightVar = pMaterial->FindVar( "$UBERLIGHT", &foundVar, false );
  3484. IMaterialVar *pEnableShadowsVar = pMaterial->FindVar( "$ENABLESHADOWS", &foundVar, false );
  3485. IMaterialVar *pUberNearFarVar = pMaterial->FindVar( "$UBERNEARFAR", &foundVar, false );
  3486. IMaterialVar *pUberHeightWidthVar = pMaterial->FindVar( "$UBERHEIGHTWIDTH", &foundVar, false );
  3487. IMaterialVar *pUberRoundnessVar = pMaterial->FindVar( "$UBERROUNDNESS", &foundVar, false );
  3488. IMaterialVar *pNoiseStrengthVar = pMaterial->FindVar( "$NOISESTRENGTH", &foundVar, false );
  3489. IMaterialVar *pFlashlighTimeVar = pMaterial->FindVar( "$FLASHLIGHTTIME", &foundVar, false );
  3490. IMaterialVar *pNumPlanesVar = pMaterial->FindVar( "$NUMPLANES", &foundVar, false );
  3491. IMaterialVar *pVolumetricIntensityVar = pMaterial->FindVar( "$VOLUMETRICINTENSITY", &foundVar, false );
  3492. if ( m_Shadows[flashlightInfo.m_Shadow].m_pFlashlightDepthTexture && pShadowDepthTextureVar )
  3493. {
  3494. pShadowDepthTextureVar->SetTextureValue( m_Shadows[flashlightInfo.m_Shadow].m_pFlashlightDepthTexture );
  3495. }
  3496. if ( flashlightState.m_pSpotlightTexture && pCookieTextureVar )
  3497. {
  3498. pCookieTextureVar->SetTextureValue( flashlightState.m_pSpotlightTexture );
  3499. }
  3500. if ( pNoiseTextureVar )
  3501. {
  3502. pNoiseTextureVar->SetTextureValue( materials->FindTexture( "effects/noise_rg", TEXTURE_GROUP_OTHER, true ) );
  3503. }
  3504. if ( pCookieFrameNumVar )
  3505. {
  3506. pCookieFrameNumVar->SetIntValue( flashlightState.m_nSpotlightTextureFrame );
  3507. }
  3508. if ( pWorldToTextureVar )
  3509. {
  3510. pWorldToTextureVar->SetMatrixValue( m_Shadows[flashlightInfo.m_Shadow].m_WorldToShadow );
  3511. }
  3512. if ( pFlashlightColorVar )
  3513. {
  3514. pFlashlightColorVar->SetVecValue( &(flashlightState.m_Color[0]), 4 );
  3515. }
  3516. if ( pAttenFactorsVar )
  3517. {
  3518. pAttenFactorsVar->SetVecValue( flashlightState.m_fConstantAtten, flashlightState.m_fLinearAtten, flashlightState.m_fQuadraticAtten, flashlightState.m_FarZAtten );
  3519. }
  3520. if ( pOriginFarZVar )
  3521. {
  3522. pOriginFarZVar->SetVecValue( flashlightState.m_vecLightOrigin[0], flashlightState.m_vecLightOrigin[1], flashlightState.m_vecLightOrigin[2], flashlightState.m_FarZ );
  3523. }
  3524. if ( pQuatOrientation )
  3525. {
  3526. pQuatOrientation->SetVecValue( flashlightState.m_quatOrientation.Base(), 4 );
  3527. }
  3528. if ( pShadowFilterSizeVar )
  3529. {
  3530. pShadowFilterSizeVar->SetFloatValue( flashlightState.m_flShadowFilterSize );
  3531. }
  3532. if ( pShadowAttenVar )
  3533. {
  3534. pShadowAttenVar->SetFloatValue( flashlightState.m_flShadowAtten );
  3535. }
  3536. if ( pShadowJitterSeedVar )
  3537. {
  3538. pShadowJitterSeedVar->SetFloatValue( flashlightState.m_flShadowJitterSeed );
  3539. }
  3540. if ( pUberlightVar )
  3541. {
  3542. pUberlightVar->SetIntValue( flashlightState.m_bUberlight ? 1 : 0 );
  3543. }
  3544. if ( pEnableShadowsVar )
  3545. {
  3546. pEnableShadowsVar->SetIntValue( flashlightState.m_bEnableShadows ? 1 : 0 );
  3547. }
  3548. if ( pUberNearFarVar )
  3549. {
  3550. pUberNearFarVar->SetVecValue( flashlightState.m_uberlightState.m_fNearEdge, flashlightState.m_uberlightState.m_fFarEdge,
  3551. flashlightState.m_uberlightState.m_fCutOn, flashlightState.m_uberlightState.m_fCutOff );
  3552. }
  3553. if ( pUberHeightWidthVar )
  3554. {
  3555. pUberHeightWidthVar->SetVecValue( flashlightState.m_uberlightState.m_fWidth, flashlightState.m_uberlightState.m_fWedge,
  3556. flashlightState.m_uberlightState.m_fHeight, flashlightState.m_uberlightState.m_fHedge );
  3557. }
  3558. if ( pUberRoundnessVar )
  3559. {
  3560. pUberRoundnessVar->SetFloatValue( flashlightState.m_uberlightState.m_fRoundness );
  3561. }
  3562. if ( pNoiseStrengthVar )
  3563. {
  3564. pNoiseStrengthVar->SetFloatValue( flashlightState.m_flNoiseStrength );
  3565. }
  3566. if ( pFlashlighTimeVar )
  3567. {
  3568. pFlashlighTimeVar->SetFloatValue( flashlightState.m_flFlashlightTime );
  3569. }
  3570. if ( pNumPlanesVar )
  3571. {
  3572. pNumPlanesVar->SetIntValue( flashlightState.m_nNumPlanes );
  3573. }
  3574. if ( pVolumetricIntensityVar )
  3575. {
  3576. pVolumetricIntensityVar->SetFloatValue( flashlightState.m_flVolumetricIntensity );
  3577. }
  3578. pRenderContext->Bind( pMaterial );
  3579. // Set up user clip planes to clip to this flashlight's frustum
  3580. VPlane planes[FRUSTUM_NUMPLANES];
  3581. flashlightInfo.m_Frustum.GetPlanes( planes );
  3582. for ( int i = 0; i < 6; i++ )
  3583. {
  3584. pRenderContext->PushCustomClipPlane( planes[i].m_Normal.Base() );
  3585. }
  3586. // Flashlight space to world space, then view space
  3587. VMatrix matWorldToView, matViewToWorld, matFlashlightToView, matViewToFlashlight;
  3588. pRenderContext->GetMatrix( MATERIAL_VIEW, &matWorldToView );
  3589. MatrixInverseGeneral( matWorldToView, matViewToWorld );
  3590. MatrixMultiply( m_Shadows[flashlightInfo.m_Shadow].m_WorldToShadow, matViewToWorld, matViewToFlashlight );
  3591. MatrixInverseGeneral( matViewToFlashlight, matFlashlightToView );
  3592. // View space AABB
  3593. Vector vView, vWorld, vViewMins, vViewMaxs;
  3594. CalculateAABBFromProjectionMatrixInverse( matFlashlightToView, &vViewMins, &vViewMaxs );
  3595. // Distance between planes
  3596. float zIncrement = ( vViewMaxs.z - vViewMins.z ) / (float) flashlightState.m_nNumPlanes;
  3597. // Base offset for this set of planes (progressive refinement sets this in SFM)
  3598. vViewMins.z += zIncrement * flashlightState.m_flPlaneOffset;
  3599. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  3600. pRenderContext->MatrixMode( MATERIAL_MODEL );
  3601. pRenderContext->PushMatrix();
  3602. pRenderContext->LoadIdentity();
  3603. CMeshBuilder meshBuilder;
  3604. meshBuilder.Begin( pMesh, MATERIAL_QUADS, flashlightState.m_nNumPlanes );
  3605. for (int i = 0; i < flashlightState.m_nNumPlanes; i++ )
  3606. {
  3607. vView = Vector( vViewMins.x, vViewMins.y, vViewMins.z + (float)i * zIncrement );// View space
  3608. Vector3DMultiplyPosition( matViewToWorld, vView, vWorld ); // Transform to world space
  3609. meshBuilder.Position3fv( vWorld.Base() );
  3610. meshBuilder.AdvanceVertexF<VTX_HAVEPOS, 0>();
  3611. vView = Vector( vViewMins.x, vViewMaxs.y, vViewMins.z + (float)i * zIncrement );// View space
  3612. Vector3DMultiplyPosition( matViewToWorld, vView, vWorld ); // Transform to world space
  3613. meshBuilder.Position3fv( vWorld.Base() );
  3614. meshBuilder.AdvanceVertexF<VTX_HAVEPOS, 0>();
  3615. vView = Vector( vViewMaxs.x, vViewMaxs.y, vViewMins.z + (float)i * zIncrement );// View space
  3616. Vector3DMultiplyPosition( matViewToWorld, vView, vWorld ); // Transform to world space
  3617. meshBuilder.Position3fv( vWorld.Base() );
  3618. meshBuilder.AdvanceVertexF<VTX_HAVEPOS, 0>();
  3619. vView = Vector( vViewMaxs.x, vViewMins.y, vViewMins.z + (float)i * zIncrement );// View space
  3620. Vector3DMultiplyPosition( matViewToWorld, vView, vWorld ); // Transform to world space
  3621. meshBuilder.Position3fv( vWorld.Base() );
  3622. meshBuilder.AdvanceVertexF<VTX_HAVEPOS, 0>();
  3623. }
  3624. meshBuilder.End( false, true );
  3625. pRenderContext->PopMatrix();
  3626. // Pop the custom clip planes
  3627. for ( int i=0; i<6; i++ )
  3628. {
  3629. pRenderContext->PopCustomClipPlane();
  3630. }
  3631. }
  3632. }
  3633. void CShadowMgr::DrawFlashlightDecals( IMatRenderContext *pRenderContext, int sortGroup, bool bDoMasking, float flFade )
  3634. {
  3635. VPROF_BUDGET( "CShadowMgr::DrawFlashlightDecals", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  3636. if ( m_bSinglePassFlashlightStateEnabled )
  3637. return;
  3638. FlashlightHandle_t flashlightID = m_FlashlightStates.Head();
  3639. if ( flashlightID == m_FlashlightStates.InvalidIndex() )
  3640. return;
  3641. pRenderContext->SetFlashlightMode( true );
  3642. for( ;
  3643. flashlightID != m_FlashlightStates.InvalidIndex();
  3644. flashlightID = m_FlashlightStates.Next( flashlightID ) )
  3645. {
  3646. FlashlightInfo_t &flashlightInfo = m_FlashlightStates[flashlightID];
  3647. if ( ( m_Shadows[flashlightInfo.m_Shadow].m_Flags & ( SHADOW_SIMPLE_PROJECTION ) ) != 0 )
  3648. {
  3649. continue;
  3650. }
  3651. if ( flashlightInfo.m_nSplitscreenOwner >= 0 )
  3652. {
  3653. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  3654. if ( flashlightInfo.m_nSplitscreenOwner != GET_ACTIVE_SPLITSCREEN_SLOT() )
  3655. continue;
  3656. }
  3657. pRenderContext->SetFlashlightStateEx( flashlightInfo.m_FlashlightState, m_Shadows[flashlightInfo.m_Shadow].m_WorldToShadow, m_Shadows[flashlightInfo.m_Shadow].m_pFlashlightDepthTexture );
  3658. EnableStencilAndScissorMasking( pRenderContext, flashlightInfo, bDoMasking );
  3659. DecalSurfaceDraw( pRenderContext, sortGroup, flFade );
  3660. DisableStencilAndScissorMasking( pRenderContext, flashlightInfo, bDoMasking );
  3661. }
  3662. // Tell the materialsystem that we are finished drawing additive flashlight lighting.
  3663. pRenderContext->SetFlashlightMode( false );
  3664. }
  3665. void CShadowMgr::FlashlightDrawCallback( ShadowDrawCallbackFn_t pCallback, void *pData )
  3666. {
  3667. VPROF_BUDGET( "CShadowMgr::FlashlightDrawCallback", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  3668. if ( m_bSinglePassFlashlightStateEnabled )
  3669. return;
  3670. FlashlightHandle_t flashlightID = m_FlashlightStates.Head();
  3671. if ( flashlightID == m_FlashlightStates.InvalidIndex() )
  3672. return;
  3673. CMatRenderContextPtr pRenderContext( materials );
  3674. pRenderContext->SetFlashlightMode( true );
  3675. for( ;
  3676. flashlightID != m_FlashlightStates.InvalidIndex();
  3677. flashlightID = m_FlashlightStates.Next( flashlightID ) )
  3678. {
  3679. FlashlightInfo_t &flashlightInfo = m_FlashlightStates[flashlightID];
  3680. if ( flashlightInfo.m_nSplitscreenOwner >= 0 )
  3681. {
  3682. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  3683. if ( flashlightInfo.m_nSplitscreenOwner != GET_ACTIVE_SPLITSCREEN_SLOT() )
  3684. continue;
  3685. }
  3686. pRenderContext->SetFlashlightStateEx( flashlightInfo.m_FlashlightState, m_Shadows[flashlightInfo.m_Shadow].m_WorldToShadow, m_Shadows[flashlightInfo.m_Shadow].m_pFlashlightDepthTexture );
  3687. EnableStencilAndScissorMasking( pRenderContext, flashlightInfo, false );
  3688. pCallback( pData );
  3689. DisableStencilAndScissorMasking( pRenderContext, flashlightInfo, false );
  3690. }
  3691. // Tell the materialsystem that we are finished drawing additive flashlight lighting.
  3692. pRenderContext->SetFlashlightMode( false );
  3693. }
  3694. void CShadowMgr::SetSinglePassFlashlightRenderState( ShadowHandle_t handle )
  3695. {
  3696. m_hSinglePassFlashlightState = handle;
  3697. //materials->GetRenderContext()->Flush();
  3698. if( m_bSinglePassFlashlightStateEnabled )
  3699. {
  3700. SetFlashlightRenderState( m_hSinglePassFlashlightState );
  3701. }
  3702. else
  3703. {
  3704. //TODO: Look for headaches of changing the handle while we're not supposed to be in control
  3705. SetFlashlightRenderState( SHADOW_HANDLE_INVALID );
  3706. }
  3707. }
  3708. void CShadowMgr::PushSinglePassFlashlightStateEnabled( bool bEnable )
  3709. {
  3710. m_bStack_SinglePassFlashlightStateEnabled.Push( bEnable );
  3711. if( m_bSinglePassFlashlightStateEnabled != bEnable )
  3712. {
  3713. materials->GetRenderContext()->EnableSinglePassFlashlightMode( bEnable );
  3714. if( bEnable )
  3715. SetFlashlightRenderState( m_hSinglePassFlashlightState );
  3716. else
  3717. SetFlashlightRenderState( SHADOW_HANDLE_INVALID );
  3718. m_bSinglePassFlashlightStateEnabled = bEnable;
  3719. }
  3720. if ( m_bSinglePassFlashlightStateEnabled )
  3721. {
  3722. // Only enable culling for single pass flashlight if NOT in splitscreen
  3723. materials->GetRenderContext()->EnableCullingForSinglePassFlashlight( r_flashlight_always_cull_for_single_pass.GetBool() || ( GET_NUM_SPLIT_SCREEN_PLAYERS() < 2 ) );
  3724. }
  3725. }
  3726. void CShadowMgr::PopSinglePassFlashlightStateEnabled( void )
  3727. {
  3728. m_bStack_SinglePassFlashlightStateEnabled.Pop();
  3729. bool bEnable = IsGameConsole();
  3730. if( m_bStack_SinglePassFlashlightStateEnabled.Count() != 0 )
  3731. {
  3732. bEnable = m_bStack_SinglePassFlashlightStateEnabled.Top();
  3733. }
  3734. if( m_bSinglePassFlashlightStateEnabled != bEnable )
  3735. {
  3736. materials->GetRenderContext()->EnableSinglePassFlashlightMode( bEnable );
  3737. if( bEnable )
  3738. SetFlashlightRenderState( m_hSinglePassFlashlightState );
  3739. else
  3740. SetFlashlightRenderState( SHADOW_HANDLE_INVALID );
  3741. m_bSinglePassFlashlightStateEnabled = bEnable;
  3742. }
  3743. if ( m_bSinglePassFlashlightStateEnabled )
  3744. {
  3745. // Only enable culling for single pass flashlight if NOT in splitscreen
  3746. materials->GetRenderContext()->EnableCullingForSinglePassFlashlight( r_flashlight_always_cull_for_single_pass.GetBool() || ( GET_NUM_SPLIT_SCREEN_PLAYERS() < 2 ) );
  3747. }
  3748. }
  3749. bool CShadowMgr::SinglePassFlashlightModeEnabled( void )
  3750. {
  3751. return m_bSinglePassFlashlightStateEnabled;
  3752. }
  3753. void CShadowMgr::DrawFlashlightDecalsOnDisplacements( IMatRenderContext *pRenderContext, int sortGroup, CDispInfo *visibleDisps[MAX_MAP_DISPINFO], int nVisibleDisps, bool bDoMasking )
  3754. {
  3755. VPROF_BUDGET( "CShadowMgr::DrawFlashlightDecalsOnDisplacements", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  3756. if ( m_bSinglePassFlashlightStateEnabled )
  3757. return;
  3758. FlashlightHandle_t flashlightID = m_FlashlightStates.Head();
  3759. if ( flashlightID == m_FlashlightStates.InvalidIndex() )
  3760. return;
  3761. pRenderContext->SetFlashlightMode( true );
  3762. DispInfo_BatchDecals( visibleDisps, nVisibleDisps );
  3763. for( ;
  3764. flashlightID != m_FlashlightStates.InvalidIndex();
  3765. flashlightID = m_FlashlightStates.Next( flashlightID ) )
  3766. {
  3767. FlashlightInfo_t &flashlightInfo = m_FlashlightStates[flashlightID];
  3768. if ( flashlightInfo.m_nSplitscreenOwner >= 0 )
  3769. {
  3770. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  3771. if ( flashlightInfo.m_nSplitscreenOwner != GET_ACTIVE_SPLITSCREEN_SLOT() )
  3772. continue;
  3773. }
  3774. pRenderContext->SetFlashlightStateEx( flashlightInfo.m_FlashlightState, m_Shadows[flashlightInfo.m_Shadow].m_WorldToShadow, m_Shadows[flashlightInfo.m_Shadow].m_pFlashlightDepthTexture );
  3775. EnableStencilAndScissorMasking( pRenderContext, flashlightInfo, bDoMasking );
  3776. DispInfo_DrawDecals( pRenderContext, visibleDisps, nVisibleDisps );
  3777. DisableStencilAndScissorMasking( pRenderContext, flashlightInfo, bDoMasking );
  3778. }
  3779. // Tell the materialsystem that we are finished drawing additive flashlight lighting.
  3780. pRenderContext->SetFlashlightMode( false );
  3781. }
  3782. void CShadowMgr::DrawFlashlightDecalsOnSurfaceList( IMatRenderContext *pRenderContext, SurfaceHandle_t *pList, int listCount, bool bDoMasking )
  3783. {
  3784. VPROF_BUDGET( "CShadowMgr::DrawFlashlightDecalsOnSurfaceList", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  3785. if ( m_bSinglePassFlashlightStateEnabled )
  3786. return;
  3787. FlashlightHandle_t flashlightID = m_FlashlightStates.Head();
  3788. if ( flashlightID == m_FlashlightStates.InvalidIndex() )
  3789. return;
  3790. pRenderContext->SetFlashlightMode( true );
  3791. for( ;
  3792. flashlightID != m_FlashlightStates.InvalidIndex();
  3793. flashlightID = m_FlashlightStates.Next( flashlightID ) )
  3794. {
  3795. FlashlightInfo_t &flashlightInfo = m_FlashlightStates[flashlightID];
  3796. if ( flashlightInfo.m_nSplitscreenOwner >= 0 )
  3797. {
  3798. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  3799. if ( flashlightInfo.m_nSplitscreenOwner != GET_ACTIVE_SPLITSCREEN_SLOT() )
  3800. continue;
  3801. }
  3802. pRenderContext->SetFlashlightStateEx( flashlightInfo.m_FlashlightState, m_Shadows[flashlightInfo.m_Shadow].m_WorldToShadow, m_Shadows[flashlightInfo.m_Shadow].m_pFlashlightDepthTexture );
  3803. EnableStencilAndScissorMasking( pRenderContext, flashlightInfo, bDoMasking );
  3804. for ( int i = 0; i < listCount; i++ )
  3805. {
  3806. if ( MSurf_Decals(pList[i]) != WORLD_DECAL_HANDLE_INVALID )
  3807. {
  3808. DrawDecalsOnSingleSurface( pRenderContext, pList[i] );
  3809. }
  3810. }
  3811. DisableStencilAndScissorMasking( pRenderContext, flashlightInfo, bDoMasking );
  3812. }
  3813. // Tell the materialsystem that we are finished drawing additive flashlight lighting.
  3814. pRenderContext->SetFlashlightMode( false );
  3815. }
  3816. void CShadowMgr::DrawFlashlightOverlays( IMatRenderContext *pRenderContext, int nSortGroup, bool bDoMasking )
  3817. {
  3818. VPROF_BUDGET( "CShadowMgr::DrawFlashlightOverlays", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  3819. if ( m_bSinglePassFlashlightStateEnabled )
  3820. return;
  3821. FlashlightHandle_t flashlightID = m_FlashlightStates.Head();
  3822. if ( flashlightID == m_FlashlightStates.InvalidIndex() )
  3823. return;
  3824. if ( r_flashlightrender.GetBool()==false )
  3825. return;
  3826. pRenderContext->SetFlashlightMode( true );
  3827. for( ;
  3828. flashlightID != m_FlashlightStates.InvalidIndex();
  3829. flashlightID = m_FlashlightStates.Next( flashlightID ) )
  3830. {
  3831. FlashlightInfo_t &flashlightInfo = m_FlashlightStates[flashlightID];
  3832. if ( flashlightInfo.m_nSplitscreenOwner >= 0 )
  3833. {
  3834. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  3835. if ( flashlightInfo.m_nSplitscreenOwner != GET_ACTIVE_SPLITSCREEN_SLOT() )
  3836. continue;
  3837. }
  3838. pRenderContext->SetFlashlightStateEx( flashlightInfo.m_FlashlightState, m_Shadows[flashlightInfo.m_Shadow].m_WorldToShadow, m_Shadows[flashlightInfo.m_Shadow].m_pFlashlightDepthTexture );
  3839. EnableStencilAndScissorMasking( pRenderContext, flashlightInfo, bDoMasking );
  3840. OverlayMgr()->RenderOverlays( pRenderContext, nSortGroup );
  3841. DisableStencilAndScissorMasking( pRenderContext, flashlightInfo, bDoMasking );
  3842. }
  3843. // Tell the materialsystem that we are finished drawing additive flashlight lighting.
  3844. pRenderContext->SetFlashlightMode( false );
  3845. }
  3846. void CShadowMgr::DrawFlashlightDepthTexture( )
  3847. {
  3848. int i = 0;
  3849. for ( FlashlightHandle_t flashlightID = m_FlashlightStates.Head();
  3850. flashlightID != m_FlashlightStates.InvalidIndex();
  3851. flashlightID = m_FlashlightStates.Next( flashlightID ) ) // Count up the shadows
  3852. {
  3853. FlashlightInfo_t &flashlightInfo = m_FlashlightStates[ flashlightID ];
  3854. if ( flashlightInfo.m_nSplitscreenOwner >= 0 )
  3855. {
  3856. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  3857. if ( flashlightInfo.m_nSplitscreenOwner != GET_ACTIVE_SPLITSCREEN_SLOT() )
  3858. {
  3859. continue;
  3860. }
  3861. }
  3862. if ( m_Shadows[ flashlightInfo.m_Shadow ].m_pFlashlightDepthTexture )
  3863. {
  3864. bool foundVar;
  3865. IMaterial *pMaterial = materials->FindMaterial( "debug/showz", TEXTURE_GROUP_OTHER, true );
  3866. IMaterialVar *BaseTextureVar = pMaterial->FindVar( "$basetexture", &foundVar, false );
  3867. if (!foundVar)
  3868. return;
  3869. IMaterialVar *FrameVar = pMaterial->FindVar( "$frame", &foundVar, false );
  3870. if (!foundVar)
  3871. return;
  3872. float w, h;
  3873. w = h = r_flashlightdrawdepthres.GetFloat();
  3874. float wOffset = (i % 2) * 256.0f; // Even|Odd go left|right
  3875. float hOffset = (i / 2) * 256.0f; // Rows of two
  3876. BaseTextureVar->SetTextureValue( m_Shadows[ flashlightInfo.m_Shadow ].m_pFlashlightDepthTexture );
  3877. FrameVar->SetIntValue( 0 );
  3878. CMatRenderContextPtr pRenderContext( materials );
  3879. pRenderContext->Bind( pMaterial );
  3880. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  3881. CMeshBuilder meshBuilder;
  3882. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  3883. meshBuilder.Position3f( wOffset, hOffset, 0.0f );
  3884. #ifdef DX_TO_GL_ABSTRACTION
  3885. meshBuilder.TexCoord2f( 0, 0.0f, 1.0f ); // Posix is rotated due to render target origin differences
  3886. #else
  3887. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  3888. #endif
  3889. meshBuilder.AdvanceVertexF<VTX_HAVEPOS, 1>();
  3890. meshBuilder.Position3f( wOffset + w, hOffset, 0.0f );
  3891. #ifdef DX_TO_GL_ABSTRACTION
  3892. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  3893. #else
  3894. meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
  3895. #endif
  3896. meshBuilder.AdvanceVertexF<VTX_HAVEPOS, 1>();
  3897. meshBuilder.Position3f( wOffset + w, hOffset + h, 0.0f );
  3898. #ifdef DX_TO_GL_ABSTRACTION
  3899. meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
  3900. #else
  3901. meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
  3902. #endif
  3903. meshBuilder.AdvanceVertexF<VTX_HAVEPOS, 1>();
  3904. meshBuilder.Position3f( wOffset, hOffset + h, 0.0f );
  3905. #ifdef DX_TO_GL_ABSTRACTION
  3906. meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
  3907. #else
  3908. meshBuilder.TexCoord2f( 0, 0.0f, 1.0f );
  3909. #endif
  3910. meshBuilder.AdvanceVertexF<VTX_HAVEPOS, 1>();
  3911. meshBuilder.End();
  3912. pMesh->Draw();
  3913. i++;
  3914. }
  3915. }
  3916. }
  3917. void CShadowMgr::SkipShadowForEntity( int nEntIndex )
  3918. {
  3919. m_nSkipShadowForEntIndex = nEntIndex;
  3920. }