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

3774 lines
132 KiB

  1. //========= Copyright 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 "istudiorender.h"
  20. #include "engine/ivmodelrender.h"
  21. #include "collisionutils.h"
  22. #include "debugoverlay.h"
  23. #include "tier0/vprof.h"
  24. #include "disp.h"
  25. #include "gl_rmain.h"
  26. #include "MaterialBuckets.h"
  27. #include "r_decal.h"
  28. #include "cmodel_engine.h"
  29. #include "iclientrenderable.h"
  30. #include "cdll_engine_int.h"
  31. #include "sys_dll.h"
  32. #include "render.h"
  33. // memdbgon must be the last include file in a .cpp file!!!
  34. #include "tier0/memdbgon.h"
  35. //-----------------------------------------------------------------------------
  36. // Shadow-related functionality exported by the engine
  37. //
  38. // We have two shadow-related caches in this system
  39. // 1) A surface cache. We keep track of which surfaces the shadows can
  40. // potentially hit. The computation of the surface cache should be
  41. // as fast as possible
  42. // 2) A surface vertex cache. Once we know what surfaces the shadow
  43. // hits, we caompute the actual polygons using a clip. This is only
  44. // useful for shadows that we know don't change too frequently, so
  45. // we pass in a flag when making the shadow to indicate whether the
  46. // vertex cache should be used or not. The assumption is that the client
  47. // of this system should know whether the shadows are always changing or not
  48. //
  49. // The first cache is generated when the shadow is initially projected, and
  50. // the second cache is generated when the surfaces are actually being rendered.
  51. //
  52. // For rendering, I assign a sort order ID to all materials used by shadow
  53. // decals. The sort order serves the identical purpose to the material's EnumID
  54. // but I remap those IDs so I can keep a small list of decals to render with
  55. // that enum ID (the other option would be to allocate an array with a number
  56. // of elements == to the number of material enumeration IDs, which is pretty large).
  57. //-----------------------------------------------------------------------------
  58. //-----------------------------------------------------------------------------
  59. // forward decarations
  60. //-----------------------------------------------------------------------------
  61. extern int r_surfacevisframe;
  62. extern IStudioRender *g_pStudioRender;
  63. #define BACKFACE_EPSILON 0.01f
  64. // Max number of vertices per shadow decal
  65. enum
  66. {
  67. SHADOW_VERTEX_SMALL_CACHE_COUNT = 8,
  68. SHADOW_VERTEX_LARGE_CACHE_COUNT = 32,
  69. SHADOW_VERTEX_TEMP_COUNT = 48,
  70. MAX_CLIP_PLANE_COUNT = 4,
  71. SURFACE_BOUNDS_CACHE_COUNT = 1024,
  72. //=============================================================================
  73. // HPE_BEGIN:
  74. // [smessick] Cache size for the shadow decals. This used to be on the stack.
  75. //=============================================================================
  76. SHADOW_DECAL_CACHE_COUNT = 16*1024,
  77. MAX_SHADOW_DECAL_CACHE_COUNT = 64*1024,
  78. //=============================================================================
  79. // HPE_END
  80. //=============================================================================
  81. };
  82. //-----------------------------------------------------------------------------
  83. // Used to clip the shadow decals
  84. //-----------------------------------------------------------------------------
  85. struct ShadowClipState_t
  86. {
  87. int m_CurrVert;
  88. int m_TempCount;
  89. int m_ClipCount;
  90. ShadowVertex_t m_pTempVertices[SHADOW_VERTEX_TEMP_COUNT];
  91. ShadowVertex_t* RESTRICT m_ppClipVertices[2][SHADOW_VERTEX_TEMP_COUNT];
  92. };
  93. //-----------------------------------------------------------------------------
  94. // ConVars (must be defined before CShadowMgr is instanced!)
  95. //-----------------------------------------------------------------------------
  96. ConVar r_shadows("r_shadows", "1");
  97. ConVar r_shadows_gamecontrol("r_shadows_gamecontrol", "-1", FCVAR_CHEAT ); // Shadow override controlled by game entities (shadow_controller)
  98. static ConVar r_shadowwireframe("r_shadowwireframe", "0", FCVAR_CHEAT );
  99. static ConVar r_shadowids("r_shadowids", "0", FCVAR_CHEAT );
  100. static ConVar r_flashlightdrawsweptbbox( "r_flashlightdrawsweptbbox", "0" );
  101. static ConVar r_flashlightdrawfrustumbbox( "r_flashlightdrawfrustumbbox", "0" );
  102. static ConVar r_flashlightnodraw( "r_flashlightnodraw", "0" );
  103. static ConVar r_flashlightupdatedepth( "r_flashlightupdatedepth", "1" );
  104. static ConVar r_flashlightdrawdepth( "r_flashlightdrawdepth", "0" );
  105. static ConVar r_flashlightrenderworld( "r_flashlightrenderworld", "1" );
  106. static ConVar r_flashlightrendermodels( "r_flashlightrendermodels", "1" );
  107. static ConVar r_flashlightrender( "r_flashlightrender", "1" );
  108. static ConVar r_flashlightculldepth( "r_flashlightculldepth", "1" );
  109. ConVar r_flashlight_version2( "r_flashlight_version2", "0", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY );
  110. //-----------------------------------------------------------------------------
  111. // Implementation of IShadowMgr
  112. //-----------------------------------------------------------------------------
  113. class CShadowMgr : public IShadowMgrInternal, ISpatialLeafEnumerator
  114. {
  115. public:
  116. // constructor
  117. CShadowMgr();
  118. // Methods inherited from IShadowMgr
  119. virtual ShadowHandle_t CreateShadow( IMaterial* pMaterial, IMaterial* pModelMaterial, void* pBindProxy, int creationFlags );
  120. virtual ShadowHandle_t CreateShadowEx( IMaterial* pMaterial, IMaterial* pModelMaterial, void* pBindProxy, int creationFlags );
  121. virtual void DestroyShadow( ShadowHandle_t handle );
  122. virtual void SetShadowMaterial( ShadowHandle_t handle, IMaterial* pMaterial, IMaterial* pModelMaterial, void* pBindProxy );
  123. virtual void EnableShadow( ShadowHandle_t handle, bool bEnable );
  124. virtual void ProjectFlashlight( ShadowHandle_t handle, const VMatrix& worldToShadow, int nLeafCount, const int *pLeafList );
  125. virtual void ProjectShadow( ShadowHandle_t handle, const Vector &origin,
  126. const Vector& projectionDir, const VMatrix& worldToShadow, const Vector2D& size,
  127. int nLeafCount, const int *pLeafList,
  128. float maxHeight, float falloffOffset, float falloffAmount, const Vector &vecCasterOrigin );
  129. virtual const Frustum_t &GetFlashlightFrustum( ShadowHandle_t handle );
  130. virtual const FlashlightState_t &GetFlashlightState( ShadowHandle_t handle );
  131. virtual int ProjectAndClipVertices( ShadowHandle_t handle, int count,
  132. Vector** ppPosition, ShadowVertex_t*** ppOutVertex );
  133. virtual void AddShadowToBrushModel( ShadowHandle_t handle, model_t* pModel,
  134. const Vector& origin, const QAngle& angles );
  135. virtual void RemoveAllShadowsFromBrushModel( model_t* pModel );
  136. virtual void AddShadowToModel( ShadowHandle_t shadow, ModelInstanceHandle_t handle );
  137. virtual void RemoveAllShadowsFromModel( ModelInstanceHandle_t handle );
  138. virtual const ShadowInfo_t& GetInfo( ShadowHandle_t handle );
  139. virtual void SetFlashlightRenderState( ShadowHandle_t handle );
  140. // Methods inherited from IShadowMgrInternal
  141. virtual void LevelInit( int nSurfCount );
  142. virtual void LevelShutdown();
  143. virtual void AddShadowsOnSurfaceToRenderList( ShadowDecalHandle_t decalHandle );
  144. virtual void ClearShadowRenderList();
  145. virtual void ComputeRenderInfo( ShadowDecalRenderInfo_t* pInfo, ShadowHandle_t handle ) const;
  146. virtual void SetModelShadowState( ModelInstanceHandle_t instance );
  147. virtual unsigned short InvalidShadowIndex( );
  148. // Methods of ISpatialLeafEnumerator
  149. virtual bool EnumerateLeaf( int leaf, int context );
  150. // Sets the texture coordinate range for a shadow...
  151. virtual void SetShadowTexCoord( ShadowHandle_t handle, float x, float y, float w, float h );
  152. // Set extra clip planes related to shadows...
  153. // These are used to prevent pokethru and back-casting
  154. virtual void ClearExtraClipPlanes( ShadowHandle_t shadow );
  155. virtual void AddExtraClipPlane( ShadowHandle_t shadow, const Vector& normal, float dist );
  156. // Gets the first model associated with a shadow
  157. unsigned short& FirstModelInShadow( ShadowHandle_t h ) { return m_Shadows[h].m_FirstModel; }
  158. // Set the darkness falloff bias
  159. virtual void SetFalloffBias( ShadowHandle_t shadow, unsigned char ucBias );
  160. // Set the number of world material buckets. This should happen exactly once per level load.
  161. virtual void SetNumWorldMaterialBuckets( int numMaterialSortBins );
  162. // Update the state for a flashlight.
  163. virtual void UpdateFlashlightState( ShadowHandle_t shadowHandle, const FlashlightState_t &lightState );
  164. virtual void DrawFlashlightDecals( int sortGroup, bool bDoMasking );
  165. virtual void DrawFlashlightDecalsOnSingleSurface( SurfaceHandle_t surfID, bool bDoMasking );
  166. virtual void DrawFlashlightOverlays( int sortGroup, bool bDoMasking );
  167. virtual void DrawFlashlightDepthTexture( );
  168. virtual void SetFlashlightDepthTexture( ShadowHandle_t shadowHandle, ITexture *pFlashlightDepthTexture, unsigned char ucShadowStencilBit );
  169. virtual void AddFlashlightRenderable( ShadowHandle_t shadow, IClientRenderable *pRenderable );
  170. virtual void DrawFlashlightDecalsOnDisplacements( int sortGroup, CDispInfo **visibleDisps, int nVisibleDisps, bool bDoMasking );
  171. virtual bool ModelHasShadows( ModelInstanceHandle_t instance );
  172. private:
  173. enum
  174. {
  175. SHADOW_DISABLED = (SHADOW_LAST_FLAG << 1),
  176. };
  177. typedef CUtlFixedLinkedList< ShadowDecalHandle_t >::IndexType_t ShadowSurfaceIndex_t;
  178. struct SurfaceBounds_t
  179. {
  180. fltx4 m_vecMins;
  181. fltx4 m_vecMaxs;
  182. Vector m_vecCenter;
  183. float m_flRadius;
  184. int m_nSurfaceIndex;
  185. };
  186. struct ShadowVertexSmallList_t
  187. {
  188. ShadowVertex_t m_Verts[SHADOW_VERTEX_SMALL_CACHE_COUNT];
  189. };
  190. struct ShadowVertexLargeList_t
  191. {
  192. ShadowVertex_t m_Verts[SHADOW_VERTEX_LARGE_CACHE_COUNT];
  193. };
  194. // A cache entries' worth of vertices....
  195. struct ShadowVertexCache_t
  196. {
  197. unsigned short m_Count;
  198. ShadowHandle_t m_Shadow;
  199. unsigned short m_CachedVerts;
  200. ShadowVertex_t* m_pVerts;
  201. };
  202. typedef unsigned short FlashlightHandle_t;
  203. // Shadow state
  204. struct Shadow_t : public ShadowInfo_t
  205. {
  206. Vector m_ProjectionDir;
  207. IMaterial* m_pMaterial; // material for rendering surfaces
  208. IMaterial* m_pModelMaterial; // material for rendering models
  209. void* m_pBindProxy;
  210. unsigned short m_Flags;
  211. unsigned short m_SortOrder;
  212. float m_flSphereRadius; // Radius of sphere surrounding the shadow
  213. Ray_t m_Ray; // NOTE: Ray needs to be on 16-byte boundaries.
  214. Vector m_vecSphereCenter; // Sphere surrounding the shadow
  215. FlashlightHandle_t m_FlashlightHandle;
  216. ITexture *m_pFlashlightDepthTexture;
  217. // Extra clip planes
  218. unsigned short m_ClipPlaneCount;
  219. Vector m_ClipPlane[MAX_CLIP_PLANE_COUNT];
  220. float m_ClipDist[MAX_CLIP_PLANE_COUNT];
  221. // First shadow decal the shadow has
  222. ShadowSurfaceIndex_t m_FirstDecal;
  223. // First model the shadow is projected onto
  224. unsigned short m_FirstModel;
  225. // Stencil bit used to mask this shadow
  226. unsigned char m_ucShadowStencilBit;
  227. };
  228. // Each surface has one of these, they reference the main shadow
  229. // projector and cached off shadow decals.
  230. struct ShadowDecal_t
  231. {
  232. SurfaceHandle_t m_SurfID;
  233. ShadowSurfaceIndex_t m_ShadowListIndex;
  234. ShadowHandle_t m_Shadow;
  235. DispShadowHandle_t m_DispShadow;
  236. unsigned short m_ShadowVerts;
  237. // This is a handle of the next shadow decal to be rendered
  238. ShadowDecalHandle_t m_NextRender;
  239. };
  240. // This structure is used when building new shadow information
  241. struct ShadowBuildInfo_t
  242. {
  243. ShadowHandle_t m_Shadow;
  244. Vector m_RayStart;
  245. Vector m_ProjectionDirection;
  246. Vector m_vecSphereCenter; // Sphere surrounding the shadow
  247. float m_flSphereRadius; // Radius of sphere surrounding the shadow
  248. const byte *m_pVis; // Vis from the ray start
  249. };
  250. // This structure contains rendering information
  251. struct ShadowRenderInfo_t
  252. {
  253. int m_VertexCount;
  254. int m_IndexCount;
  255. int m_nMaxVertices;
  256. int m_nMaxIndices;
  257. int m_Count;
  258. int* m_pCache;
  259. int m_DispCount;
  260. const VMatrix* m_pModelToWorld;
  261. VMatrix m_WorldToModel;
  262. DispShadowHandle_t* m_pDispCache;
  263. };
  264. // Structures used to assign sort order handles
  265. struct SortOrderInfo_t
  266. {
  267. int m_MaterialEnum;
  268. int m_RefCount;
  269. };
  270. typedef void (*ShadowDebugFunc_t)( ShadowHandle_t shadowHandle, const Vector &vecCentroid );
  271. // m_FlashlightWorldMaterialBuckets is where surfaces are stored per flashlight each frame.
  272. typedef CUtlVector<FlashlightHandle_t> WorldMaterialBuckets_t;
  273. struct FlashlightInfo_t
  274. {
  275. FlashlightState_t m_FlashlightState;
  276. unsigned short m_Shadow;
  277. Frustum_t m_Frustum;
  278. CMaterialsBuckets<SurfaceHandle_t> m_MaterialBuckets;
  279. CMaterialsBuckets<SurfaceHandle_t> m_OccluderBuckets;
  280. CUtlVector< IClientRenderable *> m_Renderables;
  281. };
  282. private:
  283. // Applies a flashlight to all surfaces in the leaf
  284. void ApplyFlashlightToLeaf( const Shadow_t &shadow, mleaf_t* pLeaf, ShadowBuildInfo_t* pBuild );
  285. // Applies a shadow to all surfaces in the leaf
  286. void ApplyShadowToLeaf( const Shadow_t &shadow, mleaf_t* RESTRICT pLeaf, ShadowBuildInfo_t* RESTRICT pBuild );
  287. // These functions deal with creation of render sort ids
  288. void SetMaterial( Shadow_t& shadow, IMaterial* pMaterial, IMaterial* pModelMaterial, void* pBindProxy );
  289. void CleanupMaterial( Shadow_t& shadow );
  290. // These functions add/remove shadow decals to surfaces
  291. ShadowDecalHandle_t AddShadowDecalToSurface( SurfaceHandle_t surfID, ShadowHandle_t handle );
  292. void RemoveShadowDecalFromSurface( SurfaceHandle_t surfID, ShadowDecalHandle_t decalHandle );
  293. // Adds the surface to the list for this shadow
  294. bool AddDecalToShadowList( ShadowHandle_t handle, ShadowDecalHandle_t decalHandle );
  295. // Removes the shadow to the list of surfaces
  296. void RemoveDecalFromShadowList( ShadowHandle_t handle, ShadowDecalHandle_t decalHandle );
  297. // Actually projects + clips vertices
  298. int ProjectAndClipVertices( const Shadow_t& shadow, const VMatrix& worldToShadow,
  299. const VMatrix *pWorldToModel, int count, Vector** ppPosition, ShadowVertex_t*** ppOutVertex );
  300. // These functions hook/unhook shadows up to surfaces + vice versa
  301. void AddSurfaceToShadow( ShadowHandle_t handle, SurfaceHandle_t surfID );
  302. void RemoveSurfaceFromShadow( ShadowHandle_t handle, SurfaceHandle_t surfID );
  303. void RemoveAllSurfacesFromShadow( ShadowHandle_t handle );
  304. void RemoveAllShadowsFromSurface( SurfaceHandle_t surfID );
  305. // Deals with model shadow management
  306. void RemoveAllModelsFromShadow( ShadowHandle_t handle );
  307. // Applies the shadow to a surface
  308. void ApplyShadowToSurface( ShadowBuildInfo_t& build, SurfaceHandle_t surfID );
  309. // Applies the shadow to a displacement
  310. void ApplyShadowToDisplacement( ShadowBuildInfo_t& build, IDispInfo *pDispInfo, bool bIsFlashlight );
  311. // Renders shadows that all share a material enumeration
  312. void RenderShadowList( IMatRenderContext *pRenderContext, ShadowDecalHandle_t decalHandle, const VMatrix* pModelToWorld );
  313. // Should we cache vertices?
  314. bool ShouldCacheVertices( const ShadowDecal_t& decal );
  315. // Generates a list displacement shadow vertices to render
  316. bool GenerateDispShadowRenderInfo( IMatRenderContext *pRenderContext, ShadowDecal_t& decal, ShadowRenderInfo_t& info );
  317. // Generates a list shadow vertices to render
  318. bool GenerateNormalShadowRenderInfo( IMatRenderContext *pRenderContext, ShadowDecal_t& decal, ShadowRenderInfo_t& info );
  319. // Adds normal shadows to the mesh builder
  320. int AddNormalShadowsToMeshBuilder( CMeshBuilder& meshBuilder, ShadowRenderInfo_t& info );
  321. // Adds displacement shadows to the mesh builder
  322. int AddDisplacementShadowsToMeshBuilder( CMeshBuilder& meshBuilder,
  323. ShadowRenderInfo_t& info, int baseIndex );
  324. // Does the actual work of computing shadow vertices
  325. bool ComputeShadowVertices( ShadowDecal_t& decal, const VMatrix* pModelToWorld, const VMatrix* pWorldToModel, ShadowVertexCache_t* pVertexCache );
  326. // Project vertices into shadow space
  327. bool ProjectVerticesIntoShadowSpace( const VMatrix& modelToShadow,
  328. float maxDist, int count, Vector** RESTRICT ppPosition, ShadowClipState_t& clip );
  329. // Copies vertex info from the clipped vertices
  330. void CopyClippedVertices( int count, ShadowVertex_t** ppSrcVert, ShadowVertex_t* pDstVert, const Vector &vToAdd );
  331. // Allocate, free vertices
  332. ShadowVertex_t* AllocateVertices( ShadowVertexCache_t& cache, int count );
  333. void FreeVertices( ShadowVertexCache_t& cache );
  334. // Gets at cache entry...
  335. ShadowVertex_t* GetCachedVerts( const ShadowVertexCache_t& cache );
  336. // Clears out vertices in the temporary cache
  337. void ClearTempCache( );
  338. // Renders debugging information
  339. void RenderDebuggingInfo( const ShadowRenderInfo_t &info, ShadowDebugFunc_t func );
  340. // Methods for dealing with world material buckets for flashlights.
  341. void ClearAllFlashlightMaterialBuckets( void );
  342. void AddSurfaceToFlashlightMaterialBuckets( ShadowHandle_t handle, SurfaceHandle_t surfID );
  343. void AllocFlashlightMaterialBuckets( FlashlightHandle_t flashlightID );
  344. // Render all projected textures (including shadows and flashlights)
  345. void RenderProjectedTextures( const VMatrix* pModelToWorld );
  346. void RenderFlashlights( bool bDoMasking, const VMatrix* pModelToWorld );
  347. void SetFlashlightStencilMasks( bool bDoMasking );
  348. void SetStencilAndScissor( IMatRenderContext *pRenderContext, FlashlightInfo_t &flashlightInfo, bool bUseStencil );
  349. void EnableStencilAndScissorMasking( IMatRenderContext *pRenderContext, const FlashlightInfo_t &flashlightInfo, bool bDoMasking );
  350. void DisableStencilAndScissorMasking( IMatRenderContext *pRenderContext );
  351. void RenderShadows( const VMatrix* pModelToWorld );
  352. // Generates a list shadow vertices to render
  353. void GenerateShadowRenderInfo( IMatRenderContext *pRenderContext, ShadowDecalHandle_t decalHandle, ShadowRenderInfo_t& info );
  354. // Methods related to the surface bounds cache
  355. void ComputeSurfaceBounds( SurfaceBounds_t* pBounds, SurfaceHandle_t nSurfID );
  356. const SurfaceBounds_t* GetSurfaceBounds( SurfaceHandle_t nSurfID );
  357. bool IsShadowNearSurface( ShadowHandle_t h, SurfaceHandle_t nSurfID, const VMatrix* pModelToWorld, const VMatrix* pWorldToModel );
  358. private:
  359. // List of all shadows (one per cast shadow)
  360. // Align it so the Ray in the Shadow_t is aligned
  361. CUtlLinkedList< Shadow_t, ShadowHandle_t, false, int, CUtlMemoryAligned< UtlLinkedListElem_t< Shadow_t, ShadowHandle_t >, 16 > > m_Shadows;
  362. // List of all shadow decals (one per surface hit by a shadow)
  363. CUtlLinkedList< ShadowDecal_t, ShadowDecalHandle_t, true, int > m_ShadowDecals;
  364. // List of all shadow decals associated with a particular shadow
  365. CUtlFixedLinkedList< ShadowDecalHandle_t > m_ShadowSurfaces;
  366. // List of queued decals waiting to be rendered....
  367. CUtlVector<ShadowDecalHandle_t> m_RenderQueue;
  368. // Used to assign sort order handles
  369. CUtlLinkedList<SortOrderInfo_t, unsigned short> m_SortOrderIds;
  370. // A cache of shadow vertex data...
  371. CUtlLinkedList<ShadowVertexCache_t, unsigned short> m_VertexCache;
  372. // This is temporary, not saved off....
  373. CUtlVector<ShadowVertexCache_t> m_TempVertexCache;
  374. // Vertex data
  375. CUtlLinkedList<ShadowVertexSmallList_t, unsigned short> m_SmallVertexList;
  376. CUtlLinkedList<ShadowVertexLargeList_t, unsigned short> m_LargeVertexList;
  377. // Model-shadow association
  378. CBidirectionalSet< ModelInstanceHandle_t, ShadowHandle_t, unsigned short > m_ShadowsOnModels;
  379. // Cache of information for surface bounds
  380. typedef CUtlLinkedList< SurfaceBounds_t, unsigned short, false, int, CUtlMemoryFixed< UtlLinkedListElem_t< SurfaceBounds_t, unsigned short >, SURFACE_BOUNDS_CACHE_COUNT, 16 > > SurfaceBoundsCache_t;
  381. typedef SurfaceBoundsCache_t::IndexType_t SurfaceBoundsCacheIndex_t;
  382. SurfaceBoundsCache_t m_SurfaceBoundsCache;
  383. SurfaceBoundsCacheIndex_t *m_pSurfaceBounds;
  384. // The number of decals we're gonna need to render
  385. int m_DecalsToRender;
  386. CUtlLinkedList<FlashlightInfo_t> m_FlashlightStates;
  387. int m_NumWorldMaterialBuckets;
  388. bool m_bInitialized;
  389. //=============================================================================
  390. // HPE_BEGIN:
  391. // [smessick] These used to be dynamically allocated on the stack.
  392. //=============================================================================
  393. CUtlMemory<int> m_ShadowDecalCache;
  394. CUtlMemory<DispShadowHandle_t> m_DispShadowDecalCache;
  395. //=============================================================================
  396. // HPE_END
  397. //=============================================================================
  398. };
  399. //-----------------------------------------------------------------------------
  400. // Singleton
  401. //-----------------------------------------------------------------------------
  402. static CShadowMgr s_ShadowMgr;
  403. IShadowMgrInternal* g_pShadowMgr = &s_ShadowMgr;
  404. EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CShadowMgr, IShadowMgr,
  405. ENGINE_SHADOWMGR_INTERFACE_VERSION, s_ShadowMgr);
  406. //-----------------------------------------------------------------------------
  407. // Shadows on model instances
  408. //-----------------------------------------------------------------------------
  409. unsigned short& FirstShadowOnModel( ModelInstanceHandle_t h )
  410. {
  411. // See l_studio.cpp
  412. return FirstShadowOnModelInstance( h );
  413. }
  414. unsigned short& FirstModelInShadow( ShadowHandle_t h )
  415. {
  416. return s_ShadowMgr.FirstModelInShadow(h);
  417. }
  418. //-----------------------------------------------------------------------------
  419. // Constructor, destructor
  420. //-----------------------------------------------------------------------------
  421. CShadowMgr::CShadowMgr()
  422. {
  423. m_ShadowSurfaces.SetGrowSize( 4096 );
  424. m_ShadowDecals.SetGrowSize( 4096 );
  425. m_ShadowsOnModels.Init( ::FirstShadowOnModel, ::FirstModelInShadow );
  426. m_NumWorldMaterialBuckets = 0;
  427. m_pSurfaceBounds = NULL;
  428. m_bInitialized = false;
  429. ClearShadowRenderList();
  430. //=============================================================================
  431. // HPE_BEGIN:
  432. // [smessick] Initialize the shadow decal caches. These used to be dynamically
  433. // allocated on the stack, but we were getting stack overflows.
  434. //=============================================================================
  435. m_ShadowDecalCache.SetGrowSize( 4096 );
  436. m_DispShadowDecalCache.SetGrowSize( 4096 );
  437. m_ShadowDecalCache.Grow( SHADOW_DECAL_CACHE_COUNT );
  438. m_DispShadowDecalCache.Grow( SHADOW_DECAL_CACHE_COUNT );
  439. //=============================================================================
  440. // HPE_END
  441. //=============================================================================
  442. }
  443. //-----------------------------------------------------------------------------
  444. // Level init, shutdown
  445. //-----------------------------------------------------------------------------
  446. void CShadowMgr::LevelInit( int nSurfCount )
  447. {
  448. if ( m_bInitialized )
  449. return;
  450. m_bInitialized = true;
  451. m_pSurfaceBounds = new SurfaceBoundsCacheIndex_t[nSurfCount];
  452. // NOTE: Need to memset to 0 if we switch to integer SurfaceBoundsCacheIndex_t here
  453. COMPILE_TIME_ASSERT( sizeof(SurfaceBoundsCacheIndex_t) == 2 );
  454. memset( m_pSurfaceBounds, 0xFF, nSurfCount * sizeof(SurfaceBoundsCacheIndex_t) );
  455. }
  456. void CShadowMgr::LevelShutdown()
  457. {
  458. if ( !m_bInitialized )
  459. return;
  460. if ( m_pSurfaceBounds )
  461. {
  462. delete[] m_pSurfaceBounds;
  463. m_pSurfaceBounds = NULL;
  464. }
  465. m_SurfaceBoundsCache.RemoveAll();
  466. m_bInitialized = false;
  467. }
  468. //-----------------------------------------------------------------------------
  469. // Create, destroy material sort order ids...
  470. //-----------------------------------------------------------------------------
  471. void CShadowMgr::SetMaterial( Shadow_t& shadow, IMaterial* pMaterial, IMaterial* pModelMaterial, void *pBindProxy )
  472. {
  473. shadow.m_pMaterial = pMaterial;
  474. shadow.m_pModelMaterial = pModelMaterial;
  475. shadow.m_pBindProxy = pBindProxy;
  476. // We're holding onto this material
  477. if ( pMaterial )
  478. {
  479. pMaterial->IncrementReferenceCount();
  480. }
  481. if ( pModelMaterial )
  482. {
  483. pModelMaterial->IncrementReferenceCount();
  484. }
  485. // Search the sort order handles for an enumeration id match
  486. int materialEnum = (int)pMaterial;
  487. for (unsigned short i = m_SortOrderIds.Head(); i != m_SortOrderIds.InvalidIndex();
  488. i = m_SortOrderIds.Next(i) )
  489. {
  490. // Found a match, lets increment the refcount of this sort order id
  491. if (m_SortOrderIds[i].m_MaterialEnum == materialEnum)
  492. {
  493. ++m_SortOrderIds[i].m_RefCount;
  494. shadow.m_SortOrder = i;
  495. return;
  496. }
  497. }
  498. // Didn't find it, lets assign a new sort order ID, with a refcount of 1
  499. shadow.m_SortOrder = m_SortOrderIds.AddToTail();
  500. m_SortOrderIds[shadow.m_SortOrder].m_MaterialEnum = materialEnum;
  501. m_SortOrderIds[shadow.m_SortOrder].m_RefCount = 1;
  502. // Make sure the render queue has as many entries as the max sort order id.
  503. int count = m_RenderQueue.Count();
  504. while( count < m_SortOrderIds.MaxElementIndex() )
  505. {
  506. MEM_ALLOC_CREDIT();
  507. m_RenderQueue.AddToTail( SHADOW_DECAL_HANDLE_INVALID );
  508. ++count;
  509. }
  510. }
  511. void CShadowMgr::CleanupMaterial( Shadow_t& shadow )
  512. {
  513. // Decrease the sort order reference count
  514. if (--m_SortOrderIds[shadow.m_SortOrder].m_RefCount <= 0)
  515. {
  516. // No one referencing the sort order number?
  517. // Then lets clean up the sort order id
  518. m_SortOrderIds.Remove(shadow.m_SortOrder);
  519. }
  520. // We're done with this material
  521. if ( shadow.m_pMaterial )
  522. {
  523. shadow.m_pMaterial->DecrementReferenceCount();
  524. }
  525. if ( shadow.m_pModelMaterial )
  526. {
  527. shadow.m_pModelMaterial->DecrementReferenceCount();
  528. }
  529. }
  530. //-----------------------------------------------------------------------------
  531. // For the model shadow list
  532. //-----------------------------------------------------------------------------
  533. unsigned short CShadowMgr::InvalidShadowIndex( )
  534. {
  535. return m_ShadowsOnModels.InvalidIndex();
  536. }
  537. //-----------------------------------------------------------------------------
  538. // Create, destroy shadows
  539. //-----------------------------------------------------------------------------
  540. ShadowHandle_t CShadowMgr::CreateShadow( IMaterial* pMaterial, IMaterial* pModelMaterial, void* pBindProxy, int creationFlags )
  541. {
  542. return CreateShadowEx( pMaterial, pModelMaterial, pBindProxy, creationFlags );
  543. }
  544. ShadowHandle_t CShadowMgr::CreateShadowEx( IMaterial* pMaterial, IMaterial* pModelMaterial, void* pBindProxy, int creationFlags )
  545. {
  546. #ifndef SWDS
  547. ShadowHandle_t h = m_Shadows.AddToTail();
  548. //=============================================================================
  549. // HPE_BEGIN:
  550. // [smessick] Check for overflow.
  551. //=============================================================================
  552. if ( h == m_Shadows.InvalidIndex() )
  553. {
  554. ExecuteNTimes( 10, Warning( "CShadowMgr::CreateShadowEx - overflowed m_Shadows linked list!\n" ) );
  555. return h;
  556. }
  557. //=============================================================================
  558. // HPE_END
  559. //=============================================================================
  560. Shadow_t& shadow = m_Shadows[h];
  561. SetMaterial( shadow, pMaterial, pModelMaterial, pBindProxy );
  562. shadow.m_Flags = creationFlags;
  563. shadow.m_FirstDecal = m_ShadowSurfaces.InvalidIndex();
  564. shadow.m_FirstModel = m_ShadowsOnModels.InvalidIndex();
  565. shadow.m_ProjectionDir.Init( 0, 0, 1 );
  566. shadow.m_TexOrigin.Init( 0, 0 );
  567. shadow.m_TexSize.Init( 1, 1 );
  568. shadow.m_ClipPlaneCount = 0;
  569. shadow.m_FalloffBias = 0;
  570. shadow.m_pFlashlightDepthTexture = NULL;
  571. shadow.m_FlashlightHandle = m_FlashlightStates.InvalidIndex();
  572. if ( ( creationFlags & SHADOW_FLASHLIGHT ) != 0 )
  573. {
  574. shadow.m_FlashlightHandle = m_FlashlightStates.AddToTail();
  575. m_FlashlightStates[shadow.m_FlashlightHandle].m_Shadow = h;
  576. if ( !IsX360() && !r_flashlight_version2.GetInt() )
  577. {
  578. AllocFlashlightMaterialBuckets( shadow.m_FlashlightHandle );
  579. }
  580. }
  581. MatrixSetIdentity( shadow.m_WorldToShadow );
  582. return h;
  583. #endif
  584. }
  585. void CShadowMgr::DestroyShadow( ShadowHandle_t handle )
  586. {
  587. CleanupMaterial( m_Shadows[handle] );
  588. RemoveAllSurfacesFromShadow( handle );
  589. RemoveAllModelsFromShadow( handle );
  590. if( m_Shadows[handle].m_FlashlightHandle != m_FlashlightStates.InvalidIndex() )
  591. {
  592. m_FlashlightStates.Remove( m_Shadows[handle].m_FlashlightHandle );
  593. }
  594. m_Shadows.Remove(handle);
  595. }
  596. //-----------------------------------------------------------------------------
  597. // Resets the shadow material (useful for shadow LOD.. doing blobby at distance)
  598. //-----------------------------------------------------------------------------
  599. void CShadowMgr::SetShadowMaterial( ShadowHandle_t handle, IMaterial* pMaterial, IMaterial* pModelMaterial, void* pBindProxy )
  600. {
  601. Shadow_t& shadow = m_Shadows[handle];
  602. if ( (shadow.m_pMaterial != pMaterial) || (shadow.m_pModelMaterial != pModelMaterial) || (shadow.m_pBindProxy != pBindProxy) )
  603. {
  604. CleanupMaterial( shadow );
  605. SetMaterial( shadow, pMaterial, pModelMaterial, pBindProxy );
  606. }
  607. }
  608. //-----------------------------------------------------------------------------
  609. // Sets the texture coordinate range for a shadow...
  610. //-----------------------------------------------------------------------------
  611. void CShadowMgr::SetShadowTexCoord( ShadowHandle_t handle, float x, float y, float w, float h )
  612. {
  613. Shadow_t& shadow = m_Shadows[handle];
  614. shadow.m_TexOrigin.Init( x, y );
  615. shadow.m_TexSize.Init( w, h );
  616. }
  617. //-----------------------------------------------------------------------------
  618. // Set extra clip planes related to shadows...
  619. //-----------------------------------------------------------------------------
  620. void CShadowMgr::ClearExtraClipPlanes( ShadowHandle_t h )
  621. {
  622. m_Shadows[h].m_ClipPlaneCount = 0;
  623. }
  624. void CShadowMgr::AddExtraClipPlane( ShadowHandle_t h, const Vector& normal, float dist )
  625. {
  626. Shadow_t& shadow = m_Shadows[h];
  627. Assert( shadow.m_ClipPlaneCount < MAX_CLIP_PLANE_COUNT );
  628. VectorCopy( normal, shadow.m_ClipPlane[shadow.m_ClipPlaneCount] );
  629. shadow.m_ClipDist[shadow.m_ClipPlaneCount] = dist;
  630. ++shadow.m_ClipPlaneCount;
  631. }
  632. //-----------------------------------------------------------------------------
  633. // Gets at information about a particular shadow
  634. //-----------------------------------------------------------------------------
  635. const ShadowInfo_t& CShadowMgr::GetInfo( ShadowHandle_t handle )
  636. {
  637. return m_Shadows[handle];
  638. }
  639. //-----------------------------------------------------------------------------
  640. // Gets at cache entry...
  641. //-----------------------------------------------------------------------------
  642. ShadowVertex_t* CShadowMgr::GetCachedVerts( const ShadowVertexCache_t& cache )
  643. {
  644. if (cache.m_Count == 0)
  645. return 0 ;
  646. if (cache.m_pVerts)
  647. return cache.m_pVerts;
  648. if (cache.m_Count <= SHADOW_VERTEX_SMALL_CACHE_COUNT)
  649. return m_SmallVertexList[cache.m_CachedVerts].m_Verts;
  650. return m_LargeVertexList[cache.m_CachedVerts].m_Verts;
  651. }
  652. //-----------------------------------------------------------------------------
  653. // Allocates, cleans up vertex cache vertices
  654. //-----------------------------------------------------------------------------
  655. inline ShadowVertex_t* CShadowMgr::AllocateVertices( ShadowVertexCache_t& cache, int count )
  656. {
  657. cache.m_pVerts = 0;
  658. if (count <= SHADOW_VERTEX_SMALL_CACHE_COUNT)
  659. {
  660. cache.m_Count = count;
  661. cache.m_CachedVerts = m_SmallVertexList.AddToTail( );
  662. return m_SmallVertexList[cache.m_CachedVerts].m_Verts;
  663. }
  664. else if (count <= SHADOW_VERTEX_LARGE_CACHE_COUNT)
  665. {
  666. cache.m_Count = count;
  667. cache.m_CachedVerts = m_LargeVertexList.AddToTail( );
  668. return m_LargeVertexList[cache.m_CachedVerts].m_Verts;
  669. }
  670. cache.m_Count = count;
  671. if (count > 0)
  672. {
  673. cache.m_pVerts = new ShadowVertex_t[count];
  674. }
  675. cache.m_CachedVerts = m_LargeVertexList.InvalidIndex();
  676. return cache.m_pVerts;
  677. }
  678. inline void CShadowMgr::FreeVertices( ShadowVertexCache_t& cache )
  679. {
  680. if (cache.m_Count == 0)
  681. return;
  682. if (cache.m_pVerts)
  683. {
  684. delete[] cache.m_pVerts;
  685. }
  686. else if (cache.m_Count <= SHADOW_VERTEX_SMALL_CACHE_COUNT)
  687. {
  688. m_SmallVertexList.Remove( cache.m_CachedVerts );
  689. }
  690. else
  691. {
  692. m_LargeVertexList.Remove( cache.m_CachedVerts );
  693. }
  694. }
  695. //-----------------------------------------------------------------------------
  696. // Clears out vertices in the temporary cache
  697. //-----------------------------------------------------------------------------
  698. void CShadowMgr::ClearTempCache( )
  699. {
  700. // Clear out the vertices
  701. for (int i = m_TempVertexCache.Count(); --i >= 0; )
  702. {
  703. FreeVertices( m_TempVertexCache[i] );
  704. }
  705. m_TempVertexCache.RemoveAll();
  706. }
  707. //-----------------------------------------------------------------------------
  708. // Adds the surface to the list for this shadow
  709. //-----------------------------------------------------------------------------
  710. bool CShadowMgr::AddDecalToShadowList( ShadowHandle_t handle, ShadowDecalHandle_t decalHandle )
  711. {
  712. // Add the shadow to the list of surfaces affected by this shadow
  713. ShadowSurfaceIndex_t idx = m_ShadowSurfaces.Alloc( true );
  714. if ( idx == m_ShadowSurfaces.InvalidIndex() )
  715. {
  716. ExecuteNTimes( 10, Warning( "CShadowMgr::AddDecalToShadowList - overflowed m_ShadowSurfaces linked list!\n" ) );
  717. return false;
  718. }
  719. m_ShadowSurfaces[idx] = decalHandle;
  720. if ( m_Shadows[handle].m_FirstDecal != m_ShadowSurfaces.InvalidIndex() )
  721. {
  722. m_ShadowSurfaces.LinkBefore( m_Shadows[handle].m_FirstDecal, idx );
  723. }
  724. m_Shadows[handle].m_FirstDecal = idx;
  725. m_ShadowDecals[decalHandle].m_ShadowListIndex = idx;
  726. return true;
  727. }
  728. //-----------------------------------------------------------------------------
  729. // Removes the shadow to the list of surfaces
  730. //-----------------------------------------------------------------------------
  731. void CShadowMgr::RemoveDecalFromShadowList( ShadowHandle_t handle, ShadowDecalHandle_t decalHandle )
  732. {
  733. ShadowSurfaceIndex_t idx = m_ShadowDecals[decalHandle].m_ShadowListIndex;
  734. // Make sure the list of shadow decals for a single shadow is ok
  735. if ( m_Shadows[handle].m_FirstDecal == idx )
  736. {
  737. m_Shadows[handle].m_FirstDecal = m_ShadowSurfaces.Next(idx);
  738. }
  739. // Remove it from the shadow surfaces list
  740. m_ShadowSurfaces.Free(idx);
  741. // Blat out the decal index
  742. m_ShadowDecals[decalHandle].m_ShadowListIndex = m_ShadowSurfaces.InvalidIndex();
  743. }
  744. //-----------------------------------------------------------------------------
  745. // Computes spherical bounds for a surface
  746. //-----------------------------------------------------------------------------
  747. void CShadowMgr::ComputeSurfaceBounds( SurfaceBounds_t* pBounds, SurfaceHandle_t nSurfID )
  748. {
  749. pBounds->m_vecCenter.Init();
  750. pBounds->m_vecMins = ReplicateX4( FLT_MAX );
  751. pBounds->m_vecMaxs = ReplicateX4( -FLT_MAX );
  752. int nCount = MSurf_VertCount( nSurfID );
  753. for ( int i = 0; i < nCount; ++i )
  754. {
  755. int nVertIndex = host_state.worldbrush->vertindices[ MSurf_FirstVertIndex( nSurfID ) + i ];
  756. const Vector &position = host_state.worldbrush->vertexes[ nVertIndex ].position;
  757. pBounds->m_vecCenter += position;
  758. fltx4 pos4 = LoadUnaligned3SIMD( position.Base() );
  759. pBounds->m_vecMins = MinSIMD( pos4, pBounds->m_vecMins );
  760. pBounds->m_vecMaxs = MaxSIMD( pos4, pBounds->m_vecMaxs );
  761. }
  762. fltx4 eps = ReplicateX4( 1e-3 );
  763. pBounds->m_vecMins = SetWToZeroSIMD( SubSIMD( pBounds->m_vecMins, eps ) );
  764. pBounds->m_vecMaxs = SetWToZeroSIMD( AddSIMD( pBounds->m_vecMaxs, eps ) );
  765. pBounds->m_vecCenter /= nCount;
  766. pBounds->m_flRadius = 0.0f;
  767. for ( int i = 0; i < nCount; ++i )
  768. {
  769. int nVertIndex = host_state.worldbrush->vertindices[ MSurf_FirstVertIndex( nSurfID ) + i ];
  770. const Vector &position = host_state.worldbrush->vertexes[ nVertIndex ].position;
  771. float flDistSq = position.DistToSqr( pBounds->m_vecCenter );
  772. if ( flDistSq > pBounds->m_flRadius )
  773. {
  774. pBounds->m_flRadius = flDistSq;
  775. }
  776. }
  777. pBounds->m_flRadius = sqrt( pBounds->m_flRadius );
  778. }
  779. //-----------------------------------------------------------------------------
  780. // Get spherical bounds for a surface
  781. //-----------------------------------------------------------------------------
  782. const CShadowMgr::SurfaceBounds_t* CShadowMgr::GetSurfaceBounds( SurfaceHandle_t surfID )
  783. {
  784. int nSurfaceIndex = MSurf_Index( surfID );
  785. // NOTE: We're not bumping the surface index to the front of the LRU
  786. // here, but I think if we did the cost doing that would exceed the cost
  787. // of anything else in this path.
  788. // If this turns out to not be true, then we should make this a true LRU
  789. if ( m_pSurfaceBounds[nSurfaceIndex] != m_SurfaceBoundsCache.InvalidIndex() )
  790. return &m_SurfaceBoundsCache[ m_pSurfaceBounds[nSurfaceIndex] ];
  791. SurfaceBoundsCacheIndex_t nIndex;
  792. if ( m_SurfaceBoundsCache.Count() >= SURFACE_BOUNDS_CACHE_COUNT )
  793. {
  794. // Retire existing cache entry if we're out of space,
  795. // move it to the head of the LRU cache
  796. nIndex = m_SurfaceBoundsCache.Tail( );
  797. m_SurfaceBoundsCache.Unlink( nIndex );
  798. m_SurfaceBoundsCache.LinkToHead( nIndex );
  799. m_pSurfaceBounds[ m_SurfaceBoundsCache[nIndex].m_nSurfaceIndex ] = m_SurfaceBoundsCache.InvalidIndex();
  800. }
  801. else
  802. {
  803. // Allocate new cache entry if we have more room
  804. nIndex = m_SurfaceBoundsCache.AddToHead( );
  805. }
  806. m_pSurfaceBounds[ nSurfaceIndex ] = nIndex;
  807. // Computes the surface bounds
  808. SurfaceBounds_t &bounds = m_SurfaceBoundsCache[nIndex];
  809. bounds.m_nSurfaceIndex = nSurfaceIndex;
  810. ComputeSurfaceBounds( &bounds, surfID );
  811. return &bounds;
  812. }
  813. //-----------------------------------------------------------------------------
  814. // Is the shadow near the surface?
  815. //-----------------------------------------------------------------------------
  816. bool CShadowMgr::IsShadowNearSurface( ShadowHandle_t h, SurfaceHandle_t nSurfID,
  817. const VMatrix* pModelToWorld, const VMatrix* pWorldToModel )
  818. {
  819. const Shadow_t &shadow = m_Shadows[h];
  820. const SurfaceBounds_t* pBounds = GetSurfaceBounds( nSurfID );
  821. Vector vecSurfCenter;
  822. if ( !pModelToWorld )
  823. {
  824. vecSurfCenter = pBounds->m_vecCenter;
  825. }
  826. else
  827. {
  828. Vector3DMultiplyPosition( *pModelToWorld, pBounds->m_vecCenter, vecSurfCenter );
  829. }
  830. // Sphere check
  831. Vector vecDelta;
  832. VectorSubtract( shadow.m_vecSphereCenter, vecSurfCenter, vecDelta );
  833. float flDistSqr = vecDelta.LengthSqr();
  834. float flMinDistSqr = pBounds->m_flRadius + shadow.m_flSphereRadius;
  835. flMinDistSqr *= flMinDistSqr;
  836. if ( flDistSqr >= flMinDistSqr )
  837. return false;
  838. if ( !pModelToWorld )
  839. return IsBoxIntersectingRay( pBounds->m_vecMins, pBounds->m_vecMaxs, shadow.m_Ray );
  840. Ray_t transformedRay;
  841. Vector3DMultiplyPosition( *pWorldToModel, shadow.m_Ray.m_Start, transformedRay.m_Start );
  842. Vector3DMultiply( *pWorldToModel, shadow.m_Ray.m_Delta, transformedRay.m_Delta );
  843. transformedRay.m_StartOffset = shadow.m_Ray.m_StartOffset;
  844. transformedRay.m_Extents = shadow.m_Ray.m_Extents;
  845. transformedRay.m_IsRay = shadow.m_Ray.m_IsRay;
  846. transformedRay.m_IsSwept = shadow.m_Ray.m_IsSwept;
  847. return IsBoxIntersectingRay( pBounds->m_vecMins, pBounds->m_vecMaxs, transformedRay );
  848. }
  849. //-----------------------------------------------------------------------------
  850. // Adds the shadow decal reference to the surface
  851. //-----------------------------------------------------------------------------
  852. inline ShadowDecalHandle_t CShadowMgr::AddShadowDecalToSurface( SurfaceHandle_t surfID, ShadowHandle_t handle )
  853. {
  854. ShadowDecalHandle_t decalHandle = m_ShadowDecals.Alloc( true );
  855. if ( decalHandle == m_ShadowDecals.InvalidIndex() )
  856. {
  857. ExecuteNTimes( 10, Warning( "CShadowMgr::AddShadowDecalToSurface - overflowed m_ShadowDecals linked list!\n" ) );
  858. return decalHandle;
  859. }
  860. ShadowDecal_t& decal = m_ShadowDecals[decalHandle];
  861. decal.m_SurfID = surfID;
  862. m_ShadowDecals.LinkBefore( MSurf_ShadowDecals( surfID ), decalHandle );
  863. MSurf_ShadowDecals( surfID ) = decalHandle;
  864. // Hook the shadow into the displacement system....
  865. if ( !SurfaceHasDispInfo( surfID ) )
  866. {
  867. decal.m_DispShadow = DISP_SHADOW_HANDLE_INVALID;
  868. }
  869. else
  870. {
  871. decal.m_DispShadow = MSurf_DispInfo( surfID )->AddShadowDecal( handle );
  872. }
  873. decal.m_Shadow = handle;
  874. decal.m_ShadowVerts = m_VertexCache.InvalidIndex();
  875. decal.m_NextRender = SHADOW_DECAL_HANDLE_INVALID;
  876. decal.m_ShadowListIndex = m_ShadowSurfaces.InvalidIndex();
  877. //=============================================================================
  878. // HPE_BEGIN:
  879. // [smessick] Check the return value of AddDecalToShadowList and make sure
  880. // to delete the newly created shadow decal if there is a failure.
  881. //=============================================================================
  882. if ( !AddDecalToShadowList( handle, decalHandle ) )
  883. {
  884. m_ShadowDecals.Free( decalHandle );
  885. decalHandle = m_ShadowDecals.InvalidIndex();
  886. }
  887. //=============================================================================
  888. // HPE_END
  889. //=============================================================================
  890. return decalHandle;
  891. }
  892. inline void CShadowMgr::RemoveShadowDecalFromSurface( SurfaceHandle_t surfID, ShadowDecalHandle_t decalHandle )
  893. {
  894. // Clean up its shadow verts if it has any
  895. ShadowDecal_t& decal = m_ShadowDecals[decalHandle];
  896. if (decal.m_ShadowVerts != m_VertexCache.InvalidIndex())
  897. {
  898. FreeVertices( m_VertexCache[decal.m_ShadowVerts] );
  899. m_VertexCache.Remove(decal.m_ShadowVerts);
  900. decal.m_ShadowVerts = m_VertexCache.InvalidIndex();
  901. }
  902. // Clean up displacement...
  903. if ( decal.m_DispShadow != DISP_SHADOW_HANDLE_INVALID )
  904. {
  905. MSurf_DispInfo( decal.m_SurfID )->RemoveShadowDecal( decal.m_DispShadow );
  906. }
  907. // Make sure the list of shadow decals on a surface is set up correctly
  908. if ( MSurf_ShadowDecals( surfID ) == decalHandle )
  909. {
  910. MSurf_ShadowDecals( surfID ) = m_ShadowDecals.Next(decalHandle);
  911. }
  912. RemoveDecalFromShadowList( decal.m_Shadow, decalHandle );
  913. // Kill the shadow decal
  914. m_ShadowDecals.Free( decalHandle );
  915. }
  916. void CShadowMgr::AddSurfaceToFlashlightMaterialBuckets( ShadowHandle_t handle, SurfaceHandle_t surfID )
  917. {
  918. // Make sure that this is a flashlight.
  919. Assert( m_Shadows[handle].m_Flags & SHADOW_FLASHLIGHT );
  920. // Get the flashlight id for this particular shadow handle and make sure that it's valid.
  921. FlashlightHandle_t flashlightID = m_Shadows[handle].m_FlashlightHandle;
  922. Assert( flashlightID != m_FlashlightStates.InvalidIndex() );
  923. m_FlashlightStates[flashlightID].m_MaterialBuckets.AddElement( MSurf_MaterialSortID( surfID ), surfID );
  924. }
  925. //-----------------------------------------------------------------------------
  926. // Adds the shadow decal reference to the surface
  927. // This causes a shadow decal to be made
  928. //-----------------------------------------------------------------------------
  929. void CShadowMgr::AddSurfaceToShadow( ShadowHandle_t handle, SurfaceHandle_t surfID )
  930. {
  931. // FIXME: We could make this work, but there's a perf cost...
  932. // Basically, we'd need to have a separate rendering batch for
  933. // each translucent material the shadow is projected onto. The
  934. // material alpha would have to be taken into account, so that
  935. // no multiplication occurs where the alpha == 0
  936. // FLASHLIGHTFIXME: get rid of some of these checks for the ones that will work just fine with the flashlight.
  937. bool bIsFlashlight = ( ( m_Shadows[handle].m_Flags & SHADOW_FLASHLIGHT ) != 0 );
  938. if ( !bIsFlashlight && MSurf_Flags(surfID) & (SURFDRAW_TRANS | SURFDRAW_ALPHATEST | SURFDRAW_NOSHADOWS) )
  939. return;
  940. #ifdef _XBOX
  941. // Don't let the flashlight get on water on XBox
  942. if ( bIsFlashlight && ( MSurf_Flags(surfID) & SURFDRAW_WATERSURFACE ) )
  943. return;
  944. #endif
  945. #if 0
  946. // Make sure the surface has the shadow on it exactly once...
  947. ShadowDecalHandle_t dh = MSurf_ShadowDecals( surfID );
  948. while (dh != m_ShadowDecals.InvalidIndex() )
  949. {
  950. Assert ( m_ShadowDecals[dh].m_Shadow != handle );
  951. dh = m_ShadowDecals.Next(dh);
  952. }
  953. #endif
  954. // Create a shadow decal for this surface and add it to the surface
  955. AddShadowDecalToSurface( surfID, handle );
  956. }
  957. void CShadowMgr::RemoveSurfaceFromShadow( ShadowHandle_t handle, SurfaceHandle_t surfID )
  958. {
  959. // Find the decal associated with the handle that lies on the surface
  960. // FIXME: Linear search; bleah.
  961. // Luckily the search is probably over only a couple items at most
  962. // Linear searching over the shadow surfaces so we can remove the entry
  963. // in the shadow surface list if we find a match
  964. ASSERT_SURF_VALID( surfID );
  965. ShadowSurfaceIndex_t i = m_Shadows[handle].m_FirstDecal;
  966. while ( i != m_ShadowSurfaces.InvalidIndex() )
  967. {
  968. ShadowDecalHandle_t decalHandle = m_ShadowSurfaces[i];
  969. if ( m_ShadowDecals[decalHandle].m_SurfID == surfID )
  970. {
  971. // Found a match! There should be at most one shadow decal
  972. // associated with a particular shadow per surface
  973. RemoveShadowDecalFromSurface( surfID, decalHandle );
  974. // FIXME: Could check the shadow doesn't appear again in the list
  975. return;
  976. }
  977. i = m_ShadowSurfaces.Next(i);
  978. }
  979. #ifdef _DEBUG
  980. // Here, the shadow didn't have the surface in its list
  981. // let's make sure the surface doesn't think it's got the shadow in its list
  982. ShadowDecalHandle_t dh = MSurf_ShadowDecals( surfID );
  983. while (dh != m_ShadowDecals.InvalidIndex() )
  984. {
  985. Assert ( m_ShadowDecals[dh].m_Shadow != handle );
  986. dh = m_ShadowDecals.Next(dh);
  987. }
  988. #endif
  989. }
  990. void CShadowMgr::RemoveAllSurfacesFromShadow( ShadowHandle_t handle )
  991. {
  992. // Iterate over all the decals associated with a particular shadow
  993. // Remove the decals from the surfaces they are associated with
  994. ShadowSurfaceIndex_t i = m_Shadows[handle].m_FirstDecal;
  995. ShadowSurfaceIndex_t next;
  996. while ( i != m_ShadowSurfaces.InvalidIndex() )
  997. {
  998. ShadowDecalHandle_t decalHandle = m_ShadowSurfaces[i];
  999. next = m_ShadowSurfaces.Next(i);
  1000. RemoveShadowDecalFromSurface( m_ShadowDecals[decalHandle].m_SurfID, decalHandle );
  1001. i = next;
  1002. }
  1003. m_Shadows[handle].m_FirstDecal = m_ShadowSurfaces.InvalidIndex();
  1004. }
  1005. void CShadowMgr::RemoveAllShadowsFromSurface( SurfaceHandle_t surfID )
  1006. {
  1007. // Iterate over all the decals associated with a particular shadow
  1008. // Remove the decals from the surfaces they are associated with
  1009. ShadowDecalHandle_t dh = MSurf_ShadowDecals( surfID );
  1010. while (dh != m_ShadowDecals.InvalidIndex() )
  1011. {
  1012. // Remove this shadow from the surface
  1013. ShadowDecalHandle_t next = m_ShadowDecals.Next(dh);
  1014. // Remove the surface from the shadow
  1015. RemoveShadowDecalFromSurface( m_ShadowDecals[dh].m_SurfID, dh );
  1016. dh = next;
  1017. }
  1018. MSurf_ShadowDecals( surfID ) = m_ShadowDecals.InvalidIndex();
  1019. }
  1020. //-----------------------------------------------------------------------------
  1021. // Shadow/model association
  1022. //-----------------------------------------------------------------------------
  1023. void CShadowMgr::AddShadowToModel( ShadowHandle_t handle, ModelInstanceHandle_t model )
  1024. {
  1025. // FIXME: Add culling here based on the model bbox
  1026. // and the shadow bbox
  1027. // FIXME:
  1028. /*
  1029. // Trivial bbox reject.
  1030. Vector bbMin, bbMax;
  1031. pDisp->GetBoundingBox( bbMin, bbMax );
  1032. if( decalinfo->m_Position.x - decalinfo->m_Size < bbMax.x && decalinfo->m_Position.x + decalinfo->m_Size > bbMin.x &&
  1033. decalinfo->m_Position.y - decalinfo->m_Size < bbMax.y && decalinfo->m_Position.y + decalinfo->m_Size > bbMin.y &&
  1034. decalinfo->m_Position.z - decalinfo->m_Size < bbMax.z && decalinfo->m_Position.z + decalinfo->m_Size > bbMin.z )
  1035. */
  1036. if ( model == MODEL_INSTANCE_INVALID )
  1037. {
  1038. // async data not loaded yet
  1039. return;
  1040. }
  1041. if( r_flashlightrender.GetBool()==false )
  1042. return;
  1043. m_ShadowsOnModels.AddElementToBucket( model, handle );
  1044. }
  1045. void CShadowMgr::RemoveAllShadowsFromModel( ModelInstanceHandle_t model )
  1046. {
  1047. if( model != MODEL_INSTANCE_INVALID )
  1048. {
  1049. m_ShadowsOnModels.RemoveBucket( model );
  1050. FOR_EACH_LL( m_FlashlightStates, i )
  1051. {
  1052. FlashlightInfo_t &info = m_FlashlightStates[i];
  1053. for( int j=0;j<info.m_Renderables.Count();j++ )
  1054. {
  1055. if( info.m_Renderables[j]->GetModelInstance() == model )
  1056. {
  1057. info.m_Renderables.Remove( j );
  1058. break;
  1059. }
  1060. }
  1061. }
  1062. }
  1063. }
  1064. void CShadowMgr::RemoveAllModelsFromShadow( ShadowHandle_t handle )
  1065. {
  1066. m_ShadowsOnModels.RemoveElement( handle );
  1067. FOR_EACH_LL( m_FlashlightStates, i )
  1068. {
  1069. FlashlightInfo_t &info = m_FlashlightStates[i];
  1070. if( info.m_Shadow==handle )
  1071. {
  1072. info.m_Renderables.RemoveAll();
  1073. }
  1074. }
  1075. }
  1076. //-----------------------------------------------------------------------------
  1077. // Shadow state...
  1078. //-----------------------------------------------------------------------------
  1079. void CShadowMgr::SetModelShadowState( ModelInstanceHandle_t instance )
  1080. {
  1081. #ifndef SWDS
  1082. g_pStudioRender->ClearAllShadows();
  1083. if (instance != MODEL_INSTANCE_INVALID && r_shadows.GetInt() )
  1084. {
  1085. bool bWireframe = r_shadowwireframe.GetBool();
  1086. unsigned short i = m_ShadowsOnModels.FirstElement( instance );
  1087. while ( i != m_ShadowsOnModels.InvalidIndex() )
  1088. {
  1089. Shadow_t& shadow = m_Shadows[m_ShadowsOnModels.Element(i)];
  1090. if( !bWireframe )
  1091. {
  1092. if( shadow.m_Flags & SHADOW_FLASHLIGHT )
  1093. {
  1094. // NULL means that the models material should be used.
  1095. // This is what we want in the case of the flashlight
  1096. // since we need to render the models material again with different lighting.
  1097. // Need to add something here to specify which flashlight.
  1098. g_pStudioRender->AddShadow( NULL, NULL, &m_FlashlightStates[shadow.m_FlashlightHandle].m_FlashlightState, &shadow.m_WorldToShadow, shadow.m_pFlashlightDepthTexture );
  1099. }
  1100. else if( r_shadows_gamecontrol.GetInt() != 0 )
  1101. {
  1102. g_pStudioRender->AddShadow( shadow.m_pModelMaterial, shadow.m_pBindProxy );
  1103. }
  1104. }
  1105. else if( ( shadow.m_Flags & SHADOW_FLASHLIGHT ) || r_shadows_gamecontrol.GetInt() != 0 )
  1106. {
  1107. g_pStudioRender->AddShadow( g_pMaterialMRMWireframe, NULL );
  1108. }
  1109. i = m_ShadowsOnModels.NextElement(i);
  1110. }
  1111. }
  1112. #endif
  1113. }
  1114. bool CShadowMgr::ModelHasShadows( ModelInstanceHandle_t instance )
  1115. {
  1116. if ( instance != MODEL_INSTANCE_INVALID )
  1117. {
  1118. if ( m_ShadowsOnModels.FirstElement(instance) != m_ShadowsOnModels.InvalidIndex() )
  1119. return true;
  1120. }
  1121. return false;
  1122. }
  1123. //-----------------------------------------------------------------------------
  1124. // Applies the shadow to a surface
  1125. //-----------------------------------------------------------------------------
  1126. void CShadowMgr::ApplyShadowToSurface( ShadowBuildInfo_t& build, SurfaceHandle_t surfID )
  1127. {
  1128. // We've found a potential surface to add to the shadow
  1129. // At this point, we want to do fast culling to see whether we actually
  1130. // should apply the shadow or not before actually adding it to any lists
  1131. // FIXME: implement
  1132. // Put the texture extents into shadow space; see if there's an intersection
  1133. // If not, we can early out
  1134. // To do this, we're gonna want to project the surface into the space of the decal
  1135. // Therefore, we want to produce a surface->world transformation, and a
  1136. // world->shadow/light space transformation
  1137. // Then we transform the surface points into shadow space and apply the projection
  1138. // in shadow space.
  1139. /*
  1140. // Get the texture associated with this surface
  1141. mtexinfo_t* tex = pSurface->texinfo;
  1142. Vector4D &textureU = tex->textureVecsTexelsPerWorldUnits[0];
  1143. Vector4D &textureV = tex->textureVecsTexelsPerWorldUnits[1];
  1144. // project decal center into the texture space of the surface
  1145. float s = DotProduct( decalinfo->m_Position, textureU.AsVector3D() ) +
  1146. textureU.w - surf->textureMins[0];
  1147. float t = DotProduct( decalinfo->m_Position, textureV.AsVector3D() ) +
  1148. textureV.w - surf->textureMins[1];
  1149. */
  1150. // Don't do any more computation at the moment, only do it if
  1151. // we end up rendering the surface later on
  1152. AddSurfaceToShadow( build.m_Shadow, surfID );
  1153. }
  1154. //-----------------------------------------------------------------------------
  1155. // Applies the shadow to a displacement
  1156. //-----------------------------------------------------------------------------
  1157. void CShadowMgr::ApplyShadowToDisplacement( ShadowBuildInfo_t& build, IDispInfo *pDispInfo, bool bIsFlashlight )
  1158. {
  1159. // Avoid noshadow displacements
  1160. if ( !bIsFlashlight && ( MSurf_Flags( pDispInfo->GetParent() ) & SURFDRAW_NOSHADOWS ) )
  1161. return;
  1162. // Trivial bbox reject.
  1163. Vector bbMin, bbMax;
  1164. pDispInfo->GetBoundingBox( bbMin, bbMax );
  1165. if ( !bIsFlashlight )
  1166. {
  1167. if ( !IsBoxIntersectingSphere( bbMin, bbMax, build.m_vecSphereCenter, build.m_flSphereRadius ) )
  1168. return;
  1169. }
  1170. else
  1171. {
  1172. if( R_CullBox( bbMin, bbMax, GetFlashlightFrustum( build.m_Shadow ) ) )
  1173. return;
  1174. }
  1175. SurfaceHandle_t surfID = pDispInfo->GetParent();
  1176. if ( surfID->m_bDynamicShadowsEnabled == false && !bIsFlashlight )
  1177. return;
  1178. AddSurfaceToShadow( build.m_Shadow, surfID );
  1179. }
  1180. //-----------------------------------------------------------------------------
  1181. // Allows us to disable particular shadows
  1182. //-----------------------------------------------------------------------------
  1183. void CShadowMgr::EnableShadow( ShadowHandle_t handle, bool bEnable )
  1184. {
  1185. if (!bEnable)
  1186. {
  1187. // We need to remove the shadow from all surfaces it may currently be in
  1188. RemoveAllSurfacesFromShadow( handle );
  1189. RemoveAllModelsFromShadow( handle );
  1190. m_Shadows[handle].m_Flags |= SHADOW_DISABLED;
  1191. }
  1192. else
  1193. {
  1194. // FIXME: Could make this recompute the cache...
  1195. m_Shadows[handle].m_Flags &= ~SHADOW_DISABLED;
  1196. }
  1197. }
  1198. //-----------------------------------------------------------------------------
  1199. // Purpose: Set the darkness falloff bias
  1200. // Input : shadow -
  1201. // ucBias -
  1202. //-----------------------------------------------------------------------------
  1203. void CShadowMgr::SetFalloffBias( ShadowHandle_t shadow, unsigned char ucBias )
  1204. {
  1205. m_Shadows[shadow].m_FalloffBias = ucBias;
  1206. }
  1207. //-----------------------------------------------------------------------------
  1208. // Recursive routine to find surface to apply a decal to. World coordinates of
  1209. // the decal are passed in r_recalpos like the rest of the engine. This should
  1210. // be called through R_DecalShoot()
  1211. //-----------------------------------------------------------------------------
  1212. void CShadowMgr::ProjectShadow( ShadowHandle_t handle, const Vector &origin,
  1213. const Vector& projectionDir, const VMatrix& worldToShadow, const Vector2D& size,
  1214. int nLeafCount, const int *pLeafList,
  1215. float maxHeight, float falloffOffset, float falloffAmount, const Vector &vecCasterOrigin )
  1216. {
  1217. VPROF_BUDGET( "CShadowMgr::ProjectShadow", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  1218. // First, we need to remove the shadow from all surfaces it may
  1219. // currently be in; in other words we're invalidating the shadow surface cache
  1220. RemoveAllSurfacesFromShadow( handle );
  1221. RemoveAllModelsFromShadow( handle );
  1222. // Don't bother with this shadow if it's disabled
  1223. Shadow_t &shadow = m_Shadows[handle];
  1224. if ( shadow.m_Flags & SHADOW_DISABLED )
  1225. return;
  1226. // Don't compute the surface cache if shadows are off..
  1227. if ( !r_shadows.GetInt() )
  1228. return;
  1229. // Set the falloff coefficient
  1230. shadow.m_FalloffOffset = falloffOffset;
  1231. VectorCopy( projectionDir, shadow.m_ProjectionDir );
  1232. // We need to know about surfaces in leaves hit by the ray...
  1233. // We'd like to stop iterating as soon as the entire swept volume
  1234. // enters a solid leaf; that may be hard to determine. Instead,
  1235. // we should stop iterating when the ray center enters a solid leaf?
  1236. AssertFloatEquals( projectionDir.LengthSqr(), 1.0f, 1e-3 );
  1237. // The maximum ray distance is equal to the distance it takes the
  1238. // falloff to get to 15%.
  1239. shadow.m_MaxDist = maxHeight; //sqrt( coeff / 0.10f ) + falloffOffset;
  1240. shadow.m_FalloffAmount = falloffAmount;
  1241. MatrixCopy( worldToShadow, shadow.m_WorldToShadow );
  1242. // Compute a rough bounding sphere for the ray
  1243. float flRadius = sqrt( size.x * size.x + size.y * size.y ) * 0.5f;
  1244. VectorMA( origin, 0.5f * maxHeight, projectionDir, shadow.m_vecSphereCenter );
  1245. shadow.m_flSphereRadius = 0.5f * maxHeight + flRadius;
  1246. Vector vecEndPoint;
  1247. Vector vecMins( -flRadius, -flRadius, -flRadius );
  1248. Vector vecMaxs( flRadius, flRadius, flRadius );
  1249. VectorMA( origin, maxHeight, projectionDir, vecEndPoint );
  1250. shadow.m_Ray.Init( origin, vecEndPoint, vecMins, vecMaxs );
  1251. // No more work necessary if it hits no leaves
  1252. if ( nLeafCount == 0 )
  1253. return;
  1254. // We're hijacking the surface vis frame to make sure we enumerate
  1255. // surfaces only once;
  1256. ++r_surfacevisframe;
  1257. // Clear out the displacement tags also
  1258. DispInfo_ClearAllTags( host_state.worldbrush->hDispInfos );
  1259. ShadowBuildInfo_t build;
  1260. build.m_Shadow = handle;
  1261. build.m_RayStart = origin;
  1262. build.m_pVis = NULL;
  1263. build.m_vecSphereCenter = shadow.m_vecSphereCenter;
  1264. build.m_flSphereRadius = shadow.m_flSphereRadius;
  1265. VectorCopy( projectionDir, build.m_ProjectionDirection );
  1266. // Enumerate leaves
  1267. for ( int i = 0; i < nLeafCount; ++i )
  1268. {
  1269. // NOTE: Scope specifier eliminates virtual function call
  1270. CShadowMgr::EnumerateLeaf( pLeafList[i], (int)&build );
  1271. }
  1272. }
  1273. void DrawFrustum( Frustum_t &frustum )
  1274. {
  1275. const int maxPoints = 8;
  1276. int i;
  1277. for( i = 0; i < FRUSTUM_NUMPLANES; i++ )
  1278. {
  1279. Vector points[maxPoints];
  1280. Vector points2[maxPoints];
  1281. int numPoints = PolyFromPlane( points, frustum.GetPlane( i )->normal, frustum.GetPlane( i )->dist );
  1282. Assert( numPoints <= maxPoints );
  1283. Vector *in, *out;
  1284. in = points;
  1285. out = points2;
  1286. int j;
  1287. for( j = 0; j < FRUSTUM_NUMPLANES; j++ )
  1288. {
  1289. if( i == j )
  1290. {
  1291. continue;
  1292. }
  1293. numPoints = ClipPolyToPlane( in, numPoints, out, frustum.GetPlane( j )->normal, frustum.GetPlane( j )->dist );
  1294. Assert( numPoints <= maxPoints );
  1295. V_swap( in, out );
  1296. }
  1297. int c;
  1298. for( c = 0; c < numPoints; c++ )
  1299. {
  1300. CDebugOverlay::AddLineOverlay( in[c], in[(c+1)%numPoints], 0, 255, 0, 255, true, 0.0f );
  1301. }
  1302. }
  1303. }
  1304. //static void LineDrawHelper( const Vector &startShadowSpace, const Vector &endShadowSpace,
  1305. // const VMatrix &shadowToWorld, unsigned char r, unsigned char g,
  1306. // unsigned char b, bool ignoreZ )
  1307. //{
  1308. // Vector startWorldSpace, endWorldSpace;
  1309. // Vector3DMultiplyPositionProjective( shadowToWorld, startShadowSpace, startWorldSpace );
  1310. // Vector3DMultiplyPositionProjective( shadowToWorld, endShadowSpace, endWorldSpace );
  1311. //
  1312. // CDebugOverlay::AddLineOverlay( startWorldSpace,
  1313. // endWorldSpace,
  1314. // r, g, b, ignoreZ
  1315. // , 0.0 );
  1316. //}
  1317. void CShadowMgr::ProjectFlashlight( ShadowHandle_t handle, const VMatrix& worldToShadow, int nLeafCount, const int *pLeafList )
  1318. {
  1319. VPROF_BUDGET( "CShadowMgr::ProjectFlashlight", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  1320. Shadow_t& shadow = m_Shadows[handle];
  1321. if ( !IsX360() && !r_flashlight_version2.GetInt() )
  1322. {
  1323. // First, we need to remove the shadow from all surfaces it may
  1324. // currently be in; in other words we're invalidating the shadow surface cache
  1325. RemoveAllSurfacesFromShadow( handle );
  1326. RemoveAllModelsFromShadow( handle );
  1327. m_FlashlightStates[ shadow.m_FlashlightHandle ].m_OccluderBuckets.Flush();
  1328. }
  1329. // Don't bother with this shadow if it's disabled
  1330. if ( m_Shadows[handle].m_Flags & SHADOW_DISABLED )
  1331. return;
  1332. // Don't compute the surface cache if shadows are off..
  1333. if ( !r_shadows.GetInt() )
  1334. return;
  1335. MatrixCopy( worldToShadow, shadow.m_WorldToShadow );
  1336. // We need this for our various bounding computations
  1337. VMatrix shadowToWorld;
  1338. MatrixInverseGeneral( shadow.m_WorldToShadow, shadowToWorld );
  1339. // Set up the frustum for the flashlight so that we can cull each leaf against it.
  1340. Assert( shadow.m_Flags & SHADOW_FLASHLIGHT );
  1341. Frustum_t &frustum = m_FlashlightStates[shadow.m_FlashlightHandle].m_Frustum;
  1342. FrustumPlanesFromMatrix( shadowToWorld, frustum );
  1343. CalculateSphereFromProjectionMatrixInverse( shadowToWorld, &shadow.m_vecSphereCenter, &shadow.m_flSphereRadius );
  1344. if ( nLeafCount == 0 )
  1345. return;
  1346. // We're hijacking the surface vis frame to make sure we enumerate
  1347. // surfaces only once;
  1348. ++r_surfacevisframe;
  1349. // Clear out the displacement tags also
  1350. DispInfo_ClearAllTags( host_state.worldbrush->hDispInfos );
  1351. ShadowBuildInfo_t build;
  1352. build.m_Shadow = handle;
  1353. build.m_RayStart = m_FlashlightStates[shadow.m_FlashlightHandle].m_FlashlightState.m_vecLightOrigin;
  1354. build.m_pVis = NULL;
  1355. build.m_vecSphereCenter = shadow.m_vecSphereCenter;
  1356. build.m_flSphereRadius = shadow.m_flSphereRadius;
  1357. if( r_flashlightdrawfrustumbbox.GetBool() )
  1358. {
  1359. Vector mins, maxs;
  1360. CalculateAABBFromProjectionMatrixInverse( shadowToWorld, &mins, &maxs );
  1361. CDebugOverlay::AddBoxOverlay( Vector( 0.0f, 0.0f, 0.0f ), mins, maxs, QAngle( 0, 0, 0 ),
  1362. 0, 0, 255, 100, 0.0f );
  1363. }
  1364. for ( int i = 0; i < nLeafCount; ++i )
  1365. {
  1366. // NOTE: Scope specifier eliminates virtual function call
  1367. CShadowMgr::EnumerateLeaf( pLeafList[i], (int)&build );
  1368. }
  1369. }
  1370. //-----------------------------------------------------------------------------
  1371. // Applies the flashlight to all surfaces in the leaf
  1372. //-----------------------------------------------------------------------------
  1373. void CShadowMgr::ApplyFlashlightToLeaf( const Shadow_t &shadow, mleaf_t* pLeaf, ShadowBuildInfo_t* pBuild )
  1374. {
  1375. // Get the bounds of the leaf so that we can test it against the flashlight frustum.
  1376. Vector leafMins, leafMaxs;
  1377. VectorAdd( pLeaf->m_vecCenter, pLeaf->m_vecHalfDiagonal, leafMaxs );
  1378. VectorSubtract( pLeaf->m_vecCenter, pLeaf->m_vecHalfDiagonal, leafMins );
  1379. // The flashlight frustum didn't intersect the bounding box for this leaf! Get outta here!
  1380. if( R_CullBox( leafMins, leafMaxs, GetFlashlightFrustum( pBuild->m_Shadow ) ) )
  1381. return;
  1382. // Iterate over all surfaces in the leaf, check for backfacing
  1383. // and apply the shadow to the surface if it's not backfaced.
  1384. // Note that this really only indicates that the shadow may potentially
  1385. // sit on the surface; when we render, we'll actually do the clipping
  1386. // computation and at that point we'll remove surfaces that don't
  1387. // actually hit the surface
  1388. bool bCullDepth = r_flashlightculldepth.GetBool();
  1389. SurfaceHandle_t *pHandle = &host_state.worldbrush->marksurfaces[pLeaf->firstmarksurface];
  1390. for ( int i = 0; i < pLeaf->nummarksurfaces; i++ )
  1391. {
  1392. SurfaceHandle_t surfID = pHandle[i];
  1393. // only process each surface once;
  1394. if( MSurf_VisFrame( surfID ) == r_surfacevisframe )
  1395. continue;
  1396. MSurf_VisFrame( surfID ) = r_surfacevisframe;
  1397. Assert( !MSurf_DispInfo( surfID ) );
  1398. // perspective projection
  1399. // world-space vertex
  1400. int vertIndex = host_state.worldbrush->vertindices[MSurf_FirstVertIndex( surfID )];
  1401. Vector& worldPos = host_state.worldbrush->vertexes[vertIndex].position;
  1402. // Get the lookdir
  1403. Vector lookdir;
  1404. VectorSubtract( worldPos, pBuild->m_RayStart, lookdir );
  1405. VectorNormalize( lookdir );
  1406. const cplane_t &surfPlane = MSurf_Plane( surfID );
  1407. // Now apply the spherical cull
  1408. float flDist = DotProduct( surfPlane.normal, pBuild->m_vecSphereCenter ) - surfPlane.dist;
  1409. if ( fabs(flDist) >= pBuild->m_flSphereRadius )
  1410. continue;
  1411. ApplyShadowToSurface( *pBuild, surfID );
  1412. // Backface cull
  1413. if( bCullDepth )
  1414. {
  1415. if ( (MSurf_Flags( surfID ) & SURFDRAW_NOCULL) == 0 )
  1416. {
  1417. if ( DotProduct(surfPlane.normal, lookdir) < BACKFACE_EPSILON )
  1418. continue;
  1419. }
  1420. else
  1421. {
  1422. // Avoid edge-on shadows regardless.
  1423. float dot = DotProduct(surfPlane.normal, lookdir);
  1424. if (fabs(dot) < BACKFACE_EPSILON)
  1425. continue;
  1426. }
  1427. }
  1428. FlashlightInfo_t &flashlightInfo = m_FlashlightStates[ shadow.m_FlashlightHandle ];
  1429. flashlightInfo.m_OccluderBuckets.AddElement( MSurf_MaterialSortID( surfID ), surfID );
  1430. }
  1431. }
  1432. //-----------------------------------------------------------------------------
  1433. // Applies a shadow to all surfaces in the leaf
  1434. //-----------------------------------------------------------------------------
  1435. void CShadowMgr::ApplyShadowToLeaf( const Shadow_t &shadow, mleaf_t* RESTRICT pLeaf, ShadowBuildInfo_t* RESTRICT pBuild )
  1436. {
  1437. // Iterate over all surfaces in the leaf, check for backfacing
  1438. // and apply the shadow to the surface if it's not backfaced.
  1439. // Note that this really only indicates that the shadow may potentially
  1440. // sit on the surface; when we render, we'll actually do the clipping
  1441. // computation and at that point we'll remove surfaces that don't
  1442. // actually hit the surface
  1443. SurfaceHandle_t *pHandle = &host_state.worldbrush->marksurfaces[pLeaf->firstmarksurface];
  1444. for ( int i = 0; i < pLeaf->nummarksurfaces; i++ )
  1445. {
  1446. SurfaceHandleRestrict_t surfID = pHandle[i];
  1447. // only process each surface once;
  1448. if( MSurf_VisFrame( surfID ) == r_surfacevisframe )
  1449. continue;
  1450. MSurf_VisFrame( surfID ) = r_surfacevisframe;
  1451. Assert( !MSurf_DispInfo( surfID ) );
  1452. // If this surface has specifically had dynamic shadows disabled on it, then get out!
  1453. if ( !MSurf_AreDynamicShadowsEnabled( surfID ) )
  1454. continue;
  1455. // Backface cull
  1456. const cplane_t * RESTRICT pSurfPlane = &MSurf_Plane( surfID );
  1457. bool bInFront;
  1458. if ( (MSurf_Flags( surfID ) & SURFDRAW_NOCULL) == 0 )
  1459. {
  1460. if ( DotProduct( pSurfPlane->normal, pBuild->m_ProjectionDirection) > -BACKFACE_EPSILON )
  1461. continue;
  1462. bInFront = true;
  1463. }
  1464. else
  1465. {
  1466. // Avoid edge-on shadows regardless.
  1467. float dot = DotProduct( pSurfPlane->normal, pBuild->m_ProjectionDirection );
  1468. if (fabs(dot) < BACKFACE_EPSILON)
  1469. continue;
  1470. bInFront = (dot < 0);
  1471. }
  1472. // Here, it's front facing...
  1473. // Discard stuff on the wrong side of the ray start
  1474. if (bInFront)
  1475. {
  1476. if ( DotProduct( pSurfPlane->normal, pBuild->m_RayStart) < pSurfPlane->dist )
  1477. continue;
  1478. }
  1479. else
  1480. {
  1481. if ( DotProduct( pSurfPlane->normal, pBuild->m_RayStart) > pSurfPlane->dist )
  1482. continue;
  1483. }
  1484. // Now apply the spherical cull
  1485. float flDist = DotProduct( pSurfPlane->normal, pBuild->m_vecSphereCenter ) - pSurfPlane->dist;
  1486. if ( fabs(flDist) >= pBuild->m_flSphereRadius )
  1487. continue;
  1488. ApplyShadowToSurface( *pBuild, surfID );
  1489. }
  1490. }
  1491. #define BIT_SET( a, b ) ((a)[(b)>>3] & (1<<((b)&7)))
  1492. //-----------------------------------------------------------------------------
  1493. // Applies a projected texture to all surfaces in the leaf
  1494. //-----------------------------------------------------------------------------
  1495. bool CShadowMgr::EnumerateLeaf( int leaf, int context )
  1496. {
  1497. VPROF( "CShadowMgr::EnumerateLeaf" );
  1498. ShadowBuildInfo_t* pBuild = (ShadowBuildInfo_t*)context;
  1499. // Skip this leaf if it's not visible from the shadow caster
  1500. if ( pBuild->m_pVis )
  1501. {
  1502. int cluster = CM_LeafCluster( leaf );
  1503. if ( !BIT_SET( pBuild->m_pVis, cluster ) )
  1504. return true;
  1505. }
  1506. const Shadow_t &shadow = m_Shadows[pBuild->m_Shadow];
  1507. mleaf_t* pLeaf = &host_state.worldbrush->leafs[leaf];
  1508. bool bIsFlashlight;
  1509. if( shadow.m_Flags & SHADOW_FLASHLIGHT )
  1510. {
  1511. bIsFlashlight = true;
  1512. ApplyFlashlightToLeaf( shadow, pLeaf, pBuild );
  1513. }
  1514. else
  1515. {
  1516. bIsFlashlight = false;
  1517. ApplyShadowToLeaf( shadow, pLeaf, pBuild );
  1518. }
  1519. // Add the decal to each displacement in the leaf it touches.
  1520. for ( int i = 0; i < pLeaf->dispCount; i++ )
  1521. {
  1522. IDispInfo *pDispInfo = MLeaf_Disaplcement( pLeaf, i );
  1523. // Make sure the decal hasn't already been added to it.
  1524. if( pDispInfo->GetTag() )
  1525. continue;
  1526. pDispInfo->SetTag();
  1527. ApplyShadowToDisplacement( *pBuild, pDispInfo, bIsFlashlight );
  1528. }
  1529. return true;
  1530. }
  1531. //-----------------------------------------------------------------------------
  1532. // Adds a shadow to a brush model
  1533. //-----------------------------------------------------------------------------
  1534. void CShadowMgr::AddShadowToBrushModel( ShadowHandle_t handle, model_t* pModel,
  1535. const Vector& origin, const QAngle& angles )
  1536. {
  1537. // Don't compute the surface cache if shadows are off..
  1538. if ( !r_shadows.GetInt() )
  1539. return;
  1540. const Shadow_t * RESTRICT pShadow = &m_Shadows[handle];
  1541. // Transform the shadow ray direction into model space
  1542. Vector shadowDirInModelSpace;
  1543. bool bIsFlashlight = ( pShadow->m_Flags & SHADOW_FLASHLIGHT ) != 0;
  1544. if( !bIsFlashlight )
  1545. {
  1546. // FLASHLIGHTFIXME: should do backface culling for projective light sources.
  1547. matrix3x4_t worldToModel;
  1548. AngleIMatrix( angles, worldToModel );
  1549. VectorRotate( pShadow->m_ProjectionDir, worldToModel, shadowDirInModelSpace );
  1550. }
  1551. // Just add all non-backfacing brush surfaces to the list of potential
  1552. // surfaces that we may be casting a shadow onto.
  1553. SurfaceHandleRestrict_t surfID = SurfaceHandleFromIndex( pModel->brush.firstmodelsurface, pModel->brush.pShared );
  1554. for (int i=0; i<pModel->brush.nummodelsurfaces; ++i, ++surfID)
  1555. {
  1556. // Don't bother with nodraw surfaces
  1557. int nFlags = MSurf_Flags( surfID );
  1558. if ( nFlags & SURFDRAW_NODRAW )
  1559. continue;
  1560. if( !bIsFlashlight )
  1561. {
  1562. // FLASHLIGHTFIXME: should do backface culling for projective light sources.
  1563. // Don't bother with backfacing surfaces
  1564. if ( (nFlags & SURFDRAW_NOCULL) == 0 )
  1565. {
  1566. const cplane_t * RESTRICT pSurfPlane = &MSurf_Plane( surfID );
  1567. float dot = DotProduct( shadowDirInModelSpace, pSurfPlane->normal );
  1568. if ( dot > 0 )
  1569. continue;
  1570. }
  1571. }
  1572. // FIXME: We may want to do some more high-level per-surface culling
  1573. // If so, it'll be added to ApplyShadowToSurface. Call it instead.
  1574. AddSurfaceToShadow( handle, surfID );
  1575. }
  1576. }
  1577. //-----------------------------------------------------------------------------
  1578. // Removes all shadows from a brush model
  1579. //-----------------------------------------------------------------------------
  1580. void CShadowMgr::RemoveAllShadowsFromBrushModel( model_t* pModel )
  1581. {
  1582. SurfaceHandle_t surfID = SurfaceHandleFromIndex( pModel->brush.firstmodelsurface, pModel->brush.pShared );
  1583. for (int i=0; i<pModel->brush.nummodelsurfaces; ++i, ++surfID)
  1584. {
  1585. RemoveAllShadowsFromSurface( surfID );
  1586. }
  1587. }
  1588. //-----------------------------------------------------------------------------
  1589. // Adds the shadow decals on the surface to a queue of things to render
  1590. //-----------------------------------------------------------------------------
  1591. void CShadowMgr::AddShadowsOnSurfaceToRenderList( ShadowDecalHandle_t decalHandle )
  1592. {
  1593. // Don't compute the surface cache if shadows are off..
  1594. if (!r_shadows.GetInt() )
  1595. return;
  1596. // Add all surface decals into the appropriate render lists
  1597. while( decalHandle != m_ShadowDecals.InvalidIndex() )
  1598. {
  1599. ShadowDecal_t& shadowDecal = m_ShadowDecals[decalHandle];
  1600. if( m_Shadows[shadowDecal.m_Shadow].m_Flags & SHADOW_FLASHLIGHT )
  1601. {
  1602. AddSurfaceToFlashlightMaterialBuckets( shadowDecal.m_Shadow, shadowDecal.m_SurfID );
  1603. // We've got one more decal to render
  1604. ++m_DecalsToRender;
  1605. }
  1606. else if( r_shadows_gamecontrol.GetInt() != 0 )
  1607. {
  1608. // For shadow rendering, hook the decal into the render list based on the shadow material, not the surface material.
  1609. int sortOrder = m_Shadows[shadowDecal.m_Shadow].m_SortOrder;
  1610. m_ShadowDecals[decalHandle].m_NextRender = m_RenderQueue[sortOrder];
  1611. m_RenderQueue[sortOrder] = decalHandle;
  1612. // We've got one more decal to render
  1613. ++m_DecalsToRender;
  1614. }
  1615. decalHandle = m_ShadowDecals.Next(decalHandle);
  1616. }
  1617. }
  1618. void CShadowMgr::ClearShadowRenderList()
  1619. {
  1620. COMPILE_TIME_ASSERT( sizeof(ShadowDecalHandle_t) == 2 );
  1621. // Clear out the render list
  1622. if (m_RenderQueue.Count() > 0)
  1623. {
  1624. memset( m_RenderQueue.Base(), 0xFF, m_RenderQueue.Count() * sizeof(ShadowDecalHandle_t) );
  1625. }
  1626. m_DecalsToRender = 0;
  1627. // Clear all lists pertaining to flashlight decals that need to be rendered.
  1628. ClearAllFlashlightMaterialBuckets();
  1629. }
  1630. void CShadowMgr::RenderShadows( const VMatrix* pModelToWorld )
  1631. {
  1632. VPROF_BUDGET( "CShadowMgr::RenderShadows", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  1633. // Iterate through all sort ids and render for regular shadows, which get their materials from the shadow material.
  1634. CMatRenderContextPtr pRenderContext( materials );
  1635. int i;
  1636. for( i = 0; i < m_RenderQueue.Count(); ++i )
  1637. {
  1638. if (m_RenderQueue[i] != m_ShadowDecals.InvalidIndex())
  1639. {
  1640. RenderShadowList(pRenderContext, m_RenderQueue[i], pModelToWorld );
  1641. }
  1642. }
  1643. }
  1644. void CShadowMgr::RenderProjectedTextures( const VMatrix* pModelToWorld )
  1645. {
  1646. VPROF_BUDGET( "CShadowMgr::RenderProjectedTextures", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  1647. RenderFlashlights( true, pModelToWorld );
  1648. RenderShadows( pModelToWorld );
  1649. // Clear out the render list, we've rendered it now
  1650. ClearShadowRenderList();
  1651. }
  1652. //-----------------------------------------------------------------------------
  1653. // A 2D sutherland-hodgman clipper
  1654. //-----------------------------------------------------------------------------
  1655. class CClipTop
  1656. {
  1657. public:
  1658. static inline bool Inside( ShadowVertex_t const& vert ) { return vert.m_ShadowSpaceTexCoord.y < 1;}
  1659. static inline float Clip( const Vector& one, const Vector& two ) { return (1 - one.y) / (two.y - one.y);}
  1660. static inline bool IsPlane() {return false;}
  1661. static inline bool IsAbove() {return false;}
  1662. };
  1663. class CClipLeft
  1664. {
  1665. public:
  1666. static inline bool Inside( ShadowVertex_t const& vert ) { return vert.m_ShadowSpaceTexCoord.x > 0;}
  1667. static inline float Clip( const Vector& one, const Vector& two ) { return one.x / (one.x - two.x);}
  1668. static inline bool IsPlane() {return false;}
  1669. static inline bool IsAbove() {return false;}
  1670. };
  1671. class CClipRight
  1672. {
  1673. public:
  1674. static inline bool Inside( ShadowVertex_t const& vert ) {return vert.m_ShadowSpaceTexCoord.x < 1;}
  1675. static inline float Clip( const Vector& one, const Vector& two ) {return (1 - one.x) / (two.x - one.x);}
  1676. static inline bool IsPlane() {return false;}
  1677. static inline bool IsAbove() {return false;}
  1678. };
  1679. class CClipBottom
  1680. {
  1681. public:
  1682. static inline bool Inside( ShadowVertex_t const& vert ) {return vert.m_ShadowSpaceTexCoord.y > 0;}
  1683. static inline float Clip( const Vector& one, const Vector& two ) {return one.y / (one.y - two.y);}
  1684. static inline bool IsPlane() {return false;}
  1685. static inline bool IsAbove() {return false;}
  1686. };
  1687. class CClipAbove
  1688. {
  1689. public:
  1690. static inline bool Inside( ShadowVertex_t const& vert ) {return vert.m_ShadowSpaceTexCoord.z > 0;}
  1691. static inline float Clip( const Vector& one, const Vector& two ) {return one.z / (one.z - two.z);}
  1692. static inline bool IsPlane() {return false;}
  1693. static inline bool IsAbove() {return true;}
  1694. };
  1695. class CClipPlane
  1696. {
  1697. public:
  1698. static inline bool Inside( ShadowVertex_t const& vert )
  1699. {
  1700. return DotProduct( vert.m_Position, *m_pNormal ) < m_Dist;
  1701. }
  1702. static inline float Clip( const Vector& one, const Vector& two )
  1703. {
  1704. Vector dir;
  1705. VectorSubtract( two, one, dir );
  1706. return IntersectRayWithPlane( one, dir, *m_pNormal, m_Dist );
  1707. }
  1708. static inline bool IsAbove() {return false;}
  1709. static inline bool IsPlane() {return true;}
  1710. static void SetPlane( const Vector& normal, float dist )
  1711. {
  1712. m_pNormal = &normal;
  1713. m_Dist = dist;
  1714. }
  1715. private:
  1716. static const Vector *m_pNormal;
  1717. static float m_Dist;
  1718. };
  1719. const Vector *CClipPlane::m_pNormal;
  1720. float CClipPlane::m_Dist;
  1721. static inline void ClampTexCoord( ShadowVertex_t *pInVertex, ShadowVertex_t *pOutVertex )
  1722. {
  1723. if ( fabs(pInVertex->m_ShadowSpaceTexCoord[0]) < 1e-3 )
  1724. pOutVertex->m_ShadowSpaceTexCoord[0] = 0.0f;
  1725. else if ( fabs(pInVertex->m_ShadowSpaceTexCoord[0] - 1.0f) < 1e-3 )
  1726. pOutVertex->m_ShadowSpaceTexCoord[0] = 1.0f;
  1727. if ( fabs(pInVertex->m_ShadowSpaceTexCoord[1]) < 1e-3 )
  1728. pOutVertex->m_ShadowSpaceTexCoord[1] = 0.0f;
  1729. else if ( fabs(pInVertex->m_ShadowSpaceTexCoord[1] - 1.0f) < 1e-3 )
  1730. pOutVertex->m_ShadowSpaceTexCoord[1] = 1.0f;
  1731. }
  1732. template <class Clipper>
  1733. static inline void Intersect( ShadowVertex_t* pStart, ShadowVertex_t* pEnd, ShadowVertex_t* pOut, bool startInside, Clipper& clipper )
  1734. {
  1735. // Clip the edge to the clip plane
  1736. float t;
  1737. if (!Clipper::IsPlane())
  1738. {
  1739. if (!Clipper::IsAbove())
  1740. {
  1741. // This is the path the we always take for perspective light volumes.
  1742. t = Clipper::Clip( pStart->m_ShadowSpaceTexCoord, pEnd->m_ShadowSpaceTexCoord );
  1743. VectorLerp( pStart->m_ShadowSpaceTexCoord, pEnd->m_ShadowSpaceTexCoord, t, pOut->m_ShadowSpaceTexCoord );
  1744. }
  1745. else
  1746. {
  1747. t = Clipper::Clip( pStart->m_ShadowSpaceTexCoord, pEnd->m_ShadowSpaceTexCoord );
  1748. VectorLerp( pStart->m_ShadowSpaceTexCoord, pEnd->m_ShadowSpaceTexCoord, t, pOut->m_ShadowSpaceTexCoord );
  1749. // This is a special thing we do here to avoid hard-edged shadows
  1750. if (startInside)
  1751. ClampTexCoord( pEnd, pOut );
  1752. else
  1753. ClampTexCoord( pStart, pOut );
  1754. }
  1755. }
  1756. else
  1757. {
  1758. t = Clipper::Clip( pStart->m_Position, pEnd->m_Position );
  1759. VectorLerp( pStart->m_ShadowSpaceTexCoord, pEnd->m_ShadowSpaceTexCoord, t, pOut->m_ShadowSpaceTexCoord );
  1760. }
  1761. VectorLerp( pStart->m_Position, pEnd->m_Position, t, pOut->m_Position );
  1762. }
  1763. template <class Clipper>
  1764. static void ShadowClip( ShadowClipState_t& clip, Clipper& clipper )
  1765. {
  1766. if ( clip.m_ClipCount == 0 )
  1767. return;
  1768. // Ye Olde Sutherland-Hodgman clipping algorithm
  1769. int numOutVerts = 0;
  1770. ShadowVertex_t** pSrcVert = clip.m_ppClipVertices[clip.m_CurrVert];
  1771. ShadowVertex_t** pDestVert = clip.m_ppClipVertices[!clip.m_CurrVert];
  1772. int numVerts = clip.m_ClipCount;
  1773. ShadowVertex_t* pStart = pSrcVert[numVerts-1];
  1774. bool startInside = Clipper::Inside( *pStart );
  1775. for (int i = 0; i < numVerts; ++i)
  1776. {
  1777. ShadowVertex_t* pEnd = pSrcVert[i];
  1778. bool endInside = Clipper::Inside( *pEnd );
  1779. if (endInside)
  1780. {
  1781. if (!startInside)
  1782. {
  1783. // Started outside, ended inside, need to clip the edge
  1784. if ( clip.m_TempCount >= SHADOW_VERTEX_TEMP_COUNT )
  1785. return;
  1786. // Allocate a new clipped vertex
  1787. pDestVert[numOutVerts] = &clip.m_pTempVertices[clip.m_TempCount++];
  1788. // Clip the edge to the clip plane
  1789. Intersect( pStart, pEnd, pDestVert[numOutVerts], startInside, clipper );
  1790. ++numOutVerts;
  1791. }
  1792. pDestVert[numOutVerts++] = pEnd;
  1793. }
  1794. else
  1795. {
  1796. if (startInside)
  1797. {
  1798. // Started inside, ended outside, need to clip the edge
  1799. if ( clip.m_TempCount >= SHADOW_VERTEX_TEMP_COUNT )
  1800. return;
  1801. // Allocate a new clipped vertex
  1802. pDestVert[numOutVerts] = &clip.m_pTempVertices[clip.m_TempCount++];
  1803. // Clip the edge to the clip plane
  1804. Intersect( pStart, pEnd, pDestVert[numOutVerts], startInside, clipper );
  1805. ++numOutVerts;
  1806. }
  1807. }
  1808. pStart = pEnd;
  1809. startInside = endInside;
  1810. }
  1811. // Switch source lists
  1812. clip.m_CurrVert = 1 - clip.m_CurrVert;
  1813. clip.m_ClipCount = numOutVerts;
  1814. Assert( clip.m_ClipCount <= SHADOW_VERTEX_TEMP_COUNT );
  1815. }
  1816. //-----------------------------------------------------------------------------
  1817. // Project vertices into shadow space
  1818. //-----------------------------------------------------------------------------
  1819. bool CShadowMgr::ProjectVerticesIntoShadowSpace( const VMatrix& modelToShadow,
  1820. float maxDist, int count, Vector** RESTRICT ppPosition, ShadowClipState_t& clip )
  1821. {
  1822. bool insideVolume = false;
  1823. // Create vertices to clip to...
  1824. for (int i = 0; i < count; ++i )
  1825. {
  1826. Assert( ppPosition[i] );
  1827. VectorCopy( *ppPosition[i], clip.m_pTempVertices[i].m_Position );
  1828. // Project the points into shadow texture space
  1829. Vector3DMultiplyPosition( modelToShadow, *ppPosition[i], clip.m_pTempVertices[i].m_ShadowSpaceTexCoord );
  1830. // Set up clipping coords...
  1831. clip.m_ppClipVertices[0][i] = &clip.m_pTempVertices[i];
  1832. if (clip.m_pTempVertices[i].m_ShadowSpaceTexCoord[2] < maxDist )
  1833. {
  1834. insideVolume = true;
  1835. }
  1836. }
  1837. clip.m_TempCount = clip.m_ClipCount = count;
  1838. clip.m_CurrVert = 0;
  1839. return insideVolume;
  1840. }
  1841. //-----------------------------------------------------------------------------
  1842. // Projects + clips shadows
  1843. //-----------------------------------------------------------------------------
  1844. int CShadowMgr::ProjectAndClipVertices( const Shadow_t& shadow, const VMatrix& worldToShadow,
  1845. const VMatrix *pWorldToModel, int count, Vector** ppPosition, ShadowVertex_t*** ppOutVertex )
  1846. {
  1847. VPROF( "ProjectAndClipVertices" );
  1848. static ShadowClipState_t clip;
  1849. if ( !ProjectVerticesIntoShadowSpace( worldToShadow, shadow.m_MaxDist, count, ppPosition, clip ) )
  1850. return 0;
  1851. // Clippers...
  1852. CClipTop top;
  1853. CClipBottom bottom;
  1854. CClipLeft left;
  1855. CClipRight right;
  1856. CClipAbove above;
  1857. CClipPlane plane;
  1858. // Sutherland-hodgman clip
  1859. ShadowClip( clip, top );
  1860. ShadowClip( clip, bottom );
  1861. ShadowClip( clip, left );
  1862. ShadowClip( clip, right );
  1863. ShadowClip( clip, above );
  1864. // Planes to suppress back-casting
  1865. for (int i = 0; i < shadow.m_ClipPlaneCount; ++i)
  1866. {
  1867. if ( pWorldToModel )
  1868. {
  1869. cplane_t worldPlane, modelPlane;
  1870. worldPlane.normal = shadow.m_ClipPlane[i];
  1871. worldPlane.dist = shadow.m_ClipDist[i];
  1872. MatrixTransformPlane( *pWorldToModel, worldPlane, modelPlane );
  1873. plane.SetPlane( modelPlane.normal, modelPlane.dist );
  1874. }
  1875. else
  1876. {
  1877. plane.SetPlane( shadow.m_ClipPlane[i], shadow.m_ClipDist[i] );
  1878. }
  1879. ShadowClip( clip, plane );
  1880. }
  1881. if (clip.m_ClipCount < 3)
  1882. return 0;
  1883. // Return a pointer to the array of clipped vertices...
  1884. Assert(ppOutVertex);
  1885. *ppOutVertex = clip.m_ppClipVertices[clip.m_CurrVert];
  1886. return clip.m_ClipCount;
  1887. }
  1888. //-----------------------------------------------------------------------------
  1889. // Accessor for use by the displacements
  1890. //-----------------------------------------------------------------------------
  1891. int CShadowMgr::ProjectAndClipVertices( ShadowHandle_t handle, int count,
  1892. Vector** ppPosition, ShadowVertex_t*** ppOutVertex )
  1893. {
  1894. return ProjectAndClipVertices( m_Shadows[handle],
  1895. m_Shadows[handle].m_WorldToShadow, NULL, count, ppPosition, ppOutVertex );
  1896. }
  1897. //-----------------------------------------------------------------------------
  1898. // Copies vertex info from the clipped vertices
  1899. //-----------------------------------------------------------------------------
  1900. // This version treats texcoords as Vector
  1901. inline void CShadowMgr::CopyClippedVertices( int count, ShadowVertex_t** ppSrcVert, ShadowVertex_t* pDstVert, const Vector &vToAdd )
  1902. {
  1903. for (int i = 0; i < count; ++i)
  1904. {
  1905. pDstVert[i].m_Position = ppSrcVert[i]->m_Position + vToAdd;
  1906. pDstVert[i].m_ShadowSpaceTexCoord = ppSrcVert[i]->m_ShadowSpaceTexCoord;
  1907. // Make sure it's been clipped
  1908. Assert( ppSrcVert[i]->m_ShadowSpaceTexCoord[0] >= -1e-3f );
  1909. Assert( ppSrcVert[i]->m_ShadowSpaceTexCoord[0] - 1.0f <= 1e-3f );
  1910. Assert( ppSrcVert[i]->m_ShadowSpaceTexCoord[1] >= -1e-3f );
  1911. Assert( ppSrcVert[i]->m_ShadowSpaceTexCoord[1] - 1.0f <= 1e-3f );
  1912. }
  1913. }
  1914. //-----------------------------------------------------------------------------
  1915. // Does the actual work of computing shadow vertices
  1916. //-----------------------------------------------------------------------------
  1917. bool CShadowMgr::ComputeShadowVertices( ShadowDecal_t& decal,
  1918. const VMatrix* pModelToWorld, const VMatrix *pWorldToModel, ShadowVertexCache_t* pVertexCache )
  1919. {
  1920. VPROF( "CShadowMgr::ComputeShadowVertices" );
  1921. // Prepare for the clipping
  1922. Vector **ppVec = (Vector**)stackalloc( MSurf_VertCount( decal.m_SurfID ) * sizeof(Vector*) );
  1923. for (int i = 0; i < MSurf_VertCount( decal.m_SurfID ); ++i )
  1924. {
  1925. int vertIndex = host_state.worldbrush->vertindices[MSurf_FirstVertIndex( decal.m_SurfID )+i];
  1926. ppVec[i] = &host_state.worldbrush->vertexes[vertIndex].position;
  1927. }
  1928. // Compute the modelToShadow transform.
  1929. // In the case of the world, just use worldToShadow...
  1930. VMatrix* pModelToShadow = &m_Shadows[decal.m_Shadow].m_WorldToShadow;
  1931. VMatrix temp;
  1932. if ( pModelToWorld )
  1933. {
  1934. MatrixMultiply( *pModelToShadow, *pModelToWorld, temp );
  1935. pModelToShadow = &temp;
  1936. }
  1937. else
  1938. {
  1939. pWorldToModel = NULL;
  1940. }
  1941. // Create vertices to clip to...
  1942. ShadowVertex_t** ppSrcVert;
  1943. int clipCount = ProjectAndClipVertices( m_Shadows[decal.m_Shadow], *pModelToShadow, pWorldToModel,
  1944. MSurf_VertCount( decal.m_SurfID ), ppVec, &ppSrcVert );
  1945. if (clipCount == 0)
  1946. {
  1947. pVertexCache->m_Count = 0;
  1948. return false;
  1949. }
  1950. // Allocate the vertices we're going to use for the decal
  1951. ShadowVertex_t* pDstVert = AllocateVertices( *pVertexCache, clipCount );
  1952. Assert( pDstVert );
  1953. // Copy the clipped vertices into the cache
  1954. const Vector &vNormal = MSurf_Plane( decal.m_SurfID ).normal;
  1955. CopyClippedVertices( clipCount, ppSrcVert, pDstVert, vNormal * OVERLAY_AVOID_FLICKER_NORMAL_OFFSET );
  1956. // Indicate which shadow this is related to
  1957. pVertexCache->m_Shadow = decal.m_Shadow;
  1958. return true;
  1959. }
  1960. //-----------------------------------------------------------------------------
  1961. // Should we cache vertices?
  1962. //-----------------------------------------------------------------------------
  1963. inline bool CShadowMgr::ShouldCacheVertices( const ShadowDecal_t& decal )
  1964. {
  1965. return (m_Shadows[decal.m_Shadow].m_Flags & SHADOW_CACHE_VERTS) != 0;
  1966. }
  1967. //-----------------------------------------------------------------------------
  1968. // Generates a list displacement shadow vertices to render
  1969. //-----------------------------------------------------------------------------
  1970. inline bool CShadowMgr::GenerateDispShadowRenderInfo( IMatRenderContext *pRenderContext, ShadowDecal_t& decal, ShadowRenderInfo_t& info )
  1971. {
  1972. //=============================================================================
  1973. // HPE_BEGIN:
  1974. // [smessick] Added an overflow condition for the max disp decal cache.
  1975. //=============================================================================
  1976. if ( info.m_DispCount >= MAX_SHADOW_DECAL_CACHE_COUNT )
  1977. {
  1978. info.m_DispCount = MAX_SHADOW_DECAL_CACHE_COUNT;
  1979. return true;
  1980. }
  1981. //=============================================================================
  1982. // HPE_END
  1983. //=============================================================================
  1984. int v, i;
  1985. if ( !MSurf_DispInfo( decal.m_SurfID )->ComputeShadowFragments( decal.m_DispShadow, v, i ) )
  1986. return false;
  1987. // Catch overflows....
  1988. if ( ( info.m_VertexCount + v >= info.m_nMaxVertices ) || ( info.m_IndexCount + i >= info.m_nMaxIndices ) )
  1989. return true;
  1990. info.m_VertexCount += v;
  1991. info.m_IndexCount += i;
  1992. info.m_pDispCache[info.m_DispCount++] = decal.m_DispShadow;
  1993. return true;
  1994. }
  1995. //-----------------------------------------------------------------------------
  1996. // Generates a list shadow vertices to render
  1997. //-----------------------------------------------------------------------------
  1998. inline bool CShadowMgr::GenerateNormalShadowRenderInfo( IMatRenderContext *pRenderContext, ShadowDecal_t& decal, ShadowRenderInfo_t& info )
  1999. {
  2000. //=============================================================================
  2001. // HPE_BEGIN:
  2002. // [smessick] Check for cache overflow.
  2003. //=============================================================================
  2004. if ( info.m_Count >= MAX_SHADOW_DECAL_CACHE_COUNT )
  2005. {
  2006. info.m_Count = MAX_SHADOW_DECAL_CACHE_COUNT;
  2007. return true;
  2008. }
  2009. //=============================================================================
  2010. // HPE_END
  2011. //=============================================================================
  2012. // Look for a cache hit
  2013. ShadowVertexCache_t* pVertexCache;
  2014. if (decal.m_ShadowVerts != m_VertexCache.InvalidIndex())
  2015. {
  2016. // Ok, we've already computed the data, lets use it
  2017. info.m_pCache[info.m_Count] = decal.m_ShadowVerts;
  2018. pVertexCache = &m_VertexCache[decal.m_ShadowVerts];
  2019. }
  2020. else
  2021. {
  2022. // Attempt to cull the surface
  2023. bool bIsNear = IsShadowNearSurface( decal.m_Shadow, decal.m_SurfID, info.m_pModelToWorld, &info.m_WorldToModel );
  2024. if ( !bIsNear )
  2025. return false;
  2026. // In this case, we gotta recompute the shadow decal vertices
  2027. // and maybe even store it into the cache....
  2028. bool shouldCacheVerts = ShouldCacheVertices( decal );
  2029. if (shouldCacheVerts)
  2030. {
  2031. decal.m_ShadowVerts = m_VertexCache.AddToTail();
  2032. info.m_pCache[info.m_Count] = decal.m_ShadowVerts;
  2033. pVertexCache = &m_VertexCache[decal.m_ShadowVerts];
  2034. }
  2035. else
  2036. {
  2037. int i = m_TempVertexCache.AddToTail();
  2038. info.m_pCache[info.m_Count] = -i-1;
  2039. pVertexCache = &m_TempVertexCache[i];
  2040. Assert( info.m_pCache[info.m_Count] < 0 );
  2041. }
  2042. // Compute the shadow vertices
  2043. // If no vertices were created, indicate this surface should be removed from the cache
  2044. if ( !ComputeShadowVertices( decal, info.m_pModelToWorld, &info.m_WorldToModel, pVertexCache ) )
  2045. return false;
  2046. }
  2047. // Catch overflows....
  2048. int nAdditionalIndices = 3 * (pVertexCache->m_Count - 2);
  2049. if ( ( info.m_VertexCount + pVertexCache->m_Count >= info.m_nMaxVertices ) ||
  2050. ( info.m_IndexCount + nAdditionalIndices >= info.m_nMaxIndices ) )
  2051. {
  2052. return true;
  2053. }
  2054. // Update vertex, index, and decal counts
  2055. info.m_VertexCount += pVertexCache->m_Count;
  2056. info.m_IndexCount += nAdditionalIndices;
  2057. ++info.m_Count;
  2058. return true;
  2059. }
  2060. //-----------------------------------------------------------------------------
  2061. // Generates a list shadow vertices to render
  2062. //-----------------------------------------------------------------------------
  2063. void CShadowMgr::GenerateShadowRenderInfo( IMatRenderContext *pRenderContext, ShadowDecalHandle_t decalHandle, ShadowRenderInfo_t& info )
  2064. {
  2065. info.m_VertexCount = 0;
  2066. info.m_IndexCount = 0;
  2067. info.m_Count = 0;
  2068. info.m_DispCount = 0;
  2069. // Keep the lists only full of valid decals; that way we can preserve
  2070. // the render lists in the case that we discover a shadow isn't needed.
  2071. ShadowDecalHandle_t next;
  2072. for ( ; decalHandle != m_ShadowDecals.InvalidIndex(); decalHandle = next )
  2073. {
  2074. ShadowDecal_t& decal = m_ShadowDecals[decalHandle];
  2075. next = m_ShadowDecals[decalHandle].m_NextRender;
  2076. // Skip translucent shadows [ don't add their verts + indices to the render lists ]
  2077. Shadow_t &shadow = m_Shadows[ decal.m_Shadow ];
  2078. if ( shadow.m_FalloffBias == 255 )
  2079. continue;
  2080. bool keepShadow;
  2081. if ( decal.m_DispShadow != DISP_SHADOW_HANDLE_INVALID )
  2082. {
  2083. // Handle shadows on displacements...
  2084. keepShadow = GenerateDispShadowRenderInfo( pRenderContext, decal, info );
  2085. }
  2086. else
  2087. {
  2088. // Handle shadows on normal surfaces
  2089. keepShadow = GenerateNormalShadowRenderInfo( pRenderContext, decal, info );
  2090. }
  2091. // Retire the surface if the shadow didn't actually hit it
  2092. if ( !keepShadow && ShouldCacheVertices( decal ) )
  2093. {
  2094. // If no triangles were generated
  2095. // (the decal was completely clipped off)
  2096. // In this case, remove the decal from the surface cache
  2097. // so next time it'll be faster (for cached decals)
  2098. RemoveShadowDecalFromSurface( decal.m_SurfID, decalHandle );
  2099. }
  2100. }
  2101. }
  2102. //-----------------------------------------------------------------------------
  2103. // Computes information for rendering
  2104. //-----------------------------------------------------------------------------
  2105. void CShadowMgr::ComputeRenderInfo( ShadowDecalRenderInfo_t* pInfo, ShadowHandle_t handle ) const
  2106. {
  2107. const ShadowInfo_t& i = m_Shadows[handle];
  2108. pInfo->m_vTexOrigin = i.m_TexOrigin;
  2109. pInfo->m_vTexSize = i.m_TexSize;
  2110. pInfo->m_flFalloffOffset = i.m_FalloffOffset;
  2111. pInfo->m_flFalloffAmount = i.m_FalloffAmount;
  2112. pInfo->m_flFalloffBias = i.m_FalloffBias;
  2113. float flFalloffDist = i.m_MaxDist - i.m_FalloffOffset;
  2114. pInfo->m_flOOZFalloffDist = ( flFalloffDist > 0.0f ) ? 1.0f / flFalloffDist : 1.0f;
  2115. }
  2116. //-----------------------------------------------------------------------------
  2117. // Adds normal shadows to the mesh builder
  2118. //-----------------------------------------------------------------------------
  2119. int CShadowMgr::AddNormalShadowsToMeshBuilder( CMeshBuilder& meshBuilder, ShadowRenderInfo_t& info )
  2120. {
  2121. // Step through the cache and add all shadows on normal surfaces
  2122. ShadowDecalRenderInfo_t shadow;
  2123. int baseIndex = 0;
  2124. for (int i = 0; i < info.m_Count; ++i)
  2125. {
  2126. // Two loops here, basically to minimize the # of if statements we need
  2127. ShadowVertexCache_t* pVertexCache;
  2128. if (info.m_pCache[i] < 0)
  2129. {
  2130. pVertexCache = &m_TempVertexCache[-info.m_pCache[i]-1];
  2131. }
  2132. else
  2133. {
  2134. pVertexCache = &m_VertexCache[info.m_pCache[i]];
  2135. }
  2136. ShadowVertex_t* pVerts = GetCachedVerts( *pVertexCache );
  2137. g_pShadowMgr->ComputeRenderInfo( &shadow, pVertexCache->m_Shadow );
  2138. int j;
  2139. unsigned char c;
  2140. Vector2D texCoord;
  2141. int vCount = pVertexCache->m_Count - 2;
  2142. if ( vCount <= 0 )
  2143. continue;
  2144. for ( j = 0; j < vCount; ++j, ++pVerts )
  2145. {
  2146. // Transform + offset the texture coords
  2147. Vector2DMultiply( pVerts->m_ShadowSpaceTexCoord.AsVector2D(), shadow.m_vTexSize, texCoord );
  2148. texCoord += shadow.m_vTexOrigin;
  2149. c = ComputeDarkness( pVerts->m_ShadowSpaceTexCoord.z, shadow );
  2150. meshBuilder.Position3fv( pVerts->m_Position.Base() );
  2151. meshBuilder.Color4ub( c, c, c, c );
  2152. meshBuilder.TexCoord2fv( 0, texCoord.Base() );
  2153. meshBuilder.AdvanceVertex();
  2154. meshBuilder.FastIndex( baseIndex );
  2155. meshBuilder.FastIndex( j + baseIndex + 1 );
  2156. meshBuilder.FastIndex( j + baseIndex + 2 );
  2157. }
  2158. Vector2DMultiply( pVerts->m_ShadowSpaceTexCoord.AsVector2D(), shadow.m_vTexSize, texCoord );
  2159. texCoord += shadow.m_vTexOrigin;
  2160. c = ComputeDarkness( pVerts->m_ShadowSpaceTexCoord.z, shadow );
  2161. meshBuilder.Position3fv( pVerts->m_Position.Base() );
  2162. meshBuilder.Color4ub( c, c, c, c );
  2163. meshBuilder.TexCoord2fv( 0, texCoord.Base() );
  2164. meshBuilder.AdvanceVertex();
  2165. ++pVerts;
  2166. Vector2DMultiply( pVerts->m_ShadowSpaceTexCoord.AsVector2D(), shadow.m_vTexSize, texCoord );
  2167. texCoord += shadow.m_vTexOrigin;
  2168. c = ComputeDarkness( pVerts->m_ShadowSpaceTexCoord.z, shadow );
  2169. meshBuilder.Position3fv( pVerts->m_Position.Base() );
  2170. meshBuilder.Color4ub( c, c, c, c );
  2171. meshBuilder.TexCoord2fv( 0, texCoord.Base() );
  2172. meshBuilder.AdvanceVertex();
  2173. // Update the base index
  2174. baseIndex += vCount + 2;
  2175. }
  2176. return baseIndex;
  2177. }
  2178. //-----------------------------------------------------------------------------
  2179. // Adds displacement shadows to the mesh builder
  2180. //-----------------------------------------------------------------------------
  2181. int CShadowMgr::AddDisplacementShadowsToMeshBuilder( CMeshBuilder& meshBuilder,
  2182. ShadowRenderInfo_t& info, int baseIndex )
  2183. {
  2184. if ( !r_DrawDisp.GetBool() )
  2185. return baseIndex;
  2186. // Step through the cache and add all shadows on displacement surfaces
  2187. for (int i = 0; i < info.m_DispCount; ++i)
  2188. {
  2189. baseIndex = DispInfo_AddShadowsToMeshBuilder( meshBuilder, info.m_pDispCache[i], baseIndex );
  2190. }
  2191. return baseIndex;
  2192. }
  2193. //-----------------------------------------------------------------------------
  2194. // The following methods will display debugging info in the middle of each shadow decal
  2195. //-----------------------------------------------------------------------------
  2196. static void DrawShadowID( ShadowHandle_t shadowHandle, const Vector &vecCentroid )
  2197. {
  2198. #ifndef SWDS
  2199. char buf[32];
  2200. Q_snprintf(buf, sizeof( buf ), "%d", shadowHandle );
  2201. CDebugOverlay::AddTextOverlay( vecCentroid, 0, buf );
  2202. #endif
  2203. }
  2204. void CShadowMgr::RenderDebuggingInfo( const ShadowRenderInfo_t &info, ShadowDebugFunc_t func )
  2205. {
  2206. // Step through the cache and add all shadows on normal surfaces
  2207. for (int i = 0; i < info.m_Count; ++i)
  2208. {
  2209. ShadowVertexCache_t* pVertexCache;
  2210. if (info.m_pCache[i] < 0)
  2211. {
  2212. pVertexCache = &m_TempVertexCache[-info.m_pCache[i]-1];
  2213. }
  2214. else
  2215. {
  2216. pVertexCache = &m_VertexCache[info.m_pCache[i]];
  2217. }
  2218. ShadowVertex_t* pVerts = GetCachedVerts( *pVertexCache );
  2219. Vector vecNormal;
  2220. float flTotalArea = 0.0f;
  2221. Vector vecCentroid(0,0,0);
  2222. Vector vecApex = pVerts[0].m_Position;
  2223. int vCount = pVertexCache->m_Count;
  2224. for ( int j = 0; j < vCount - 2; ++j )
  2225. {
  2226. Vector v1 = pVerts[j + 1].m_Position;
  2227. Vector v2 = pVerts[j + 2].m_Position;
  2228. CrossProduct( v2 - v1, v1 - vecApex, vecNormal );
  2229. float flArea = vecNormal.Length();
  2230. flTotalArea += flArea;
  2231. vecCentroid += (vecApex + v1 + v2) * flArea / 3.0f;
  2232. }
  2233. if (flTotalArea)
  2234. {
  2235. vecCentroid /= flTotalArea;
  2236. }
  2237. func( pVertexCache->m_Shadow, vecCentroid );
  2238. }
  2239. }
  2240. //-----------------------------------------------------------------------------
  2241. // Renders shadows that all share a material enumeration
  2242. //-----------------------------------------------------------------------------
  2243. void CShadowMgr::RenderShadowList( IMatRenderContext *pRenderContext, ShadowDecalHandle_t decalHandle, const VMatrix* pModelToWorld )
  2244. {
  2245. //=============================================================================
  2246. // HPE_BEGIN:
  2247. // [smessick] Make sure we don't overflow our caches.
  2248. //=============================================================================
  2249. if ( m_DecalsToRender > m_ShadowDecalCache.Count() )
  2250. {
  2251. // Don't grow past the MAX_SHADOW_DECAL_CACHE_COUNT cap.
  2252. int diff = min( m_DecalsToRender, (int)MAX_SHADOW_DECAL_CACHE_COUNT ) - m_ShadowDecalCache.Count();
  2253. if ( diff > 0 )
  2254. {
  2255. // Grow the cache.
  2256. m_ShadowDecalCache.Grow( diff );
  2257. DevMsg( "[CShadowMgr::RenderShadowList] growing shadow decal cache (decals: %d, cache: %d, diff: %d).\n", m_DecalsToRender, m_ShadowDecalCache.Count(), diff );
  2258. }
  2259. }
  2260. if ( m_DecalsToRender > m_DispShadowDecalCache.Count() )
  2261. {
  2262. // Don't grow past the MAX_SHADOW_DECAL_CACHE_COUNT cap.
  2263. int diff = min( m_DecalsToRender, (int)MAX_SHADOW_DECAL_CACHE_COUNT ) - m_DispShadowDecalCache.Count();
  2264. if ( diff > 0 )
  2265. {
  2266. // Grow the cache.
  2267. m_DispShadowDecalCache.Grow( diff );
  2268. DevMsg( "[CShadowMgr::RenderShadowList] growing disp shadow decal cache (decals: %d, cache: %d, diff: %d).\n", m_DecalsToRender, m_DispShadowDecalCache.Count(), diff );
  2269. }
  2270. }
  2271. //=============================================================================
  2272. // HPE_END
  2273. //=============================================================================
  2274. // Set the render state...
  2275. Shadow_t& shadow = m_Shadows[m_ShadowDecals[decalHandle].m_Shadow];
  2276. if ( r_shadowwireframe.GetInt() == 0 )
  2277. {
  2278. pRenderContext->Bind( shadow.m_pMaterial, shadow.m_pBindProxy );
  2279. }
  2280. else
  2281. {
  2282. pRenderContext->Bind( g_materialWorldWireframe );
  2283. }
  2284. // Blow away the temporary vertex cache (for normal surfaces)
  2285. ClearTempCache();
  2286. // Set up rendering info structure
  2287. ShadowRenderInfo_t info;
  2288. //=============================================================================
  2289. // HPE_BEGIN:
  2290. // [smessick] This code used to create the cache dynamically on the stack.
  2291. //=============================================================================
  2292. info.m_pCache = m_ShadowDecalCache.Base();
  2293. info.m_pDispCache = m_DispShadowDecalCache.Base();
  2294. //=============================================================================
  2295. // HPE_END
  2296. //=============================================================================
  2297. info.m_pModelToWorld = pModelToWorld;
  2298. if ( pModelToWorld )
  2299. {
  2300. MatrixInverseTR( *pModelToWorld, info.m_WorldToModel );
  2301. }
  2302. info.m_nMaxIndices = pRenderContext->GetMaxIndicesToRender();
  2303. info.m_nMaxVertices = pRenderContext->GetMaxVerticesToRender( shadow.m_pMaterial );
  2304. // Iterate over all decals in the decal list and generate polygon lists
  2305. // Creating them from scratch if their shadow poly cache is invalid
  2306. GenerateShadowRenderInfo(pRenderContext, decalHandle, info);
  2307. Assert( info.m_Count <= m_DecalsToRender );
  2308. Assert( info.m_DispCount <= m_DecalsToRender );
  2309. //=============================================================================
  2310. // HPE_BEGIN:
  2311. // [smessick] Also check against the max.
  2312. //=============================================================================
  2313. Assert( info.m_Count <= m_ShadowDecalCache.Count() &&
  2314. info.m_Count <= MAX_SHADOW_DECAL_CACHE_COUNT );
  2315. Assert( info.m_DispCount <= m_DispShadowDecalCache.Count() &&
  2316. info.m_DispCount <= MAX_SHADOW_DECAL_CACHE_COUNT );
  2317. //=============================================================================
  2318. // HPE_END
  2319. //=============================================================================
  2320. // Now that the vertex lists are created, render them
  2321. IMesh* pMesh = pRenderContext->GetDynamicMesh();
  2322. CMeshBuilder meshBuilder;
  2323. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, info.m_VertexCount, info.m_IndexCount );
  2324. // Add in shadows from both normal surfaces + displacement surfaces
  2325. int baseIndex = AddNormalShadowsToMeshBuilder( meshBuilder, info );
  2326. AddDisplacementShadowsToMeshBuilder( meshBuilder, info, baseIndex );
  2327. meshBuilder.End();
  2328. pMesh->Draw();
  2329. if (r_shadowids.GetInt() != 0)
  2330. {
  2331. RenderDebuggingInfo( info, DrawShadowID );
  2332. }
  2333. }
  2334. //-----------------------------------------------------------------------------
  2335. // Set the number of world material buckets. This should get called on level load.
  2336. //-----------------------------------------------------------------------------
  2337. void CShadowMgr::SetNumWorldMaterialBuckets( int numMaterialSortBins )
  2338. {
  2339. m_NumWorldMaterialBuckets = numMaterialSortBins;
  2340. FlashlightHandle_t flashlightID;
  2341. for( flashlightID = m_FlashlightStates.Head();
  2342. flashlightID != m_FlashlightStates.InvalidIndex();
  2343. flashlightID = m_FlashlightStates.Next( flashlightID ) )
  2344. {
  2345. m_FlashlightStates[flashlightID].m_MaterialBuckets.SetNumMaterialSortIDs( numMaterialSortBins );
  2346. m_FlashlightStates[flashlightID].m_OccluderBuckets.SetNumMaterialSortIDs( numMaterialSortBins );
  2347. }
  2348. ClearAllFlashlightMaterialBuckets();
  2349. }
  2350. //-----------------------------------------------------------------------------
  2351. // Per frame call to clear all of the flashlight world material buckets.
  2352. //-----------------------------------------------------------------------------
  2353. void CShadowMgr::ClearAllFlashlightMaterialBuckets( void )
  2354. {
  2355. if ( IsX360() || r_flashlight_version2.GetInt() )
  2356. return;
  2357. FlashlightHandle_t flashlightID;
  2358. for( flashlightID = m_FlashlightStates.Head();
  2359. flashlightID != m_FlashlightStates.InvalidIndex();
  2360. flashlightID = m_FlashlightStates.Next( flashlightID ) )
  2361. {
  2362. m_FlashlightStates[flashlightID].m_MaterialBuckets.Flush();
  2363. }
  2364. }
  2365. //-----------------------------------------------------------------------------
  2366. // Allocate world material buckets for a particular flashlight. This should get called on flashlight creation.
  2367. //-----------------------------------------------------------------------------
  2368. void CShadowMgr::AllocFlashlightMaterialBuckets( FlashlightHandle_t flashlightID )
  2369. {
  2370. Assert( m_FlashlightStates.MaxElementIndex() >= flashlightID );
  2371. m_FlashlightStates[flashlightID].m_MaterialBuckets.SetNumMaterialSortIDs( m_NumWorldMaterialBuckets );
  2372. m_FlashlightStates[flashlightID].m_OccluderBuckets.SetNumMaterialSortIDs( m_NumWorldMaterialBuckets );
  2373. }
  2374. //-----------------------------------------------------------------------------
  2375. // Update a particular flashlight's state.
  2376. //-----------------------------------------------------------------------------
  2377. void CShadowMgr::UpdateFlashlightState( ShadowHandle_t shadowHandle, const FlashlightState_t &lightState )
  2378. {
  2379. m_FlashlightStates[m_Shadows[shadowHandle].m_FlashlightHandle].m_FlashlightState = lightState;
  2380. }
  2381. void CShadowMgr::SetFlashlightDepthTexture( ShadowHandle_t shadowHandle, ITexture *pFlashlightDepthTexture, unsigned char ucShadowStencilBit )
  2382. {
  2383. m_Shadows[shadowHandle].m_pFlashlightDepthTexture = pFlashlightDepthTexture;
  2384. m_Shadows[shadowHandle].m_ucShadowStencilBit = ucShadowStencilBit;
  2385. }
  2386. bool ScreenSpaceRectFromPoints( IMatRenderContext *pRenderContext, Vector vClippedPolygons[8][10], int *pNumPoints, int nNumPolygons, int *nLeft, int *nTop, int *nRight, int *nBottom )
  2387. {
  2388. if( nNumPolygons == 0 )
  2389. return false;
  2390. VMatrix matView, matProj, matViewProj;
  2391. pRenderContext->GetMatrix( MATERIAL_VIEW, &matView );
  2392. pRenderContext->GetMatrix( MATERIAL_PROJECTION, &matProj );
  2393. MatrixMultiply( matProj, matView, matViewProj );
  2394. float fMinX, fMaxX, fMinY, fMaxY; // Init bounding rect
  2395. fMinX = fMinY = FLT_MAX;
  2396. fMaxX = fMaxY = -FLT_MAX;
  2397. for ( int i=0; i<nNumPolygons; i++ )
  2398. {
  2399. for ( int j=0; j<pNumPoints[i]; j++ )
  2400. {
  2401. Vector vScreenSpacePoint;
  2402. matViewProj.V3Mul( vClippedPolygons[i][j], vScreenSpacePoint ); // Transform from World to screen space
  2403. fMinX = fpmin( fMinX, vScreenSpacePoint.x ); // Update mins/maxes
  2404. fMaxX = fpmax( fMaxX, vScreenSpacePoint.x ); //
  2405. fMinY = fpmin( fMinY, -vScreenSpacePoint.y ); // These are in -1 to +1 range
  2406. fMaxY = fpmax( fMaxY, -vScreenSpacePoint.y ); //
  2407. }
  2408. }
  2409. int nWidth, nHeight;
  2410. g_pMaterialSystem->GetBackBufferDimensions( nWidth, nHeight ); // Get render target dimensions
  2411. *nLeft = ((fMinX * 0.5f + 0.5f) * (float) nWidth ) - 1; // Convert to render target pixel units
  2412. *nTop = ((fMinY * 0.5f + 0.5f) * (float) nHeight) - 1;
  2413. *nRight = ((fMaxX * 0.5f + 0.5f) * (float) nWidth ) + 1;
  2414. *nBottom = ((fMaxY * 0.5f + 0.5f) * (float) nHeight) + 1;
  2415. *nLeft = clamp( *nLeft, 0, nWidth ); // Clamp to render target dimensions
  2416. *nTop = clamp( *nTop, 0, nHeight );
  2417. *nRight = clamp( *nRight, 0, nWidth );
  2418. *nBottom = clamp( *nBottom, 0, nHeight );
  2419. Assert( (*nLeft <= *nRight) && (*nTop <= *nBottom) );
  2420. // Do we have an actual subrect of the whole screen?
  2421. bool bWithinBounds = ((*nLeft > 0 ) || (*nTop > 0) || (*nRight < nWidth) || (*nBottom < nHeight));
  2422. // Compute valid area
  2423. nWidth = (*nRight - *nLeft);
  2424. nHeight = (*nBottom - *nTop);
  2425. int nArea = ( nWidth > 0 ) && ( nHeight > 0 ) ? nWidth * nHeight : 0;
  2426. // Valid rect?
  2427. return bWithinBounds && (nArea > 0);
  2428. }
  2429. // Turn this optimization off by default
  2430. static ConVar r_flashlightclip("r_flashlightclip", "0", FCVAR_CHEAT );
  2431. static ConVar r_flashlightdrawclip("r_flashlightdrawclip", "0", FCVAR_CHEAT );
  2432. static ConVar r_flashlightscissor( "r_flashlightscissor", "1", 0 );
  2433. void ExtractFrustumPlanes( Frustum frustumPlanes, float flPlaneEpsilon )
  2434. {
  2435. const CViewSetup &view = g_EngineRenderer->ViewGetCurrent();
  2436. float flFOVy = CalcFovY( view.fov, view.m_flAspectRatio );
  2437. Frustum_t frustum;
  2438. Vector vForward, vRight, vUp;
  2439. AngleVectors( view.angles, &vForward, &vRight, &vUp );
  2440. GeneratePerspectiveFrustum( view.origin, vForward, vRight, vUp,
  2441. view.zNear + flPlaneEpsilon, view.zFar - flPlaneEpsilon, // Apply epsilon to near and far
  2442. view.fov, flFOVy, frustum );
  2443. // Copy out to the planes that the engine renderer uses.
  2444. for( int i=0; i < FRUSTUM_NUMPLANES; i++ )
  2445. {
  2446. frustumPlanes[i].m_Normal = frustum.GetPlane(i)->normal;
  2447. frustumPlanes[i].m_Dist = frustum.GetPlane(i)->dist;
  2448. }
  2449. }
  2450. void ConstructNearAndFarPolygons( Vector *pVecNearPlane, Vector *pVecFarPlane, float flPlaneEpsilon )
  2451. {
  2452. const CViewSetup &view = g_EngineRenderer->ViewGetCurrent();
  2453. float fovY = CalcFovY( view.fov, view.m_flAspectRatio );
  2454. // Compute near and far plane half-width and half-height
  2455. float flTanHalfAngleRadians = tan( view.fov * ( 0.5f * M_PI / 180.0f ) );
  2456. float flHalfNearWidth = flTanHalfAngleRadians * ( view.zNear + flPlaneEpsilon );
  2457. float flHalfFarWidth = flTanHalfAngleRadians * ( view.zFar - flPlaneEpsilon );
  2458. flTanHalfAngleRadians = tan( fovY * ( 0.5f * M_PI / 180.0f ) );
  2459. float flHalfNearHeight = flTanHalfAngleRadians * ( view.zNear + flPlaneEpsilon );
  2460. float flHalfFarHeight = flTanHalfAngleRadians * ( view.zFar - flPlaneEpsilon );
  2461. // World-space orientation of viewer
  2462. Vector vForward, vRight, vUp;
  2463. AngleVectors( view.angles, &vForward, &vRight, &vUp );
  2464. vForward.NormalizeInPlace();
  2465. vRight.NormalizeInPlace();
  2466. vUp.NormalizeInPlace();
  2467. // Center of near and far planes in world space
  2468. Vector vCenterNear = view.origin + vForward * ( view.zNear + flPlaneEpsilon );
  2469. Vector vCenterFar = view.origin + vForward * ( view.zFar - flPlaneEpsilon );
  2470. pVecNearPlane[0] = vCenterNear - ( vRight * flHalfNearWidth ) - ( vUp * flHalfNearHeight );
  2471. pVecNearPlane[1] = vCenterNear - ( vRight * flHalfNearWidth ) + ( vUp * flHalfNearHeight );
  2472. pVecNearPlane[2] = vCenterNear + ( vRight * flHalfNearWidth ) + ( vUp * flHalfNearHeight );
  2473. pVecNearPlane[3] = vCenterNear + ( vRight * flHalfNearWidth ) - ( vUp * flHalfNearHeight );
  2474. pVecFarPlane[0] = vCenterNear - ( vRight * flHalfFarWidth ) - ( vUp * flHalfFarHeight );
  2475. pVecFarPlane[1] = vCenterNear + ( vRight * flHalfFarWidth ) - ( vUp * flHalfFarHeight );
  2476. pVecFarPlane[2] = vCenterNear + ( vRight * flHalfFarWidth ) + ( vUp * flHalfFarHeight );
  2477. pVecFarPlane[3] = vCenterNear - ( vRight * flHalfFarWidth ) + ( vUp * flHalfFarHeight );
  2478. }
  2479. void DrawDebugPolygon( int nNumVerts, Vector *pVecPoints, bool bFrontFacing, bool bNearPlane )
  2480. {
  2481. int r=0, g=0, b=0;
  2482. if ( bFrontFacing )
  2483. b = 255;
  2484. else
  2485. r = 255;
  2486. if ( bNearPlane ) // Draw near plane green for visualization
  2487. {
  2488. r = b = 0;
  2489. g = 255;
  2490. }
  2491. // Draw triangles fanned out from vertex zero
  2492. for (int i=1; i<(nNumVerts-1); i++)
  2493. {
  2494. Vector v0 = pVecPoints[0];
  2495. Vector v1 = pVecPoints[bFrontFacing ? i : i+1];
  2496. Vector v2 = pVecPoints[bFrontFacing ? i+1 : i];
  2497. CDebugOverlay::AddTriangleOverlay(v0, v1, v2, r, g, b, 20, true, 0 );
  2498. }
  2499. // Draw solid lines around the polygon
  2500. for (int i=0; i<nNumVerts; i++)
  2501. {
  2502. Vector v0 = pVecPoints[i];
  2503. Vector v1 = pVecPoints[ (i+1) % nNumVerts];
  2504. CDebugOverlay::AddLineOverlay( v0, v1, 255, 255, 255, 255, false, 0);
  2505. }
  2506. }
  2507. void DrawPolygonToStencil( IMatRenderContext *pRenderContext, int nNumVerts, Vector *pVecPoints, bool bFrontFacing, bool bNearPlane )
  2508. {
  2509. IMaterial *pMaterial = materials->FindMaterial( "engine/writestencil", TEXTURE_GROUP_OTHER, true );
  2510. pRenderContext->Bind( pMaterial );
  2511. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  2512. pRenderContext->MatrixMode( MATERIAL_MODEL );
  2513. pRenderContext->PushMatrix();
  2514. pRenderContext->LoadIdentity();
  2515. CMeshBuilder meshBuilder;
  2516. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nNumVerts-2 );
  2517. // Fan out from vertex zero
  2518. for (int i=1; i<(nNumVerts-1); i++)
  2519. {
  2520. meshBuilder.Position3f( pVecPoints[0].x, pVecPoints[0].y, pVecPoints[0].z );
  2521. meshBuilder.AdvanceVertex();
  2522. int index = bFrontFacing ? i : i+1;
  2523. meshBuilder.Position3f( pVecPoints[index].x, pVecPoints[index].y, pVecPoints[index].z );
  2524. meshBuilder.AdvanceVertex();
  2525. index = bFrontFacing ? i+1 : i;
  2526. meshBuilder.Position3f( pVecPoints[index].x, pVecPoints[index].y, pVecPoints[index].z );
  2527. meshBuilder.AdvanceVertex();
  2528. }
  2529. meshBuilder.End( false, true );
  2530. pRenderContext->MatrixMode( MATERIAL_MODEL );
  2531. pRenderContext->PopMatrix();
  2532. }
  2533. // Determine if two Vectors are sufficiently close (Manhattan-ish distance, not Euclidean)
  2534. bool SufficientlyClose( Vector v1, Vector v2, float flEpsilon )
  2535. {
  2536. if ( fabs( v1.x - v2.x ) > flEpsilon ) // Bail if x components are sufficiently different
  2537. return false;
  2538. if ( fabs( v1.y - v2.y ) > flEpsilon ) // Bail if y components are sufficiently different
  2539. return false;
  2540. if ( fabs( v1.z - v2.z ) > flEpsilon ) // Bail if z components are sufficiently different
  2541. return false;
  2542. return true;
  2543. }
  2544. int ClipPlaneToFrustum( Vector *pInPoints, Vector *pOutPoints, Vector *pVecWorldFrustumPoints )
  2545. {
  2546. Vector vClipPing[10]; // Vector lists to ping-pong between while clipping
  2547. Vector vClipPong[10]; //
  2548. bool bPing = true; // Ping holds the latest polygon
  2549. vClipPing[0] = pInPoints[0]; // Copy into Ping
  2550. vClipPing[1] = pInPoints[1];
  2551. vClipPing[2] = pInPoints[2];
  2552. vClipPing[3] = pInPoints[3];
  2553. int nNumPoints = 4;
  2554. for ( int i=0; i < 6; i++ )
  2555. {
  2556. Vector vNormal;
  2557. float flDist;
  2558. if ( nNumPoints < 3 ) // If we're already clipped away, bail out entirely
  2559. break;
  2560. Vector *pClipPolygon = pVecWorldFrustumPoints+(4*i); // Polygon defining clip plane
  2561. ComputeTrianglePlane( pClipPolygon[0], pClipPolygon[1], pClipPolygon[2], vNormal, flDist ); // Compute plane normal and dist
  2562. if ( bPing )
  2563. nNumPoints = ClipPolyToPlane( vClipPing, nNumPoints, vClipPong, vNormal, flDist ); // Clip Ping into Pong
  2564. else
  2565. nNumPoints = ClipPolyToPlane( vClipPong, nNumPoints, vClipPing, vNormal, flDist ); // Clip Pong into Ping
  2566. bPing = !bPing; // Flip buffers
  2567. }
  2568. if ( nNumPoints < 3)
  2569. return 0;
  2570. if ( bPing )
  2571. memcpy( pOutPoints, vClipPing, nNumPoints * sizeof(Vector) );
  2572. else
  2573. memcpy( pOutPoints, vClipPong, nNumPoints * sizeof(Vector) );
  2574. return nNumPoints;
  2575. }
  2576. void CShadowMgr::SetStencilAndScissor( IMatRenderContext *pRenderContext, FlashlightInfo_t &flashlightInfo, bool bUseStencil )
  2577. {
  2578. VMatrix matFlashlightToWorld;
  2579. MatrixInverseGeneral( m_Shadows[flashlightInfo.m_Shadow].m_WorldToShadow, matFlashlightToWorld );
  2580. // Eight points defining the frustum in Flashlight space
  2581. 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
  2582. 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
  2583. 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
  2584. 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
  2585. 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
  2586. 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
  2587. // Transform points to world space
  2588. Vector vWorldFrustumPoints[24];
  2589. for ( int i=0; i < 24; i++ )
  2590. {
  2591. matFlashlightToWorld.V3Mul( vFrustumPoints[i], vWorldFrustumPoints[i] );
  2592. }
  2593. // Express near and far planes of View frustum in world space
  2594. Frustum frustumPlanes;
  2595. const float flPlaneEpsilon = 0.4f;
  2596. ExtractFrustumPlanes( frustumPlanes, flPlaneEpsilon );
  2597. Vector vNearNormal = frustumPlanes[FRUSTUM_NEARZ].m_Normal;
  2598. Vector vFarNormal = frustumPlanes[FRUSTUM_FARZ].m_Normal;
  2599. float flNearDist = frustumPlanes[FRUSTUM_NEARZ].m_Dist;
  2600. float flFarDist = frustumPlanes[FRUSTUM_FARZ].m_Dist;
  2601. Vector vTempFace[5];
  2602. Vector vClippedFace[6];
  2603. Vector vClippedPolygons[8][10]; // Array of up to eight polygons (10 verts is more than enough for each)
  2604. int nNumVertices[8]; // Number vertices on each of the of clipped polygons
  2605. int nNumPolygons = 0; // How many polygons have survived the clip
  2606. // Clip each face individually to near and far planes
  2607. for ( int i=0; i < 6; i++ )
  2608. {
  2609. Vector *inVerts = vWorldFrustumPoints+(4*i); // Series of quadrilateral inputs
  2610. Vector *tempVerts = vTempFace;
  2611. Vector *outVerts = vClippedFace;
  2612. int nClipCount = ClipPolyToPlane( inVerts, 4, tempVerts, vNearNormal, flNearDist ); // need to set fOnPlaneEpsilon?
  2613. if ( nClipCount > 2 ) // If the polygon survived the near clip, try the far as well
  2614. {
  2615. nClipCount = ClipPolyToPlane( tempVerts, nClipCount, outVerts, vFarNormal, flFarDist ); // need to set fOnPlaneEpsilon?
  2616. if ( nClipCount > 2 ) // If we still have a poly after clipping to both planes, add it to the list
  2617. {
  2618. memcpy( vClippedPolygons[nNumPolygons], outVerts, nClipCount * sizeof (Vector) );
  2619. nNumVertices[nNumPolygons] = nClipCount;
  2620. nNumPolygons++;
  2621. }
  2622. }
  2623. }
  2624. // Construct polygons for near and far planes
  2625. Vector vNearPlane[4], vFarPlane[4];
  2626. ConstructNearAndFarPolygons( vNearPlane, vFarPlane, flPlaneEpsilon );
  2627. bool bNearPlane = false;
  2628. // Clip near plane to flashlight frustum and tack on to list
  2629. int nClipCount = ClipPlaneToFrustum( vNearPlane, vClippedPolygons[nNumPolygons], vWorldFrustumPoints );
  2630. if ( nClipCount > 2 ) // If the near plane clipped and resulted in a polygon, take note in the polygon list
  2631. {
  2632. nNumVertices[nNumPolygons] = nClipCount;
  2633. nNumPolygons++;
  2634. bNearPlane = true;
  2635. }
  2636. /*
  2637. TODO: do we even need to do the far plane?
  2638. // Clip near plane to flashlight frustum and tack on to list
  2639. nClipCount = ClipPlaneToFrustum( vFarPlane, vClippedPolygons[nNumPolygons], vWorldFrustumPoints );
  2640. if ( nClipCount > 2 ) // If the near plane clipped and resulted in a polygon, take note in the polygon list
  2641. {
  2642. nNumVertices[nNumPolygons] = nClipCount;
  2643. nNumPolygons++;
  2644. }
  2645. */
  2646. // Fuse positions of any verts which are within epsilon
  2647. for (int i=0; i<nNumPolygons; i++) // For each polygon
  2648. {
  2649. for (int j=0; j<nNumVertices[i]; j++) // For each vertex
  2650. {
  2651. for (int k=i+1; k<nNumPolygons; k++) // For each later polygon
  2652. {
  2653. for (int m=0; m<nNumVertices[k]; m++) // For each vertex
  2654. {
  2655. if ( SufficientlyClose(vClippedPolygons[i][j], vClippedPolygons[k][m], 0.1f) )
  2656. {
  2657. vClippedPolygons[k][m] = vClippedPolygons[i][j];
  2658. }
  2659. }
  2660. }
  2661. }
  2662. }
  2663. // Calculate scissoring rect
  2664. flashlightInfo.m_FlashlightState.m_bScissor = false;
  2665. if ( r_flashlightscissor.GetBool() && (nNumPolygons > 0) )
  2666. {
  2667. int nLeft, nTop, nRight, nBottom;
  2668. flashlightInfo.m_FlashlightState.m_bScissor = ScreenSpaceRectFromPoints( pRenderContext, vClippedPolygons, nNumVertices, nNumPolygons, &nLeft, &nTop, &nRight, &nBottom );
  2669. if ( flashlightInfo.m_FlashlightState.m_bScissor )
  2670. {
  2671. flashlightInfo.m_FlashlightState.m_nLeft = nLeft;
  2672. flashlightInfo.m_FlashlightState.m_nTop = nTop;
  2673. flashlightInfo.m_FlashlightState.m_nRight = nRight;
  2674. flashlightInfo.m_FlashlightState.m_nBottom = nBottom;
  2675. }
  2676. }
  2677. if ( r_flashlightdrawclip.GetBool() && r_flashlightclip.GetBool() && bUseStencil )
  2678. {
  2679. // Draw back facing debug polygons
  2680. for (int i=0; i<nNumPolygons; i++)
  2681. {
  2682. DrawDebugPolygon( nNumVertices[i], vClippedPolygons[i], false, false );
  2683. }
  2684. /*
  2685. // Draw front facing debug polygons
  2686. for (int i=0; i<nNumPolygons; i++)
  2687. {
  2688. DrawDebugPolygon( nNumVertices[i], vClippedPolygons[i], true, bNearPlane && (i == nNumPolygons-1) );
  2689. }
  2690. */
  2691. }
  2692. if ( r_flashlightclip.GetBool() && bUseStencil )
  2693. {
  2694. /*
  2695. // The traditional settings...
  2696. // Set up to set stencil bit on front facing polygons
  2697. pRenderContext->SetStencilEnable( true );
  2698. pRenderContext->SetStencilFailOperation( STENCILOPERATION_KEEP ); // Stencil fails
  2699. pRenderContext->SetStencilZFailOperation( STENCILOPERATION_KEEP ); // Stencil passes but depth fails
  2700. pRenderContext->SetStencilPassOperation( STENCILOPERATION_REPLACE ); // Z and stencil both pass
  2701. pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_ALWAYS ); // Stencil always pass
  2702. pRenderContext->SetStencilReferenceValue( m_Shadows[flashlightInfo.m_Shadow].m_ucShadowStencilBit );
  2703. pRenderContext->SetStencilTestMask( m_Shadows[flashlightInfo.m_Shadow].m_ucShadowStencilBit );
  2704. pRenderContext->SetStencilWriteMask( m_Shadows[flashlightInfo.m_Shadow].m_ucShadowStencilBit ); // Bit mask which is specific to this shadow
  2705. */
  2706. // Just blast front faces into the stencil buffer no matter what...
  2707. pRenderContext->SetStencilEnable( true );
  2708. pRenderContext->SetStencilFailOperation( STENCILOPERATION_REPLACE ); // Stencil fails
  2709. pRenderContext->SetStencilZFailOperation( STENCILOPERATION_REPLACE ); // Stencil passes but depth fails
  2710. pRenderContext->SetStencilPassOperation( STENCILOPERATION_REPLACE ); // Z and stencil both pass
  2711. pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_ALWAYS ); // Stencil always pass
  2712. pRenderContext->SetStencilReferenceValue( m_Shadows[flashlightInfo.m_Shadow].m_ucShadowStencilBit );
  2713. pRenderContext->SetStencilTestMask( m_Shadows[flashlightInfo.m_Shadow].m_ucShadowStencilBit );
  2714. pRenderContext->SetStencilWriteMask( m_Shadows[flashlightInfo.m_Shadow].m_ucShadowStencilBit ); // Bit mask which is specific to this shadow
  2715. for ( int i=0; i<nNumPolygons; i++ ) // Set the stencil bit on front facing
  2716. {
  2717. DrawPolygonToStencil( pRenderContext, nNumVertices[i], vClippedPolygons[i], true, false );
  2718. }
  2719. /*
  2720. pRenderContext->SetStencilReferenceValue( 0x00000000 ); // All bits cleared
  2721. for (int i=0; i<nNumPolygons; i++) // Clear the stencil bit on back facing
  2722. {
  2723. DrawPolygonToStencil( nNumVertices[i], vClippedPolygons[i], false, false );
  2724. }
  2725. */
  2726. pRenderContext->SetStencilEnable( false );
  2727. }
  2728. }
  2729. //---------------------------------------------------------------------------------------
  2730. // Set masking stencil bits for all flashlights
  2731. //---------------------------------------------------------------------------------------
  2732. void CShadowMgr::SetFlashlightStencilMasks( bool bDoMasking )
  2733. {
  2734. VPROF_BUDGET( "CShadowMgr::RenderFlashlights", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  2735. if ( IsX360() || r_flashlight_version2.GetInt() )
  2736. return;
  2737. // Bail out if we're not doing any of these optimizations
  2738. if ( !( r_flashlightclip.GetBool() || r_flashlightscissor.GetBool()) )
  2739. return;
  2740. FlashlightHandle_t flashlightID = m_FlashlightStates.Head();
  2741. if ( flashlightID == m_FlashlightStates.InvalidIndex() )
  2742. return;
  2743. CMatRenderContextPtr pRenderContext( materials );
  2744. for( ;
  2745. flashlightID != m_FlashlightStates.InvalidIndex();
  2746. flashlightID = m_FlashlightStates.Next( flashlightID ) )
  2747. {
  2748. FlashlightInfo_t &flashlightInfo = m_FlashlightStates[flashlightID];
  2749. SetStencilAndScissor( pRenderContext, flashlightInfo, m_Shadows[flashlightInfo.m_Shadow].m_pFlashlightDepthTexture != NULL );
  2750. }
  2751. }
  2752. void CShadowMgr::DisableStencilAndScissorMasking( IMatRenderContext *pRenderContext )
  2753. {
  2754. if ( r_flashlightclip.GetBool() )
  2755. {
  2756. pRenderContext->SetStencilEnable( false );
  2757. }
  2758. // Scissor even if we're not shadow depth mapping
  2759. if ( r_flashlightscissor.GetBool() )
  2760. {
  2761. pRenderContext->SetScissorRect( -1, -1, -1, -1, false );
  2762. }
  2763. }
  2764. //---------------------------------------------------------------------------------------
  2765. // Enable/Disable masking based on stencil bit
  2766. //---------------------------------------------------------------------------------------
  2767. void CShadowMgr::EnableStencilAndScissorMasking( IMatRenderContext *pRenderContext, const FlashlightInfo_t &flashlightInfo, bool bDoMasking )
  2768. {
  2769. // Bail out if we're not doing any of these optimizations
  2770. if ( !( r_flashlightclip.GetBool() || r_flashlightscissor.GetBool()) || !bDoMasking )
  2771. return;
  2772. // Only turn on scissor when rendering to the back buffer
  2773. if ( pRenderContext->GetRenderTarget() == NULL )
  2774. {
  2775. // Only do the stencil optimization when shadow depth mapping
  2776. if ( r_flashlightclip.GetBool() && m_Shadows[flashlightInfo.m_Shadow].m_pFlashlightDepthTexture != NULL )
  2777. {
  2778. unsigned char ucShadowStencilBit = m_Shadows[flashlightInfo.m_Shadow].m_ucShadowStencilBit;
  2779. pRenderContext->SetStencilEnable( true );
  2780. pRenderContext->SetStencilFailOperation( STENCILOPERATION_KEEP ); // Stencil fails
  2781. pRenderContext->SetStencilZFailOperation( STENCILOPERATION_KEEP ); // Stencil passes but depth fails
  2782. pRenderContext->SetStencilPassOperation( STENCILOPERATION_KEEP ); // Z and stencil both pass
  2783. pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_EQUAL ); // Bit must be set
  2784. pRenderContext->SetStencilReferenceValue( ucShadowStencilBit ); // Specific bit
  2785. pRenderContext->SetStencilTestMask( ucShadowStencilBit ); // Specific bit
  2786. pRenderContext->SetStencilWriteMask( 0x00000000 );
  2787. }
  2788. // Scissor even if we're not shadow depth mapping
  2789. if ( r_flashlightscissor.GetBool() && flashlightInfo.m_FlashlightState.m_bScissor )
  2790. {
  2791. pRenderContext->SetScissorRect( flashlightInfo.m_FlashlightState.m_nLeft, flashlightInfo.m_FlashlightState.m_nTop,
  2792. flashlightInfo.m_FlashlightState.m_nRight, flashlightInfo.m_FlashlightState.m_nBottom, true );
  2793. }
  2794. }
  2795. else // disable
  2796. {
  2797. DisableStencilAndScissorMasking( pRenderContext );
  2798. }
  2799. }
  2800. //---------------------------------------------------------------------------------------
  2801. // Sets the render states necessary to render a flashlight
  2802. //---------------------------------------------------------------------------------------
  2803. void CShadowMgr::SetFlashlightRenderState( ShadowHandle_t handle )
  2804. {
  2805. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  2806. if ( handle == SHADOW_HANDLE_INVALID )
  2807. {
  2808. pRenderContext->SetFlashlightMode( false );
  2809. return;
  2810. }
  2811. const Shadow_t &shadow = m_Shadows[handle];
  2812. pRenderContext->SetFlashlightMode( true );
  2813. const FlashlightInfo_t &flashlightInfo = m_FlashlightStates[ shadow.m_FlashlightHandle ];
  2814. pRenderContext->SetFlashlightStateEx( flashlightInfo.m_FlashlightState, shadow.m_WorldToShadow, shadow.m_pFlashlightDepthTexture );
  2815. }
  2816. //---------------------------------------------------------------------------------------
  2817. // Render all of the world and displacement surfaces that need to be drawn for flashlights
  2818. //---------------------------------------------------------------------------------------
  2819. void CShadowMgr::RenderFlashlights( bool bDoMasking, const VMatrix* pModelToWorld )
  2820. {
  2821. #ifndef SWDS
  2822. VPROF_BUDGET( "CShadowMgr::RenderFlashlights", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  2823. if ( IsX360() || r_flashlight_version2.GetInt() )
  2824. return;
  2825. if( r_flashlightrender.GetBool()==false )
  2826. return;
  2827. // Draw the projective light sources, which get their material
  2828. // from the surface and not from the shadow.
  2829. // Tell the materialsystem that we are drawing additive flashlight lighting.
  2830. FlashlightHandle_t flashlightID = m_FlashlightStates.Head();
  2831. if ( flashlightID == m_FlashlightStates.InvalidIndex() )
  2832. return;
  2833. bool bWireframe = r_shadowwireframe.GetBool();
  2834. CMatRenderContextPtr pRenderContext( materials );
  2835. PIXEVENT( pRenderContext, "CShadowMgr::RenderFlashlights" );
  2836. pRenderContext->SetFlashlightMode( true );
  2837. for( ;
  2838. flashlightID != m_FlashlightStates.InvalidIndex();
  2839. flashlightID = m_FlashlightStates.Next( flashlightID ) )
  2840. {
  2841. FlashlightInfo_t &flashlightInfo = m_FlashlightStates[flashlightID];
  2842. CMaterialsBuckets<SurfaceHandle_t> &materialBuckets = flashlightInfo.m_MaterialBuckets;
  2843. CMaterialsBuckets<SurfaceHandle_t>::SortIDHandle_t sortIDHandle = materialBuckets.GetFirstUsedSortID();
  2844. if ( sortIDHandle == materialBuckets.InvalidSortIDHandle() )
  2845. continue;
  2846. pRenderContext->SetFlashlightStateEx(flashlightInfo.m_FlashlightState, m_Shadows[flashlightInfo.m_Shadow].m_WorldToShadow, m_Shadows[flashlightInfo.m_Shadow].m_pFlashlightDepthTexture );
  2847. EnableStencilAndScissorMasking( pRenderContext, flashlightInfo, bDoMasking );
  2848. for( ; sortIDHandle != materialBuckets.InvalidSortIDHandle();
  2849. sortIDHandle = materialBuckets.GetNextUsedSortID( sortIDHandle ) )
  2850. {
  2851. int sortID = materialBuckets.GetSortID( sortIDHandle );
  2852. if( bWireframe )
  2853. {
  2854. pRenderContext->Bind( g_materialWorldWireframe );
  2855. }
  2856. else
  2857. {
  2858. pRenderContext->Bind( materialSortInfoArray[sortID].material );
  2859. pRenderContext->BindLightmapPage( materialSortInfoArray[sortID].lightmapPageID );
  2860. }
  2861. CMaterialsBuckets<SurfaceHandle_t>::ElementHandle_t elemHandle;
  2862. // Figure out how many indices we have.
  2863. int numIndices = 0;
  2864. for( elemHandle = materialBuckets.GetElementListHead( sortID );
  2865. elemHandle != materialBuckets.InvalidElementHandle();
  2866. elemHandle = materialBuckets.GetElementListNext( elemHandle ) )
  2867. {
  2868. SurfaceHandle_t surfID = materialBuckets.GetElement( elemHandle );
  2869. if( !SurfaceHasDispInfo( surfID ) )
  2870. {
  2871. numIndices += 3 * ( MSurf_VertCount( surfID ) - 2 );
  2872. }
  2873. }
  2874. if( numIndices > 0 )
  2875. {
  2876. // NOTE: If we ever need to make this faster, we could get larger
  2877. // batches here.
  2878. // Draw this batch.
  2879. #if NEWMESH
  2880. IIndexBuffer *pIndexBuffer = pRenderContext->GetDynamicIndexBuffer( MATERIAL_INDEX_FORMAT_16BIT );
  2881. CIndexBufferBuilder indexBufferBuilder;
  2882. indexBufferBuilder.Begin( pIndexBuffer, numIndices );
  2883. #else
  2884. IMesh *pMesh = pRenderContext->GetDynamicMesh( false, g_WorldStaticMeshes[sortID], 0 );
  2885. CMeshBuilder meshBuilder;
  2886. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 0, numIndices );
  2887. #endif
  2888. for( elemHandle = materialBuckets.GetElementListHead( sortID );
  2889. elemHandle != materialBuckets.InvalidElementHandle();
  2890. elemHandle = materialBuckets.GetElementListNext( elemHandle ) )
  2891. {
  2892. SurfaceHandle_t surfID = materialBuckets.GetElement( elemHandle );
  2893. if( !SurfaceHasDispInfo( surfID ) )
  2894. {
  2895. #if NEWMESH
  2896. BuildIndicesForWorldSurface( indexBufferBuilder, surfID, host_state.worldbrush );
  2897. #else
  2898. BuildIndicesForWorldSurface( meshBuilder, surfID, host_state.worldbrush );
  2899. #endif
  2900. }
  2901. }
  2902. // close out the index buffer
  2903. #if NEWMESH
  2904. indexBufferBuilder.End( false ); // haven't tested this one yet (flashlights)
  2905. // FIXME: IMaterial::GetVertexFormat() should do this stripping (add a separate 'SupportsCompression' accessor)
  2906. VertexFormat_t vertexFormat = materialSortInfoArray[sortID].material->GetVertexFormat() & ~VERTEX_FORMAT_COMPRESSED;
  2907. pRenderContext->BindVertexBuffer( 0, g_WorldStaticMeshes[sortID], 0, materialSortInfoArray[sortID].material->GetVertexFormat() ); // hack fixme. . . use currently bound material format instead of passing in?
  2908. pRenderContext->BindIndexBuffer( pIndexBuffer, 0 );
  2909. pRenderContext->Draw( MATERIAL_TRIANGLES, 0, numIndices );
  2910. #else
  2911. meshBuilder.End( false, true );
  2912. #endif
  2913. }
  2914. // NOTE: If we ever need to make this faster, we could get larger batches here.
  2915. // Draw displacements
  2916. for( elemHandle = materialBuckets.GetElementListHead( sortID );
  2917. elemHandle != materialBuckets.InvalidElementHandle();
  2918. elemHandle = materialBuckets.GetElementListNext( elemHandle ) )
  2919. {
  2920. SurfaceHandle_t surfID = materialBuckets.GetElement( elemHandle );
  2921. if( SurfaceHasDispInfo( surfID ) )
  2922. {
  2923. CDispInfo *pDisp = ( CDispInfo * )MSurf_DispInfo( surfID );
  2924. Assert( pDisp );
  2925. if( bWireframe )
  2926. {
  2927. pDisp->SpecifyDynamicMesh();
  2928. }
  2929. else
  2930. {
  2931. Assert( pDisp && pDisp->m_pMesh && pDisp->m_pMesh->m_pMesh );
  2932. pDisp->m_pMesh->m_pMesh->Draw( pDisp->m_iIndexOffset, pDisp->m_nIndices );
  2933. }
  2934. }
  2935. }
  2936. }
  2937. }
  2938. // Tell the materialsystem that we are finished drawing additive flashlight lighting.
  2939. pRenderContext->SetFlashlightMode( false );
  2940. // Turn off stencil masking
  2941. DisableStencilAndScissorMasking( pRenderContext );
  2942. #endif
  2943. }
  2944. const Frustum_t &CShadowMgr::GetFlashlightFrustum( ShadowHandle_t handle )
  2945. {
  2946. Assert( m_Shadows[handle].m_Flags & SHADOW_FLASHLIGHT );
  2947. Assert( m_Shadows[handle].m_FlashlightHandle != m_Shadows.InvalidIndex() );
  2948. return m_FlashlightStates[m_Shadows[handle].m_FlashlightHandle].m_Frustum;
  2949. }
  2950. const FlashlightState_t &CShadowMgr::GetFlashlightState( ShadowHandle_t handle )
  2951. {
  2952. Assert( m_Shadows[handle].m_Flags & SHADOW_FLASHLIGHT );
  2953. Assert( m_Shadows[handle].m_FlashlightHandle != m_Shadows.InvalidIndex() );
  2954. return m_FlashlightStates[m_Shadows[handle].m_FlashlightHandle].m_FlashlightState;
  2955. }
  2956. void CShadowMgr::DrawFlashlightDecals( int sortGroup, bool bDoMasking )
  2957. {
  2958. VPROF_BUDGET( "CShadowMgr::DrawFlashlightDecals", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  2959. if ( IsX360() || r_flashlight_version2.GetInt() )
  2960. return;
  2961. FlashlightHandle_t flashlightID = m_FlashlightStates.Head();
  2962. if ( flashlightID == m_FlashlightStates.InvalidIndex() )
  2963. return;
  2964. CMatRenderContextPtr pRenderContext( materials );
  2965. pRenderContext->SetFlashlightMode( true );
  2966. for( ;
  2967. flashlightID != m_FlashlightStates.InvalidIndex();
  2968. flashlightID = m_FlashlightStates.Next( flashlightID ) )
  2969. {
  2970. FlashlightInfo_t &flashlightInfo = m_FlashlightStates[flashlightID];
  2971. pRenderContext->SetFlashlightState(flashlightInfo.m_FlashlightState, m_Shadows[flashlightInfo.m_Shadow].m_WorldToShadow );
  2972. EnableStencilAndScissorMasking( pRenderContext, flashlightInfo, bDoMasking );
  2973. DecalSurfaceDraw( pRenderContext, sortGroup );
  2974. }
  2975. // Tell the materialsystem that we are finished drawing additive flashlight lighting.
  2976. pRenderContext->SetFlashlightMode( false );
  2977. // Turn off stencil masking
  2978. DisableStencilAndScissorMasking( pRenderContext );
  2979. }
  2980. void CShadowMgr::DrawFlashlightDecalsOnDisplacements( int sortGroup, CDispInfo *visibleDisps[MAX_MAP_DISPINFO], int nVisibleDisps, bool bDoMasking )
  2981. {
  2982. VPROF_BUDGET( "CShadowMgr::DrawFlashlightDecalsOnDisplacements", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  2983. if ( IsX360() || r_flashlight_version2.GetInt() )
  2984. return;
  2985. FlashlightHandle_t flashlightID = m_FlashlightStates.Head();
  2986. if ( flashlightID == m_FlashlightStates.InvalidIndex() )
  2987. return;
  2988. CMatRenderContextPtr pRenderContext( materials );
  2989. pRenderContext->SetFlashlightMode( true );
  2990. DispInfo_BatchDecals( visibleDisps, nVisibleDisps );
  2991. for( ;
  2992. flashlightID != m_FlashlightStates.InvalidIndex();
  2993. flashlightID = m_FlashlightStates.Next( flashlightID ) )
  2994. {
  2995. FlashlightInfo_t &flashlightInfo = m_FlashlightStates[flashlightID];
  2996. pRenderContext->SetFlashlightState(flashlightInfo.m_FlashlightState, m_Shadows[flashlightInfo.m_Shadow].m_WorldToShadow );
  2997. EnableStencilAndScissorMasking( pRenderContext, flashlightInfo, bDoMasking );
  2998. DispInfo_DrawDecals( visibleDisps, nVisibleDisps );
  2999. }
  3000. // Tell the materialsystem that we are finished drawing additive flashlight lighting.
  3001. pRenderContext->SetFlashlightMode( false );
  3002. // Turn off stencil masking
  3003. DisableStencilAndScissorMasking( pRenderContext );
  3004. }
  3005. void CShadowMgr::DrawFlashlightDecalsOnSingleSurface( SurfaceHandle_t surfID, bool bDoMasking )
  3006. {
  3007. VPROF_BUDGET( "CShadowMgr::DrawFlashlightDecalsOnSingleSurface", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  3008. if ( IsX360() || r_flashlight_version2.GetInt() )
  3009. return;
  3010. FlashlightHandle_t flashlightID = m_FlashlightStates.Head();
  3011. if ( flashlightID == m_FlashlightStates.InvalidIndex() )
  3012. return;
  3013. CMatRenderContextPtr pRenderContext( materials );
  3014. pRenderContext->SetFlashlightMode( true );
  3015. for( ;
  3016. flashlightID != m_FlashlightStates.InvalidIndex();
  3017. flashlightID = m_FlashlightStates.Next( flashlightID ) )
  3018. {
  3019. FlashlightInfo_t &flashlightInfo = m_FlashlightStates[flashlightID];
  3020. pRenderContext->SetFlashlightState(flashlightInfo.m_FlashlightState, m_Shadows[flashlightInfo.m_Shadow].m_WorldToShadow );
  3021. EnableStencilAndScissorMasking( pRenderContext, flashlightInfo, bDoMasking );
  3022. DrawDecalsOnSingleSurface( pRenderContext, surfID );
  3023. }
  3024. // Tell the materialsystem that we are finished drawing additive flashlight lighting.
  3025. pRenderContext->SetFlashlightMode( false );
  3026. // Turn off stencil masking
  3027. DisableStencilAndScissorMasking( pRenderContext );
  3028. }
  3029. void CShadowMgr::DrawFlashlightOverlays( int nSortGroup, bool bDoMasking )
  3030. {
  3031. VPROF_BUDGET( "CShadowMgr::DrawFlashlightOverlays", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  3032. if ( IsX360() || r_flashlight_version2.GetInt() )
  3033. return;
  3034. FlashlightHandle_t flashlightID = m_FlashlightStates.Head();
  3035. if ( flashlightID == m_FlashlightStates.InvalidIndex() )
  3036. return;
  3037. if ( r_flashlightrender.GetBool()==false )
  3038. return;
  3039. CMatRenderContextPtr pRenderContext( materials );
  3040. pRenderContext->SetFlashlightMode( true );
  3041. for( ;
  3042. flashlightID != m_FlashlightStates.InvalidIndex();
  3043. flashlightID = m_FlashlightStates.Next( flashlightID ) )
  3044. {
  3045. FlashlightInfo_t &flashlightInfo = m_FlashlightStates[flashlightID];
  3046. pRenderContext->SetFlashlightState(flashlightInfo.m_FlashlightState, m_Shadows[flashlightInfo.m_Shadow].m_WorldToShadow );
  3047. EnableStencilAndScissorMasking( pRenderContext, flashlightInfo, bDoMasking );
  3048. OverlayMgr()->RenderOverlays( nSortGroup );
  3049. }
  3050. // Tell the materialsystem that we are finished drawing additive flashlight lighting.
  3051. pRenderContext->SetFlashlightMode( false );
  3052. // Turn off stencil masking
  3053. DisableStencilAndScissorMasking( pRenderContext );
  3054. }
  3055. void CShadowMgr::DrawFlashlightDepthTexture( )
  3056. {
  3057. int i = 0;
  3058. FlashlightHandle_t flashlightID = m_FlashlightStates.Head();
  3059. while ( flashlightID != m_FlashlightStates.InvalidIndex() ) // Count up the shadows
  3060. {
  3061. FlashlightInfo_t &flashlightInfo = m_FlashlightStates[ flashlightID ];
  3062. if( m_Shadows[ flashlightInfo.m_Shadow ].m_pFlashlightDepthTexture )
  3063. {
  3064. bool foundVar;
  3065. IMaterial *pMaterial = materials->FindMaterial( "debug/showz", TEXTURE_GROUP_OTHER, true );
  3066. IMaterialVar *BaseTextureVar = pMaterial->FindVar( "$basetexture", &foundVar, false );
  3067. if (!foundVar)
  3068. return;
  3069. IMaterialVar *FrameVar = pMaterial->FindVar( "$frame", &foundVar, false );
  3070. if (!foundVar)
  3071. return;
  3072. float w = 256.0f, h = 256.0f;
  3073. float wOffset = (i % 2) * 256.0f; // Even|Odd go left|right
  3074. float hOffset = (i / 2) * 256.0f; // Rows of two
  3075. BaseTextureVar->SetTextureValue( m_Shadows[ flashlightInfo.m_Shadow ].m_pFlashlightDepthTexture );
  3076. FrameVar->SetIntValue( 0 );
  3077. CMatRenderContextPtr pRenderContext( materials );
  3078. pRenderContext->Bind( pMaterial );
  3079. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  3080. CMeshBuilder meshBuilder;
  3081. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  3082. meshBuilder.Position3f( wOffset, hOffset, 0.0f );
  3083. #ifdef DX_TO_GL_ABSTRACTION
  3084. meshBuilder.TexCoord2f( 0, 0.0f, 1.0f ); // Posix is rotated due to render target origin differences
  3085. #else
  3086. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  3087. #endif
  3088. meshBuilder.AdvanceVertex();
  3089. meshBuilder.Position3f( wOffset + w, hOffset, 0.0f );
  3090. #ifdef DX_TO_GL_ABSTRACTION
  3091. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  3092. #else
  3093. meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
  3094. #endif
  3095. meshBuilder.AdvanceVertex();
  3096. meshBuilder.Position3f( wOffset + w, hOffset + h, 0.0f );
  3097. #ifdef DX_TO_GL_ABSTRACTION
  3098. meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
  3099. #else
  3100. meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
  3101. #endif
  3102. meshBuilder.AdvanceVertex();
  3103. meshBuilder.Position3f( wOffset, hOffset + h, 0.0f );
  3104. #ifdef DX_TO_GL_ABSTRACTION
  3105. meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
  3106. #else
  3107. meshBuilder.TexCoord2f( 0, 0.0f, 1.0f );
  3108. #endif
  3109. meshBuilder.AdvanceVertex();
  3110. meshBuilder.End();
  3111. pMesh->Draw();
  3112. i++;
  3113. }
  3114. flashlightID = m_FlashlightStates.Next( flashlightID );
  3115. }
  3116. }
  3117. void CShadowMgr::AddFlashlightRenderable( ShadowHandle_t shadowHandle, IClientRenderable *pRenderable )
  3118. {
  3119. Shadow_t &shadow = m_Shadows[ shadowHandle ];
  3120. FlashlightInfo_t &flashlightInfo = m_FlashlightStates[ shadow.m_FlashlightHandle ];
  3121. if( pRenderable->GetModelInstance() != MODEL_INSTANCE_INVALID )
  3122. {
  3123. flashlightInfo.m_Renderables.AddToTail( pRenderable );
  3124. }
  3125. }