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

6908 lines
237 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. // Interface to the client system responsible for dealing with shadows
  8. //
  9. // Boy is this complicated. OK, lets talk about how this works at the moment
  10. //
  11. // The ClientShadowMgr contains all of the highest-level state for rendering
  12. // shadows, and it controls the ShadowMgr in the engine which is the central
  13. // clearing house for rendering shadows.
  14. //
  15. // There are two important types of objects with respect to shadows:
  16. // the shadow receiver, and the shadow caster. How is the association made
  17. // between casters + the receivers? Turns out it's done slightly differently
  18. // depending on whether the receiver is the world, or if it's an entity.
  19. //
  20. // In the case of the world, every time the engine's ProjectShadow() is called,
  21. // any previous receiver state stored (namely, which world surfaces are
  22. // receiving shadows) are cleared. Then, when ProjectShadow is called,
  23. // the engine iterates over all nodes + leaves within the shadow volume and
  24. // marks front-facing surfaces in them as potentially being affected by the
  25. // shadow. Later on, if those surfaces are actually rendered, the surfaces
  26. // are clipped by the shadow volume + rendered.
  27. //
  28. // In the case of entities, there are slightly different methods depending
  29. // on whether the receiver is a brush model or a studio model. However, there
  30. // are a couple central things that occur with both.
  31. //
  32. // Every time a shadow caster is moved, the ClientLeafSystem's ProjectShadow
  33. // method is called to tell it to remove the shadow from all leaves + all
  34. // renderables it's currently associated with. Then it marks each leaf in the
  35. // shadow volume as being affected by that shadow, and it marks every renderable
  36. // in that volume as being potentially affected by the shadow (the function
  37. // AddShadowToRenderable is called for each renderable in leaves affected
  38. // by the shadow volume).
  39. //
  40. // Every time a shadow receiver is moved, the ClientLeafSystem first calls
  41. // RemoveAllShadowsFromRenderable to have it clear out its state, and then
  42. // the ClientLeafSystem calls AddShadowToRenderable() for all shadows in all
  43. // leaves the renderable has moved into.
  44. //
  45. // Now comes the difference between brush models + studio models. In the case
  46. // of brush models, when a shadow is added to the studio model, it's done in
  47. // the exact same way as for the world. Surfaces on the brush model are marked
  48. // as potentially being affected by the shadow, and if those surfaces are
  49. // rendered, the surfaces are clipped to the shadow volume. When ProjectShadow()
  50. // is called, turns out the same operation that removes the shadow that moved
  51. // from the world surfaces also works to remove the shadow from brush surfaces.
  52. //
  53. // In the case of studio models, we need a separate operation to remove
  54. // the shadow from all studio models
  55. //
  56. // DEFERRED SHADOW RENDERING
  57. //
  58. // When deferred shadow rendering (currently 360 only) is enabled. The
  59. // ClientShadowMgr bypasses most calls to the engine shadow mgr to avoid the
  60. // CPU overhead of clipping world geometry against shadow frustums. Instead,
  61. // We render each shadow frustum and use the depth buffer to back-project each
  62. // covered screen pixel into shadow space and apply the shadow. This causes
  63. // everything that rendered into the depth buffer during the opaque renderables
  64. // pass to be a shadow receiver (shadows on static props are free). Because this
  65. // approach requires a lot of fill-rate, we impose the limitation that shadow
  66. // casters can't receive shadows. Shadow casters are marked in the stencil buffer
  67. // (using stencil mask 0x4) AND in the 360's heirarchical stencil buffer, which
  68. // is most important for controlling fill rate. Initializing the stencil mask
  69. // for shadow casters currently happens in several places: the staticpropmgr,
  70. // c_baseanimating rendering code, and L4D-specific entity classes.
  71. //
  72. //===========================================================================//
  73. #include "cbase.h"
  74. #include "engine/ishadowmgr.h"
  75. #include "model_types.h"
  76. #include "bitmap/imageformat.h"
  77. #include "materialsystem/imaterialproxy.h"
  78. #include "materialsystem/imaterialvar.h"
  79. #include "materialsystem/imaterial.h"
  80. #include "materialsystem/imesh.h"
  81. #include "materialsystem/itexture.h"
  82. #include "bsptreedata.h"
  83. #include "utlmultilist.h"
  84. #include "collisionutils.h"
  85. #include "iviewrender.h"
  86. #include "ivrenderview.h"
  87. #include "tier0/vprof.h"
  88. #include "engine/ivmodelinfo.h"
  89. #include "view_shared.h"
  90. #include "engine/ivdebugoverlay.h"
  91. #include "engine/IStaticPropMgr.h"
  92. #include "datacache/imdlcache.h"
  93. #include "viewrender.h"
  94. #include "tier0/icommandline.h"
  95. #include "vstdlib/jobthread.h"
  96. #include "bonetoworldarray.h"
  97. #include "debugoverlay_shared.h"
  98. #include "shaderapi/ishaderapi.h"
  99. #include "renderparm.h"
  100. #include "rendertexture.h"
  101. #include "clientalphaproperty.h"
  102. #include "flashlighteffect.h"
  103. #include "c_env_projectedtexture.h"
  104. #include "imaterialproxydict.h"
  105. #include "c_env_cascade_light.h"
  106. // memdbgon must be the last include file in a .cpp file!!!
  107. #include "tier0/memdbgon.h"
  108. #ifdef CSTRIKE15
  109. // Slam blobby shadows to disabled in CS:GO (RTT shadows are also disabled too).
  110. static ConVar r_disable_update_shadow( "r_disable_update_shadow", "1", FCVAR_CHEAT );
  111. #else
  112. static ConVar r_disable_update_shadow( "r_disable_update_shadow", "0", FCVAR_CHEAT );
  113. #endif
  114. static ConVar r_flashlightdrawfrustum( "r_flashlightdrawfrustum", "0" );
  115. static ConVar r_flashlightdrawfrustumbbox( "r_flashlightdrawfrustumbbox", "0" );
  116. static ConVar r_flashlightmodels( "r_flashlightmodels", "1" );
  117. static ConVar r_shadowrendertotexture( "r_shadowrendertotexture", "0" );
  118. static ConVar r_shadow_lightpos_lerptime( "r_shadow_lightpos_lerptime", "0.5" );
  119. static ConVar r_shadowfromworldlights_debug( "r_shadowfromworldlights_debug", "0", FCVAR_CHEAT );
  120. static ConVar r_shadowfromanyworldlight( "r_shadowfromanyworldlight", "0", FCVAR_CHEAT );
  121. static ConVar r_shadow_shortenfactor( "r_shadow_shortenfactor", "2" , 0, "Makes shadows cast from local lights shorter" );
  122. // Flashlight culling code isn't Portal-aware, so they pop on/off when viewed through portals.
  123. #ifdef PORTAL2
  124. ConVar r_flashlightenableculling( "r_flashlightenableculling", "0", 0, "Enable frustum culling of flashlights");
  125. #else
  126. ConVar r_flashlightenableculling( "r_flashlightenableculling", "1", 0, "Enable frustum culling of flashlights");
  127. #endif
  128. static void HalfUpdateRateCallback( IConVar *var, const char *pOldValue, float flOldValue );
  129. static ConVar r_shadow_half_update_rate( "r_shadow_half_update_rate", IsGameConsole() ? "1" : "0", 0, "Updates shadows at half the framerate", HalfUpdateRateCallback );
  130. static void DeferredShadowToggleCallback( IConVar *var, const char *pOldValue, float flOldValue );
  131. static void DeferredShadowDownsampleToggleCallback( IConVar *var, const char *pOldValue, float flOldValue );
  132. ConVar r_shadow_deferred( "r_shadow_deferred", "0", FCVAR_CHEAT, "Toggle deferred shadow rendering", DeferredShadowToggleCallback );
  133. static ConVar r_shadow_deferred_downsample( "r_shadow_deferred_downsample", "0", 0, "Toggle low-res deferred shadow rendering", DeferredShadowDownsampleToggleCallback );
  134. static ConVar r_shadow_deferred_simd( "r_shadow_deferred_simd", "0" );
  135. static ConVar r_shadow_debug_spew( "r_shadow_debug_spew", "0", FCVAR_CHEAT );
  136. static ConVar r_flashlight_info( "r_flashlight_info", "0", 0, "Information about currently enabled flashlights" );
  137. #if defined( _PS3 )
  138. ConVar r_flashlightdepthtexture( "r_flashlightdepthtexture", "1" );
  139. ConVar r_flashlightdepthreshigh( "r_flashlightdepthreshigh", "640" );
  140. ConVar r_flashlightdepthres( "r_flashlightdepthres", "640" );
  141. #elif defined( _X360 )
  142. ConVar r_flashlightdepthtexture( "r_flashlightdepthtexture", "1" );
  143. ConVar r_flashlightdepthreshigh( "r_flashlightdepthreshigh", "720" );
  144. ConVar r_flashlightdepthres( "r_flashlightdepthres", "720" );
  145. #else
  146. ConVar r_flashlightdepthtexture( "r_flashlightdepthtexture", "1" );
  147. ConVar r_flashlightdepthreshigh( "r_flashlightdepthreshigh", "2048" );
  148. ConVar r_flashlightdepthres( "r_flashlightdepthres", "1024" );
  149. #endif
  150. #if defined( _GAMECONSOLE )
  151. #define RTT_TEXTURE_SIZE_640
  152. #endif
  153. #ifdef _WIN32
  154. #pragma warning( disable: 4701 )
  155. #endif
  156. //-----------------------------------------------------------------------------
  157. // A texture allocator used to batch textures together
  158. // At the moment, the implementation simply allocates blocks of max 256x256
  159. // and each block stores an array of uniformly-sized textures
  160. //-----------------------------------------------------------------------------
  161. typedef unsigned short TextureHandle_t;
  162. enum
  163. {
  164. INVALID_TEXTURE_HANDLE = (TextureHandle_t)~0
  165. };
  166. class CTextureAllocator
  167. {
  168. public:
  169. // Initialize the allocator with something that knows how to refresh the bits
  170. void Init();
  171. void Shutdown();
  172. // Resets the allocator
  173. void Reset();
  174. // Deallocates everything
  175. void DeallocateAllTextures();
  176. // Allocate, deallocate texture
  177. TextureHandle_t AllocateTexture( int w, int h );
  178. void DeallocateTexture( TextureHandle_t h );
  179. // Mark texture as being used... (return true if re-render is needed)
  180. bool UseTexture( TextureHandle_t h, bool bWillRedraw, float flArea );
  181. bool HasValidTexture( TextureHandle_t h );
  182. // Advance frame...
  183. void AdvanceFrame();
  184. // Get at the location of the texture
  185. void GetTextureRect(TextureHandle_t handle, int& x, int& y, int& w, int& h );
  186. // Get at the texture it's a part of
  187. ITexture *GetTexture();
  188. // Get at the total texture size.
  189. void GetTotalTextureSize( int& w, int& h );
  190. void DebugPrintCache( void );
  191. void InitRenderTargets( void );
  192. private:
  193. typedef unsigned short FragmentHandle_t;
  194. enum
  195. {
  196. INVALID_FRAGMENT_HANDLE = (FragmentHandle_t)~0,
  197. #ifdef RTT_TEXTURE_SIZE_640
  198. TEXTURE_PAGE_SIZE = 640,
  199. MAX_TEXTURE_POWER = 7,
  200. #else
  201. TEXTURE_PAGE_SIZE = 1024,
  202. MAX_TEXTURE_POWER = 8,
  203. #endif
  204. #if !defined( _GAMECONSOLE )
  205. MIN_TEXTURE_POWER = 4,
  206. #else
  207. MIN_TEXTURE_POWER = 5, // per resolve requirements to ensure 32x32 aligned offsets
  208. #endif
  209. MAX_TEXTURE_SIZE = (1 << MAX_TEXTURE_POWER),
  210. MIN_TEXTURE_SIZE = (1 << MIN_TEXTURE_POWER),
  211. BLOCK_SIZE = MAX_TEXTURE_SIZE,
  212. BLOCKS_PER_ROW = (TEXTURE_PAGE_SIZE / MAX_TEXTURE_SIZE),
  213. BLOCK_COUNT = (BLOCKS_PER_ROW * BLOCKS_PER_ROW),
  214. };
  215. struct TextureInfo_t
  216. {
  217. FragmentHandle_t m_Fragment;
  218. unsigned short m_Size;
  219. unsigned short m_Power;
  220. };
  221. struct FragmentInfo_t
  222. {
  223. unsigned short m_Block;
  224. unsigned short m_Index;
  225. TextureHandle_t m_Texture;
  226. // Makes sure we don't overflow
  227. unsigned int m_FrameUsed;
  228. };
  229. struct BlockInfo_t
  230. {
  231. unsigned short m_FragmentPower;
  232. };
  233. struct Cache_t
  234. {
  235. unsigned short m_List;
  236. };
  237. // Adds a block worth of fragments to the LRU
  238. void AddBlockToLRU( int block );
  239. // Unlink fragment from cache
  240. void UnlinkFragmentFromCache( Cache_t& cache, FragmentHandle_t fragment );
  241. // Mark something as being used (MRU)..
  242. void MarkUsed( FragmentHandle_t fragment );
  243. // Mark something as being unused (LRU)..
  244. void MarkUnused( FragmentHandle_t fragment );
  245. // Disconnect texture from fragment
  246. void DisconnectTextureFromFragment( FragmentHandle_t f );
  247. // Returns the size of a particular fragment
  248. int GetFragmentPower( FragmentHandle_t f ) const;
  249. // Stores the actual texture we're writing into
  250. CTextureReference m_TexturePage;
  251. CUtlLinkedList< TextureInfo_t, TextureHandle_t > m_Textures;
  252. CUtlMultiList< FragmentInfo_t, FragmentHandle_t > m_Fragments;
  253. Cache_t m_Cache[MAX_TEXTURE_POWER+1];
  254. BlockInfo_t m_Blocks[BLOCK_COUNT];
  255. unsigned int m_CurrentFrame;
  256. };
  257. //-----------------------------------------------------------------------------
  258. // Allocate/deallocate the texture page
  259. //-----------------------------------------------------------------------------
  260. void CTextureAllocator::Init()
  261. {
  262. for ( int i = 0; i <= MAX_TEXTURE_POWER; ++i )
  263. {
  264. m_Cache[i].m_List = m_Fragments.InvalidIndex();
  265. }
  266. InitRenderTargets();
  267. }
  268. void CTextureAllocator::InitRenderTargets( void )
  269. {
  270. #if !defined( _X360 )
  271. // don't need depth buffer for shadows
  272. m_TexturePage.InitRenderTarget( TEXTURE_PAGE_SIZE, TEXTURE_PAGE_SIZE, RT_SIZE_NO_CHANGE, IMAGE_FORMAT_ARGB8888, MATERIAL_RT_DEPTH_NONE, false, "_rt_Shadows" );
  273. #else
  274. // unfortunate explicit management required for this render target
  275. // 32bpp edram is only largest shadow fragment, but resolved to actual shadow atlas
  276. // because full-res 1024x1024 shadow buffer is too large for EDRAM
  277. m_TexturePage.InitRenderTargetTexture( TEXTURE_PAGE_SIZE, TEXTURE_PAGE_SIZE, RT_SIZE_NO_CHANGE, IMAGE_FORMAT_ARGB8888, MATERIAL_RT_DEPTH_NONE, false, "_rt_Shadows" );
  278. #ifdef RTT_TEXTURE_SIZE_640
  279. // use 4x multisampling for smoother shadows
  280. m_TexturePage.InitRenderTargetSurface( MAX_TEXTURE_SIZE, MAX_TEXTURE_SIZE, IMAGE_FORMAT_ARGB8888, false, RT_MULTISAMPLE_4_SAMPLES );
  281. #else
  282. // edram footprint is only 256x256x4 = 256K
  283. m_TexturePage.InitRenderTargetSurface( MAX_TEXTURE_SIZE, MAX_TEXTURE_SIZE, IMAGE_FORMAT_ARGB8888, false );
  284. #endif
  285. // due to texture/surface size mismatch, ensure texture page is entirely cleared translucent
  286. // otherwise border artifacts at edge of shadows due to pixel shader averaging of unwanted bits
  287. // should also set m_bRenderTargetNeedsClear
  288. m_TexturePage->ClearTexture( 0, 0, 0, 0 );
  289. #endif
  290. }
  291. void CTextureAllocator::Shutdown()
  292. {
  293. m_TexturePage.Shutdown();
  294. }
  295. //-----------------------------------------------------------------------------
  296. // Initialize the allocator with something that knows how to refresh the bits
  297. //-----------------------------------------------------------------------------
  298. void CTextureAllocator::Reset()
  299. {
  300. DeallocateAllTextures();
  301. m_Textures.EnsureCapacity(256);
  302. m_Fragments.EnsureCapacity(256);
  303. // Set up the block sizes....
  304. #ifdef RTT_TEXTURE_SIZE_640
  305. // Going to 640x640 gives us roughly the same number of texture slots than the 1024x1024 texture
  306. // and thus won't change cache thrashing patterns
  307. m_Blocks[0].m_FragmentPower = MAX_TEXTURE_POWER-2;
  308. m_Blocks[1].m_FragmentPower = MAX_TEXTURE_POWER-2;
  309. m_Blocks[2].m_FragmentPower = MAX_TEXTURE_POWER-2;
  310. m_Blocks[3].m_FragmentPower = MAX_TEXTURE_POWER-2;
  311. m_Blocks[4].m_FragmentPower = MAX_TEXTURE_POWER-2;
  312. m_Blocks[5].m_FragmentPower = MAX_TEXTURE_POWER-2;
  313. m_Blocks[6].m_FragmentPower = MAX_TEXTURE_POWER-2;
  314. m_Blocks[7].m_FragmentPower = MAX_TEXTURE_POWER-2;
  315. m_Blocks[8].m_FragmentPower = MAX_TEXTURE_POWER-2;
  316. m_Blocks[9].m_FragmentPower = MAX_TEXTURE_POWER-2; // 10 * 16 = 160
  317. m_Blocks[10].m_FragmentPower = MAX_TEXTURE_POWER-1;
  318. m_Blocks[11].m_FragmentPower = MAX_TEXTURE_POWER-1;
  319. m_Blocks[12].m_FragmentPower = MAX_TEXTURE_POWER-1;
  320. m_Blocks[13].m_FragmentPower = MAX_TEXTURE_POWER-1;
  321. m_Blocks[14].m_FragmentPower = MAX_TEXTURE_POWER-1;
  322. m_Blocks[15].m_FragmentPower = MAX_TEXTURE_POWER-1;
  323. m_Blocks[16].m_FragmentPower = MAX_TEXTURE_POWER-1;
  324. m_Blocks[17].m_FragmentPower = MAX_TEXTURE_POWER-1; // 8 * 4 = 32
  325. m_Blocks[18].m_FragmentPower = MAX_TEXTURE_POWER; // 7
  326. m_Blocks[19].m_FragmentPower = MAX_TEXTURE_POWER;
  327. m_Blocks[20].m_FragmentPower = MAX_TEXTURE_POWER;
  328. m_Blocks[21].m_FragmentPower = MAX_TEXTURE_POWER;
  329. m_Blocks[22].m_FragmentPower = MAX_TEXTURE_POWER;
  330. m_Blocks[23].m_FragmentPower = MAX_TEXTURE_POWER;
  331. m_Blocks[24].m_FragmentPower = MAX_TEXTURE_POWER; // 199 slots total
  332. #else
  333. // FIXME: Improve heuristic?!?
  334. #if !defined( _GAMECONSOLE )
  335. m_Blocks[0].m_FragmentPower = MAX_TEXTURE_POWER-4; // 128 cells at ExE resolution
  336. #else
  337. m_Blocks[0].m_FragmentPower = MAX_TEXTURE_POWER-3; // 64 cells at DxD resolution
  338. #endif
  339. m_Blocks[1].m_FragmentPower = MAX_TEXTURE_POWER-3; // 64 cells at DxD resolution
  340. m_Blocks[2].m_FragmentPower = MAX_TEXTURE_POWER-2; // 32 cells at CxC resolution
  341. m_Blocks[3].m_FragmentPower = MAX_TEXTURE_POWER-2;
  342. m_Blocks[4].m_FragmentPower = MAX_TEXTURE_POWER-1; // 24 cells at BxB resolution
  343. m_Blocks[5].m_FragmentPower = MAX_TEXTURE_POWER-1;
  344. m_Blocks[6].m_FragmentPower = MAX_TEXTURE_POWER-1;
  345. m_Blocks[7].m_FragmentPower = MAX_TEXTURE_POWER-1;
  346. m_Blocks[8].m_FragmentPower = MAX_TEXTURE_POWER-1;
  347. m_Blocks[9].m_FragmentPower = MAX_TEXTURE_POWER-1;
  348. m_Blocks[10].m_FragmentPower = MAX_TEXTURE_POWER; // 6 cells at AxA resolution
  349. m_Blocks[11].m_FragmentPower = MAX_TEXTURE_POWER;
  350. m_Blocks[12].m_FragmentPower = MAX_TEXTURE_POWER;
  351. m_Blocks[13].m_FragmentPower = MAX_TEXTURE_POWER;
  352. m_Blocks[14].m_FragmentPower = MAX_TEXTURE_POWER;
  353. m_Blocks[15].m_FragmentPower = MAX_TEXTURE_POWER; // 190 slots total on 360
  354. #endif
  355. // Initialize the LRU
  356. int i;
  357. for ( i = 0; i <= MAX_TEXTURE_POWER; ++i )
  358. {
  359. m_Cache[i].m_List = m_Fragments.CreateList();
  360. }
  361. // Now that the block sizes are allocated, create LRUs for the various block sizes
  362. for ( i = 0; i < BLOCK_COUNT; ++i)
  363. {
  364. // Initialize LRU
  365. AddBlockToLRU( i );
  366. }
  367. m_CurrentFrame = 0;
  368. }
  369. void CTextureAllocator::DeallocateAllTextures()
  370. {
  371. m_Textures.Purge();
  372. m_Fragments.Purge();
  373. for ( int i = 0; i <= MAX_TEXTURE_POWER; ++i )
  374. {
  375. m_Cache[i].m_List = m_Fragments.InvalidIndex();
  376. }
  377. }
  378. //-----------------------------------------------------------------------------
  379. // Dump the state of the cache to debug out
  380. //-----------------------------------------------------------------------------
  381. void CTextureAllocator::DebugPrintCache( void )
  382. {
  383. // For each fragment
  384. int nNumFragments = m_Fragments.TotalCount();
  385. int nNumInvalidFragments = 0;
  386. Warning("Fragments (%d):\n===============\n", nNumFragments);
  387. for ( int f = 0; f < nNumFragments; f++ )
  388. {
  389. if ( ( m_Fragments[f].m_FrameUsed != 0 ) && ( m_Fragments[f].m_Texture != INVALID_TEXTURE_HANDLE ) )
  390. Warning("Fragment %d, Block: %d, Index: %d, Texture: %d Frame Used: %d\n", f, m_Fragments[f].m_Block, m_Fragments[f].m_Index, m_Fragments[f].m_Texture, m_Fragments[f].m_FrameUsed );
  391. else
  392. nNumInvalidFragments++;
  393. }
  394. Warning("Invalid Fragments: %d\n", nNumInvalidFragments);
  395. // for ( int c = 0; c <= MAX_TEXTURE_POWER; ++c )
  396. // {
  397. // Warning("Cache Index (%d)\n", m_Cache[c].m_List);
  398. // }
  399. }
  400. //-----------------------------------------------------------------------------
  401. // Adds a block worth of fragments to the LRU
  402. //-----------------------------------------------------------------------------
  403. void CTextureAllocator::AddBlockToLRU( int block )
  404. {
  405. int power = m_Blocks[block].m_FragmentPower;
  406. int size = (1 << power);
  407. // Compute the number of fragments in this block
  408. int fragmentCount = MAX_TEXTURE_SIZE / size;
  409. fragmentCount *= fragmentCount;
  410. // For each fragment, indicate which block it's a part of (and the index)
  411. // and then stick in at the top of the LRU
  412. while (--fragmentCount >= 0 )
  413. {
  414. FragmentHandle_t f = m_Fragments.Alloc( );
  415. m_Fragments[f].m_Block = block;
  416. m_Fragments[f].m_Index = fragmentCount;
  417. m_Fragments[f].m_Texture = INVALID_TEXTURE_HANDLE;
  418. m_Fragments[f].m_FrameUsed = 0xFFFFFFFF;
  419. m_Fragments.LinkToHead( m_Cache[power].m_List, f );
  420. }
  421. }
  422. //-----------------------------------------------------------------------------
  423. // Unlink fragment from cache
  424. //-----------------------------------------------------------------------------
  425. void CTextureAllocator::UnlinkFragmentFromCache( Cache_t& cache, FragmentHandle_t fragment )
  426. {
  427. m_Fragments.Unlink( cache.m_List, fragment);
  428. }
  429. //-----------------------------------------------------------------------------
  430. // Mark something as being used (MRU)..
  431. //-----------------------------------------------------------------------------
  432. void CTextureAllocator::MarkUsed( FragmentHandle_t fragment )
  433. {
  434. int block = m_Fragments[fragment].m_Block;
  435. int power = m_Blocks[block].m_FragmentPower;
  436. // Hook it at the end of the LRU
  437. Cache_t& cache = m_Cache[power];
  438. m_Fragments.LinkToTail( cache.m_List, fragment );
  439. m_Fragments[fragment].m_FrameUsed = m_CurrentFrame;
  440. }
  441. //-----------------------------------------------------------------------------
  442. // Mark something as being unused (LRU)..
  443. //-----------------------------------------------------------------------------
  444. void CTextureAllocator::MarkUnused( FragmentHandle_t fragment )
  445. {
  446. int block = m_Fragments[fragment].m_Block;
  447. int power = m_Blocks[block].m_FragmentPower;
  448. // Hook it at the end of the LRU
  449. Cache_t& cache = m_Cache[power];
  450. m_Fragments.LinkToHead( cache.m_List, fragment );
  451. }
  452. //-----------------------------------------------------------------------------
  453. // Allocate, deallocate texture
  454. //-----------------------------------------------------------------------------
  455. TextureHandle_t CTextureAllocator::AllocateTexture( int w, int h )
  456. {
  457. // Implementational detail for now
  458. Assert( w == h );
  459. // Clamp texture size
  460. if (w < MIN_TEXTURE_SIZE)
  461. w = MIN_TEXTURE_SIZE;
  462. else if (w > MAX_TEXTURE_SIZE)
  463. w = MAX_TEXTURE_SIZE;
  464. TextureHandle_t handle = m_Textures.AddToTail();
  465. m_Textures[handle].m_Fragment = INVALID_FRAGMENT_HANDLE;
  466. m_Textures[handle].m_Size = w;
  467. // Find the power of two
  468. int power = 0;
  469. int size = 1;
  470. while(size < w)
  471. {
  472. size <<= 1;
  473. ++power;
  474. }
  475. Assert( size == w );
  476. m_Textures[handle].m_Power = power;
  477. return handle;
  478. }
  479. void CTextureAllocator::DeallocateTexture( TextureHandle_t h )
  480. {
  481. // Warning("Beginning of DeallocateTexture\n");
  482. // DebugPrintCache();
  483. if (m_Textures[h].m_Fragment != INVALID_FRAGMENT_HANDLE)
  484. {
  485. MarkUnused(m_Textures[h].m_Fragment);
  486. m_Fragments[m_Textures[h].m_Fragment].m_FrameUsed = 0xFFFFFFFF; // non-zero frame
  487. DisconnectTextureFromFragment( m_Textures[h].m_Fragment );
  488. }
  489. m_Textures.Remove(h);
  490. // Warning("End of DeallocateTexture\n");
  491. // DebugPrintCache();
  492. }
  493. //-----------------------------------------------------------------------------
  494. // Disconnect texture from fragment
  495. //-----------------------------------------------------------------------------
  496. void CTextureAllocator::DisconnectTextureFromFragment( FragmentHandle_t f )
  497. {
  498. // Warning( "Beginning of DisconnectTextureFromFragment\n" );
  499. // DebugPrintCache();
  500. FragmentInfo_t& info = m_Fragments[f];
  501. if (info.m_Texture != INVALID_TEXTURE_HANDLE)
  502. {
  503. m_Textures[info.m_Texture].m_Fragment = INVALID_FRAGMENT_HANDLE;
  504. info.m_Texture = INVALID_TEXTURE_HANDLE;
  505. }
  506. // Warning( "End of DisconnectTextureFromFragment\n" );
  507. // DebugPrintCache();
  508. }
  509. //-----------------------------------------------------------------------------
  510. // Do we have a valid texture assigned?
  511. //-----------------------------------------------------------------------------
  512. bool CTextureAllocator::HasValidTexture( TextureHandle_t h )
  513. {
  514. TextureInfo_t& info = m_Textures[h];
  515. FragmentHandle_t currentFragment = info.m_Fragment;
  516. return (currentFragment != INVALID_FRAGMENT_HANDLE);
  517. }
  518. //-----------------------------------------------------------------------------
  519. // Mark texture as being used...
  520. //-----------------------------------------------------------------------------
  521. bool CTextureAllocator::UseTexture( TextureHandle_t h, bool bWillRedraw, float flArea )
  522. {
  523. // Warning( "Top of UseTexture\n" );
  524. // DebugPrintCache();
  525. TextureInfo_t& info = m_Textures[h];
  526. // spin up to the best fragment size
  527. int nDesiredPower = MIN_TEXTURE_POWER;
  528. int nDesiredWidth = MIN_TEXTURE_SIZE;
  529. while ( (nDesiredWidth * nDesiredWidth) < flArea )
  530. {
  531. if ( nDesiredPower >= info.m_Power )
  532. {
  533. nDesiredPower = info.m_Power;
  534. break;
  535. }
  536. ++nDesiredPower;
  537. nDesiredWidth <<= 1;
  538. }
  539. // If we've got a valid fragment for this texture, no worries!
  540. int nCurrentPower = -1;
  541. FragmentHandle_t currentFragment = info.m_Fragment;
  542. if (currentFragment != INVALID_FRAGMENT_HANDLE)
  543. {
  544. // If the current fragment is at or near the desired power, we're done
  545. nCurrentPower = GetFragmentPower(info.m_Fragment);
  546. Assert( nCurrentPower <= info.m_Power );
  547. bool bShouldKeepTexture = (!bWillRedraw) && (nDesiredPower < 8) && (nDesiredPower - nCurrentPower <= 1);
  548. if ((nCurrentPower == nDesiredPower) || bShouldKeepTexture)
  549. {
  550. // Move to the back of the LRU
  551. MarkUsed( currentFragment );
  552. return false;
  553. }
  554. }
  555. // Warning( "\n\nUseTexture B\n" );
  556. // DebugPrintCache();
  557. // Grab the LRU fragment from the appropriate cache
  558. // If that fragment is connected to a texture, disconnect it.
  559. int power = nDesiredPower;
  560. FragmentHandle_t f = INVALID_FRAGMENT_HANDLE;
  561. bool done = false;
  562. while (!done && power >= 0)
  563. {
  564. f = m_Fragments.Head( m_Cache[power].m_List );
  565. // This represents an overflow condition (used too many textures of
  566. // the same size in a single frame). It that happens, just use a texture
  567. // of lower res.
  568. if ( (f != m_Fragments.InvalidIndex()) && (m_Fragments[f].m_FrameUsed != m_CurrentFrame) )
  569. {
  570. done = true;
  571. }
  572. else
  573. {
  574. --power;
  575. }
  576. }
  577. // Warning( "\n\nUseTexture C\n" );
  578. // DebugPrintCache();
  579. // Ok, lets see if we're better off than we were...
  580. if (currentFragment != INVALID_FRAGMENT_HANDLE)
  581. {
  582. if (power <= nCurrentPower)
  583. {
  584. // Oops... we're not. Let's leave well enough alone
  585. // Move to the back of the LRU
  586. MarkUsed( currentFragment );
  587. return false;
  588. }
  589. else
  590. {
  591. // Clear out the old fragment
  592. DisconnectTextureFromFragment(currentFragment);
  593. }
  594. }
  595. if ( f == INVALID_FRAGMENT_HANDLE )
  596. {
  597. return false;
  598. }
  599. // Disconnect existing texture from this fragment (if necessary)
  600. DisconnectTextureFromFragment(f);
  601. // Connnect new texture to this fragment
  602. info.m_Fragment = f;
  603. m_Fragments[f].m_Texture = h;
  604. // Move to the back of the LRU
  605. MarkUsed( f );
  606. // Indicate we need a redraw
  607. return true;
  608. }
  609. //-----------------------------------------------------------------------------
  610. // Returns the size of a particular fragment
  611. //-----------------------------------------------------------------------------
  612. int CTextureAllocator::GetFragmentPower( FragmentHandle_t f ) const
  613. {
  614. return m_Blocks[m_Fragments[f].m_Block].m_FragmentPower;
  615. }
  616. //-----------------------------------------------------------------------------
  617. // Advance frame...
  618. //-----------------------------------------------------------------------------
  619. void CTextureAllocator::AdvanceFrame()
  620. {
  621. // Be sure that this is called as infrequently as possible (i.e. once per frame,
  622. // NOT once per view) to prevent cache thrash when rendering multiple views in a single frame
  623. m_CurrentFrame++;
  624. }
  625. //-----------------------------------------------------------------------------
  626. // Prepare to render into texture...
  627. //-----------------------------------------------------------------------------
  628. ITexture* CTextureAllocator::GetTexture()
  629. {
  630. return m_TexturePage;
  631. }
  632. //-----------------------------------------------------------------------------
  633. // Get at the total texture size.
  634. //-----------------------------------------------------------------------------
  635. void CTextureAllocator::GetTotalTextureSize( int& w, int& h )
  636. {
  637. w = h = TEXTURE_PAGE_SIZE;
  638. }
  639. //-----------------------------------------------------------------------------
  640. // Returns the rectangle the texture lives in..
  641. //-----------------------------------------------------------------------------
  642. void CTextureAllocator::GetTextureRect(TextureHandle_t handle, int& x, int& y, int& w, int& h )
  643. {
  644. TextureInfo_t& info = m_Textures[handle];
  645. Assert( info.m_Fragment != INVALID_FRAGMENT_HANDLE );
  646. // Compute the position of the fragment in the page
  647. FragmentInfo_t& fragment = m_Fragments[info.m_Fragment];
  648. int blockY = fragment.m_Block / BLOCKS_PER_ROW;
  649. int blockX = fragment.m_Block - blockY * BLOCKS_PER_ROW;
  650. int fragmentSize = (1 << m_Blocks[fragment.m_Block].m_FragmentPower);
  651. int fragmentsPerRow = BLOCK_SIZE / fragmentSize;
  652. int fragmentY = fragment.m_Index / fragmentsPerRow;
  653. int fragmentX = fragment.m_Index - fragmentY * fragmentsPerRow;
  654. x = blockX * BLOCK_SIZE + fragmentX * fragmentSize;
  655. y = blockY * BLOCK_SIZE + fragmentY * fragmentSize;
  656. w = fragmentSize;
  657. h = fragmentSize;
  658. }
  659. //-----------------------------------------------------------------------------
  660. // Defines how big of a shadow texture we should be making per caster...
  661. //-----------------------------------------------------------------------------
  662. #define TEXEL_SIZE_PER_CASTER_SIZE 2.0f
  663. #define MAX_FALLOFF_AMOUNT 240
  664. #define MAX_CLIP_PLANE_COUNT 4
  665. #define SHADOW_CULL_TOLERANCE 0.5f
  666. static ConVar r_shadows( "r_shadows", "1" ); // hook into engine's cvars..
  667. static ConVar r_shadowmaxrendered("r_shadowmaxrendered", "32");
  668. static ConVar r_shadows_gamecontrol( "r_shadows_gamecontrol", "-1", FCVAR_CHEAT ); // hook into engine's cvars..
  669. #ifdef _PS3
  670. uint32 g_ps3_ShadowDepth_TextureCache;
  671. #endif
  672. //-----------------------------------------------------------------------------
  673. // The class responsible for dealing with shadows on the client side
  674. // Oh, and let's take a moment and notice how happy Robin and John must be
  675. // owing to the lack of space between this lovely comment and the class name =)
  676. //-----------------------------------------------------------------------------
  677. class CClientShadowMgr : public IClientShadowMgr
  678. {
  679. friend bool ClientShadowMgrAcquireShadowDepthTexture( CTextureReference *pDummyColorTexture, CTextureReference *pShadowDepthTexture );
  680. public:
  681. CClientShadowMgr();
  682. virtual char const *Name() { return "CCLientShadowMgr"; }
  683. // Inherited from IClientShadowMgr
  684. virtual bool Init();
  685. virtual void InitRenderTargets();
  686. virtual void PostInit() {}
  687. virtual void Shutdown();
  688. virtual void LevelInitPreEntity();
  689. virtual void LevelInitPostEntity() {}
  690. virtual void LevelShutdownPreEntity() {}
  691. virtual void LevelShutdownPostEntity();
  692. virtual bool IsPerFrame() { return true; }
  693. virtual void PreRender() {}
  694. virtual void Update( float frametime ) { }
  695. virtual void PostRender() {}
  696. virtual void OnSave() {}
  697. virtual void OnRestore() {}
  698. virtual void SafeRemoveIfDesired() {}
  699. virtual void ReprojectShadows();
  700. virtual ClientShadowHandle_t CreateShadow( ClientEntityHandle_t entity, int nEntIndex, int flags, CBitVec< MAX_SPLITSCREEN_PLAYERS > *pSplitScreenBits = NULL );
  701. virtual void DestroyShadow( ClientShadowHandle_t handle );
  702. // Create flashlight (projected texture light source)
  703. virtual ClientShadowHandle_t CreateFlashlight( const FlashlightState_t &lightState );
  704. virtual void UpdateFlashlightState( ClientShadowHandle_t shadowHandle, const FlashlightState_t &lightState );
  705. virtual void DestroyFlashlight( ClientShadowHandle_t shadowHandle );
  706. // Create simple projected texture. it is not a light or a shadow, but this system does most of the work already for it
  707. virtual ClientShadowHandle_t CreateProjection( const FlashlightState_t &lightState );
  708. virtual void UpdateProjectionState( ClientShadowHandle_t shadowHandle, const FlashlightState_t &lightState );
  709. virtual void DestroyProjection( ClientShadowHandle_t shadowHandle );
  710. // Update a shadow
  711. virtual void UpdateProjectedTexture( ClientShadowHandle_t handle, bool force );
  712. void ComputeBoundingSphere( IClientRenderable* pRenderable, Vector& origin, float& radius );
  713. virtual void AddToDirtyShadowList( ClientShadowHandle_t handle, bool bForce );
  714. virtual void AddToDirtyShadowList( IClientRenderable *pRenderable, bool force );
  715. // Marks the render-to-texture shadow as needing to be re-rendered
  716. virtual void MarkRenderToTextureShadowDirty( ClientShadowHandle_t handle );
  717. // deals with shadows being added to shadow receivers
  718. void AddShadowToReceiver( ClientShadowHandle_t handle,
  719. IClientRenderable* pRenderable, ShadowReceiver_t type );
  720. // deals with shadows being added to shadow receivers
  721. void RemoveAllShadowsFromReceiver( IClientRenderable* pRenderable, ShadowReceiver_t type );
  722. // Re-renders all shadow textures for shadow casters that lie in the leaf list
  723. void ComputeShadowTextures( const CViewSetup &view, int leafCount, WorldListLeafData_t* pLeafList );
  724. // Kicks off rendering into shadow depth maps (if any)
  725. void ComputeShadowDepthTextures( const CViewSetup &view, bool bSetup = false );
  726. // Kicks off rendering of volumetrics for the flashlights
  727. void DrawVolumetrics( const CViewSetup &view );
  728. void GetFrustumExtents( ClientShadowHandle_t handle, Vector &vecMin, Vector &vecMax );
  729. // Frees shadow depth textures for use in subsequent view/frame
  730. void FreeShadowDepthTextures();
  731. // Returns the shadow texture
  732. ITexture* GetShadowTexture( unsigned short h );
  733. // Returns shadow information
  734. const ShadowInfo_t& GetShadowInfo( ClientShadowHandle_t h );
  735. // Renders the shadow texture to screen...
  736. void RenderShadowTexture( int w, int h );
  737. // Sets the shadow direction
  738. virtual void SetShadowDirection( const Vector& dir );
  739. const Vector &GetShadowDirection() const;
  740. // Sets the shadow color
  741. virtual void SetShadowColor( unsigned char r, unsigned char g, unsigned char b );
  742. void GetShadowColor( unsigned char *r, unsigned char *g, unsigned char *b ) const;
  743. // Sets the shadow distance
  744. virtual void SetShadowDistance( float flMaxDistance );
  745. float GetShadowDistance( ) const;
  746. // Sets the screen area at which blobby shadows are always used
  747. virtual void SetShadowBlobbyCutoffArea( float flMinArea );
  748. float GetBlobbyCutoffArea( ) const;
  749. // Set the darkness falloff bias
  750. virtual void SetFalloffBias( ClientShadowHandle_t handle, unsigned char ucBias );
  751. void RestoreRenderState();
  752. // Computes a rough bounding box encompassing the volume of the shadow
  753. void ComputeShadowBBox( IClientRenderable *pRenderable, ClientShadowHandle_t shadowHandle, const Vector &vecAbsCenter, float flRadius, Vector *pAbsMins, Vector *pAbsMaxs );
  754. bool WillParentRenderBlobbyShadow( IClientRenderable *pRenderable );
  755. // Are we the child of a shadow with render-to-texture?
  756. bool ShouldUseParentShadow( IClientRenderable *pRenderable );
  757. void SetShadowsDisabled( bool bDisabled )
  758. {
  759. r_shadows_gamecontrol.SetValue( bDisabled != 1 );
  760. }
  761. // Toggle shadow casting from world light sources
  762. virtual void SetShadowFromWorldLightsEnabled( bool bEnable );
  763. void SuppressShadowFromWorldLights( bool bSuppress );
  764. bool IsShadowingFromWorldLights() const { return m_bShadowFromWorldLights && !m_bSuppressShadowFromWorldLights; }
  765. virtual void DrawDeferredShadows( const CViewSetup &view, int leafCount, WorldListLeafData_t* pLeafList );
  766. virtual void UpdateSplitscreenLocalPlayerShadowSkip();
  767. private:
  768. enum
  769. {
  770. SHADOW_FLAGS_TEXTURE_DIRTY = (CLIENT_SHADOW_FLAGS_LAST_FLAG << 1),
  771. SHADOW_FLAGS_BRUSH_MODEL = (CLIENT_SHADOW_FLAGS_LAST_FLAG << 2),
  772. SHADOW_FLAGS_USING_LOD_SHADOW = (CLIENT_SHADOW_FLAGS_LAST_FLAG << 3),
  773. SHADOW_FLAGS_LIGHT_WORLD = (CLIENT_SHADOW_FLAGS_LAST_FLAG << 4),
  774. };
  775. struct ClientShadow_t
  776. {
  777. ClientEntityHandle_t m_Entity;
  778. ShadowHandle_t m_ShadowHandle;
  779. ClientLeafShadowHandle_t m_ClientLeafShadowHandle;
  780. unsigned short m_Flags;
  781. VMatrix m_WorldToShadow;
  782. Vector2D m_WorldSize;
  783. Vector m_ShadowDir;
  784. Vector m_LastOrigin;
  785. QAngle m_LastAngles;
  786. Vector m_CurrentLightPos; // When shadowing from local lights, stores the position of the currently shadowing light
  787. Vector m_TargetLightPos; // When shadowing from local lights, stores the position of the new shadowing light
  788. float m_LightPosLerp; // Lerp progress when going from current to target light
  789. TextureHandle_t m_ShadowTexture;
  790. CTextureReference m_ShadowDepthTexture;
  791. int m_nRenderFrame;
  792. EHANDLE m_hTargetEntity;
  793. bool m_bUseSplitScreenBits;
  794. CBitVec< MAX_SPLITSCREEN_PLAYERS > m_SplitScreenBits;
  795. int m_nLastUpdateFrame;
  796. // Extra info for deferred shadows.
  797. // FIXME: This data is also stored in CShadowMgr in the engine.
  798. int m_FalloffBias;
  799. float m_MaxDist;
  800. float m_FalloffStart;
  801. Vector2D m_TexCoordOffset;
  802. Vector2D m_TexCoordScale;
  803. VMatrix m_WorldToTexture;
  804. int m_nSplitscreenOwner;
  805. };
  806. private:
  807. friend void DeferredShadowToggleCallback( IConVar *var, const char *pOldValue, float flOldValue );
  808. friend void DeferredShadowDownsampleToggleCallback( IConVar *var, const char *pOldValue, float flOldValue );
  809. friend void HalfUpdateRateCallback( IConVar *var, const char *pOldValue, float flOldValue );
  810. // Shadow update functions
  811. void UpdateStudioShadow( IClientRenderable *pRenderable, ClientShadowHandle_t handle );
  812. void UpdateBrushShadow( IClientRenderable *pRenderable, ClientShadowHandle_t handle );
  813. void UpdateShadow( ClientShadowHandle_t handle, bool force );
  814. // Updates shadow cast direction when shadowing from world lights
  815. void UpdateShadowDirectionFromLocalLightSource( ClientShadowHandle_t shadowHandle );
  816. // Gets the entity whose shadow this shadow will render into
  817. IClientRenderable *GetParentShadowEntity( ClientShadowHandle_t handle );
  818. // Adds the child bounds to the bounding box
  819. void AddChildBounds( matrix3x4_t &matWorldToBBox, IClientRenderable* pParent, Vector &vecMins, Vector &vecMaxs );
  820. // Compute a bounds for the entity + children
  821. void ComputeHierarchicalBounds( IClientRenderable *pRenderable, Vector &vecMins, Vector &vecMaxs );
  822. // Builds matrices transforming from world space to shadow space
  823. void BuildGeneralWorldToShadowMatrix( VMatrix& matWorldToShadow,
  824. const Vector& origin, const Vector& dir, const Vector& xvec, const Vector& yvec );
  825. void BuildWorldToShadowMatrix( VMatrix& matWorldToShadow, const Vector& origin, const Quaternion& quatOrientation );
  826. void BuildPerspectiveWorldToFlashlightMatrix( VMatrix& matWorldToShadow, const FlashlightState_t &flashlightState );
  827. void BuildOrthoWorldToFlashlightMatrix( VMatrix& matWorldToShadow, const FlashlightState_t &flashlightState );
  828. // Update a shadow
  829. void UpdateProjectedTextureInternal( ClientShadowHandle_t handle, bool force );
  830. // Compute the shadow origin and attenuation start distance
  831. float ComputeLocalShadowOrigin( IClientRenderable* pRenderable,
  832. const Vector& mins, const Vector& maxs, const Vector& localShadowDir, float backupFactor, Vector& origin );
  833. // Remove a shadow from the dirty list
  834. void RemoveShadowFromDirtyList( ClientShadowHandle_t handle );
  835. // NOTE: this will ONLY return SHADOWS_NONE, SHADOWS_SIMPLE, or SHADOW_RENDER_TO_TEXTURE.
  836. ShadowType_t GetActualShadowCastType( ClientShadowHandle_t handle ) const;
  837. ShadowType_t GetActualShadowCastType( IClientRenderable *pRenderable ) const;
  838. // Builds a simple blobby shadow
  839. void BuildOrthoShadow( IClientRenderable* pRenderable, ClientShadowHandle_t handle, const Vector& mins, const Vector& maxs);
  840. // Builds a more complex shadow...
  841. void BuildRenderToTextureShadow( IClientRenderable* pRenderable,
  842. ClientShadowHandle_t handle, const Vector& mins, const Vector& maxs );
  843. // Build a projected-texture flashlight
  844. void BuildFlashlight( ClientShadowHandle_t handle );
  845. // Does all the lovely stuff we need to do to have render-to-texture shadows
  846. void SetupRenderToTextureShadow( ClientShadowHandle_t h );
  847. void CleanUpRenderToTextureShadow( ClientShadowHandle_t h );
  848. // Compute the extra shadow planes
  849. void ComputeExtraClipPlanes( IClientRenderable* pRenderable,
  850. ClientShadowHandle_t handle, const Vector* vec,
  851. const Vector& mins, const Vector& maxs, const Vector& localShadowDir );
  852. // Set extra clip planes related to shadows...
  853. void ClearExtraClipPlanes( ClientShadowHandle_t h );
  854. void AddExtraClipPlane( ClientShadowHandle_t h, const Vector& normal, float dist );
  855. // Cull if the origin is on the wrong side of a shadow clip plane....
  856. bool CullReceiver( ClientShadowHandle_t handle, IClientRenderable* pRenderable, IClientRenderable* pSourceRenderable );
  857. bool ComputeSeparatingPlane( IClientRenderable* pRend1, IClientRenderable* pRend2, cplane_t* pPlane );
  858. // Causes all shadows to be re-updated
  859. void UpdateAllShadows();
  860. void RemoveAllShadowDecals();
  861. // One of these gets called with every shadow that potentially will need to re-render
  862. bool DrawRenderToTextureShadow( int nSlot, unsigned short clientShadowHandle, float flArea );
  863. void DrawRenderToTextureShadowLOD( int nSlot, unsigned short clientShadowHandle );
  864. // Draws all children shadows into our own
  865. bool DrawShadowHierarchy( IClientRenderable *pRenderable, const ClientShadow_t &shadow, bool bChild = false );
  866. // Setup stage for threading
  867. bool BuildSetupListForRenderToTextureShadow( unsigned short clientShadowHandle, float flArea );
  868. bool BuildSetupShadowHierarchy( IClientRenderable *pRenderable, const ClientShadow_t &shadow, bool bChild = false );
  869. // Computes + sets the render-to-texture texcoords
  870. void SetRenderToTextureShadowTexCoords( ShadowHandle_t handle, int x, int y, int w, int h );
  871. void SetRenderToTextureShadowTexCoords( ClientShadow_t& shadow, int x, int y, int w, int h );
  872. // Visualization....
  873. void DrawRenderToTextureDebugInfo( IClientRenderable* pRenderable, const Vector& mins, const Vector& maxs );
  874. // Advance frame
  875. void AdvanceFrame();
  876. // Returns renderable-specific shadow info
  877. float GetShadowDistance( IClientRenderable *pRenderable ) const;
  878. const Vector &GetShadowDirection( IClientRenderable *pRenderable ) const;
  879. const Vector &GetShadowDirection( ClientShadowHandle_t shadowHandle ) const;
  880. // Initialize, shutdown render-to-texture shadows
  881. void InitDepthTextureShadows();
  882. void ShutdownDepthTextureShadows();
  883. // Initialize, shutdown render-to-texture shadows
  884. void InitRenderToTextureShadows();
  885. void ShutdownRenderToTextureShadows();
  886. // Initialize, shutdown deferred render-to-texture shadows
  887. void InitDeferredShadows();
  888. void ShutdownDeferredShadows();
  889. void ShutdownRenderTargets( void );
  890. static bool ShadowHandleCompareFunc( const ClientShadowHandle_t& lhs, const ClientShadowHandle_t& rhs )
  891. {
  892. return lhs < rhs;
  893. }
  894. ClientShadowHandle_t CreateProjectedTexture( ClientEntityHandle_t entity, int nEntIndex, int flags, CBitVec< MAX_SPLITSCREEN_PLAYERS > *pSplitScreenBits, bool bShareProjectedTextureBetweenSplitscreenPlayers );
  895. // Lock down the usage of a shadow depth texture...must be unlocked use on subsequent views / frames
  896. bool LockShadowDepthTexture( CTextureReference *shadowDepthTexture, int nStartTexture );
  897. void UnlockAllShadowDepthTextures();
  898. // Set and clear flashlight target renderable
  899. void SetFlashlightTarget( ClientShadowHandle_t shadowHandle, EHANDLE targetEntity );
  900. // Set flashlight light world flag
  901. void SetFlashlightLightWorld( ClientShadowHandle_t shadowHandle, bool bLightWorld );
  902. bool IsFlashlightTarget( ClientShadowHandle_t shadowHandle, IClientRenderable *pRenderable );
  903. // Builds a list of active shadows requiring shadow depth renders
  904. int BuildActiveShadowDepthList( const CViewSetup &viewSetup, int nMaxDepthShadows, ClientShadowHandle_t *pActiveDepthShadows, int &nNumHighRes );
  905. // Builds a list of active flashlights
  906. int BuildActiveFlashlightList( const CViewSetup &viewSetup, int nMaxFlashlights, ClientShadowHandle_t *pActiveFlashlights );
  907. // Sets the view's active flashlight render state
  908. void SetViewFlashlightState( int nActiveFlashlightCount, ClientShadowHandle_t* pActiveFlashlights );
  909. // Draw flashlight wireframe using debug overlay
  910. void DrawFrustum( const Vector &vOrigin, const VMatrix &matWorldToFlashlight );
  911. // Draw uberlight rig in wireframe using debug overlay
  912. void DrawUberlightRig( const Vector &vOrigin, const VMatrix &matWorldToFlashlight, FlashlightState_t state );
  913. // Called from PreRender to work through the dirty shadow set
  914. void UpdateDirtyShadows();
  915. void UpdateDirtyShadowsHalfRate();
  916. void UpdateDirtyShadow( ClientShadowHandle_t handle );
  917. void FlushLeftOverDirtyShadows();
  918. void QueueShadowForDestruction( ClientShadowHandle_t handle );
  919. void DestroyQueuedShadows();
  920. // Deferred RTT shadow rendering support
  921. static void BuildCubeWithDegenerateEdgeQuads( CMeshBuilder& meshBuilder, const matrix3x4_t& objToWorld, const VMatrix& projToShadow, const CClientShadowMgr::ClientShadow_t& shadow );
  922. bool SetupDeferredShadow( const ClientShadow_t& shadow, const Vector& camPos, matrix3x4_t* pObjToWorldMat ) const;
  923. void DownsampleDepthBuffer( IMatRenderContext* pRenderContext, const VMatrix& invViewProjMat );
  924. void CompositeDeferredShadows( IMatRenderContext* pRenderContext );
  925. static void ComputeFalloffInfo( const ClientShadow_t& shadow, Vector* pShadowFalloffParams );
  926. private:
  927. Vector m_SimpleShadowDir;
  928. color32 m_AmbientLightColor;
  929. CMaterialReference m_SimpleShadow;
  930. CMaterialReference m_RenderShadow;
  931. CMaterialReference m_RenderModelShadow;
  932. CMaterialReference m_RenderDeferredShadowMat;
  933. CMaterialReference m_RenderDeferredSimpleShadowMat;
  934. CTextureReference m_DummyColorTexture;
  935. CUtlLinkedList< ClientShadow_t, ClientShadowHandle_t > m_Shadows;
  936. CTextureAllocator m_ShadowAllocator;
  937. bool m_RenderToTextureActive;
  938. bool m_bRenderTargetNeedsClear;
  939. bool m_bUpdatingDirtyShadows;
  940. float m_flShadowCastDist;
  941. float m_flMinShadowArea;
  942. typedef CUtlRBTree< ClientShadowHandle_t, unsigned short > ClientShadowHandleSet;
  943. ClientShadowHandleSet m_DirtyShadows;
  944. ClientShadowHandleSet m_DirtyShadowsLeftOver; // shadows left over to update from previous frame
  945. CUtlVector< ClientShadowHandle_t > m_TransparentShadows;
  946. CUtlVector< ClientShadowHandle_t > m_shadowsToDestroy;
  947. int m_nPrevFrameCount;
  948. // These members maintain current state of depth texturing (size and global active state)
  949. // If either changes in a frame, PreRender() will catch it and do the appropriate allocation, deallocation or reallocation
  950. bool m_bDepthTextureActive;
  951. int m_nDepthTextureResolution; // Assume square (height == width)
  952. int m_nDepthTextureResolutionHigh; // Assume square (height == width)
  953. int m_nLowResStart; // Place in the shadow render target where the low res shadows start
  954. bool m_bDepthTexturesAllocated;
  955. uint32 m_uiDepthTextureCache;
  956. CUtlVector< CTextureReference > m_DepthTextureCache;
  957. CUtlVector< bool > m_DepthTextureCacheLocks;
  958. int m_nMaxDepthTextureShadows;
  959. bool m_bShadowFromWorldLights;
  960. bool m_bSuppressShadowFromWorldLights;
  961. friend class CVisibleShadowList;
  962. friend class CVisibleShadowFrustumList;
  963. CTextureReference m_downSampledNormals;
  964. CTextureReference m_downSampledDepth;
  965. void CalculateRenderTargetsAndSizes( void );
  966. };
  967. //-----------------------------------------------------------------------------
  968. // Singleton
  969. //-----------------------------------------------------------------------------
  970. static CClientShadowMgr s_ClientShadowMgr;
  971. IClientShadowMgr* g_pClientShadowMgr = &s_ClientShadowMgr;
  972. //-----------------------------------------------------------------------------
  973. // Builds a list of potential shadows that lie within our PVS + view frustum
  974. //-----------------------------------------------------------------------------
  975. struct VisibleShadowInfo_t
  976. {
  977. ClientShadowHandle_t m_hShadow;
  978. float m_flArea;
  979. Vector m_vecAbsCenter;
  980. };
  981. class CVisibleShadowList : public IClientLeafShadowEnum
  982. {
  983. public:
  984. CVisibleShadowList();
  985. int FindShadows( const CViewSetup *pView, int nLeafCount, WorldListLeafData_t *pLeafList );
  986. int GetVisibleShadowCount() const;
  987. int GetVisibleBlobbyShadowCount() const;
  988. const VisibleShadowInfo_t &GetVisibleShadow( int i ) const;
  989. const VisibleShadowInfo_t &GetVisibleBlobbyShadow( int i ) const;
  990. private:
  991. void EnumShadow( unsigned short clientShadowHandle );
  992. float ComputeScreenArea( const Vector &vecCenter, float r ) const;
  993. void PrioritySort();
  994. CUtlVector<VisibleShadowInfo_t> m_ShadowsInView;
  995. CUtlVector<VisibleShadowInfo_t> m_BlobbyShadowsInView;
  996. CUtlVector<int> m_PriorityIndex;
  997. };
  998. //-----------------------------------------------------------------------------
  999. // Singleton instances of shadow and shadow frustum lists
  1000. //-----------------------------------------------------------------------------
  1001. static CVisibleShadowList s_VisibleShadowList;
  1002. //-----------------------------------------------------------------------------
  1003. //
  1004. //-----------------------------------------------------------------------------
  1005. static CUtlVector<C_BaseAnimating *> s_NPCShadowBoneSetups;
  1006. static CUtlVector<C_BaseAnimating *> s_NonNPCShadowBoneSetups;
  1007. //-----------------------------------------------------------------------------
  1008. // CVisibleShadowList - Constructor and Accessors
  1009. //-----------------------------------------------------------------------------
  1010. CVisibleShadowList::CVisibleShadowList() : m_ShadowsInView( 0, 64 ), m_PriorityIndex( 0, 64 )
  1011. {
  1012. }
  1013. int CVisibleShadowList::GetVisibleShadowCount() const
  1014. {
  1015. return m_ShadowsInView.Count();
  1016. }
  1017. const VisibleShadowInfo_t &CVisibleShadowList::GetVisibleShadow( int i ) const
  1018. {
  1019. return m_ShadowsInView[m_PriorityIndex[i]];
  1020. }
  1021. int CVisibleShadowList::GetVisibleBlobbyShadowCount() const
  1022. {
  1023. return m_BlobbyShadowsInView.Count();
  1024. }
  1025. const VisibleShadowInfo_t &CVisibleShadowList::GetVisibleBlobbyShadow( int i ) const
  1026. {
  1027. return m_BlobbyShadowsInView[i];
  1028. }
  1029. //-----------------------------------------------------------------------------
  1030. // CVisibleShadowList - Computes approximate screen area of the shadow
  1031. //-----------------------------------------------------------------------------
  1032. float CVisibleShadowList::ComputeScreenArea( const Vector &vecCenter, float r ) const
  1033. {
  1034. CMatRenderContextPtr pRenderContext( materials );
  1035. float flScreenDiameter = pRenderContext->ComputePixelDiameterOfSphere( vecCenter, r );
  1036. return flScreenDiameter * flScreenDiameter;
  1037. }
  1038. //-----------------------------------------------------------------------------
  1039. // CVisibleShadowList - Visits every shadow in the list of leaves
  1040. //-----------------------------------------------------------------------------
  1041. void CVisibleShadowList::EnumShadow( unsigned short clientShadowHandle )
  1042. {
  1043. CClientShadowMgr::ClientShadow_t& shadow = s_ClientShadowMgr.m_Shadows[clientShadowHandle];
  1044. // Don't bother if we rendered it this frame, no matter which view it was rendered for
  1045. if ( shadow.m_nRenderFrame == gpGlobals->framecount )
  1046. return;
  1047. // Don't bother with flashlights
  1048. if ( ( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION )) != 0 )
  1049. return;
  1050. // We don't need to bother with it if it's not render-to-texture
  1051. ShadowType_t shadowType = s_ClientShadowMgr.GetActualShadowCastType( clientShadowHandle );
  1052. if ( shadowType != SHADOWS_RENDER_TO_TEXTURE && shadowType != SHADOWS_SIMPLE )
  1053. return;
  1054. // Don't bother with it if the shadow is totally transparent
  1055. if ( shadow.m_FalloffBias == 255 )
  1056. return;
  1057. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity );
  1058. Assert( pRenderable );
  1059. // Don't bother with children of hierarchy; they will be drawn with their parents
  1060. if ( s_ClientShadowMgr.ShouldUseParentShadow( pRenderable ) || s_ClientShadowMgr.WillParentRenderBlobbyShadow( pRenderable ) )
  1061. return;
  1062. // Compute a sphere surrounding the shadow
  1063. // FIXME: This doesn't account for children of hierarchy... too bad!
  1064. Vector vecAbsCenter;
  1065. float flRadius;
  1066. s_ClientShadowMgr.ComputeBoundingSphere( pRenderable, vecAbsCenter, flRadius );
  1067. // Compute a box surrounding the shadow
  1068. Vector vecAbsMins, vecAbsMaxs;
  1069. s_ClientShadowMgr.ComputeShadowBBox( pRenderable, clientShadowHandle, vecAbsCenter, flRadius, &vecAbsMins, &vecAbsMaxs );
  1070. // FIXME: Add distance check here?
  1071. // Make sure it's in the frustum. If it isn't it's not interesting
  1072. if (engine->CullBox( vecAbsMins, vecAbsMaxs ))
  1073. return;
  1074. if ( shadowType == SHADOWS_RENDER_TO_TEXTURE )
  1075. {
  1076. int i = m_ShadowsInView.AddToTail( );
  1077. VisibleShadowInfo_t &info = m_ShadowsInView[i];
  1078. info.m_hShadow = clientShadowHandle;
  1079. info.m_flArea = ComputeScreenArea( vecAbsCenter, flRadius );
  1080. // Har, har. When water is rendering (or any multipass technique),
  1081. // we may well initially render from a viewpoint which doesn't include this shadow.
  1082. // That doesn't mean we shouldn't check it again though. Sucks that we need to compute
  1083. // the sphere + bbox multiply times though.
  1084. shadow.m_nRenderFrame = gpGlobals->framecount;
  1085. }
  1086. else
  1087. {
  1088. int i = m_BlobbyShadowsInView.AddToTail( );
  1089. VisibleShadowInfo_t &info = m_BlobbyShadowsInView[i];
  1090. info.m_hShadow = clientShadowHandle;
  1091. info.m_flArea = 0.0f;
  1092. }
  1093. }
  1094. //-----------------------------------------------------------------------------
  1095. // CVisibleShadowList - Sort based on screen area/priority
  1096. //-----------------------------------------------------------------------------
  1097. void CVisibleShadowList::PrioritySort()
  1098. {
  1099. int nCount = m_ShadowsInView.Count();
  1100. m_PriorityIndex.EnsureCapacity( nCount );
  1101. m_PriorityIndex.RemoveAll();
  1102. int i, j;
  1103. for ( i = 0; i < nCount; ++i )
  1104. {
  1105. m_PriorityIndex.AddToTail(i);
  1106. }
  1107. for ( i = 0; i < nCount - 1; ++i )
  1108. {
  1109. int nLargestInd = i;
  1110. float flLargestArea = m_ShadowsInView[m_PriorityIndex[i]].m_flArea;
  1111. for ( j = i + 1; j < nCount; ++j )
  1112. {
  1113. int nIndex = m_PriorityIndex[j];
  1114. if ( flLargestArea < m_ShadowsInView[nIndex].m_flArea )
  1115. {
  1116. nLargestInd = j;
  1117. flLargestArea = m_ShadowsInView[nIndex].m_flArea;
  1118. }
  1119. }
  1120. V_swap( m_PriorityIndex[i], m_PriorityIndex[nLargestInd] );
  1121. }
  1122. }
  1123. //-----------------------------------------------------------------------------
  1124. // CVisibleShadowList - Main entry point for finding shadows in the leaf list
  1125. //-----------------------------------------------------------------------------
  1126. int CVisibleShadowList::FindShadows( const CViewSetup *pView, int nLeafCount, WorldListLeafData_t *pLeafList )
  1127. {
  1128. VPROF_BUDGET( "CVisibleShadowList::FindShadows", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  1129. m_ShadowsInView.RemoveAll();
  1130. m_BlobbyShadowsInView.RemoveAll();
  1131. ClientLeafSystem()->EnumerateShadowsInLeaves( nLeafCount, pLeafList, this );
  1132. int nCount = m_ShadowsInView.Count();
  1133. if (nCount != 0)
  1134. {
  1135. // Sort based on screen area/priority
  1136. PrioritySort();
  1137. }
  1138. return nCount;
  1139. }
  1140. // sniff the command line parameters, etc. to determine how many shadow rt's and their dimensions
  1141. void CClientShadowMgr::CalculateRenderTargetsAndSizes( void )
  1142. {
  1143. bool bTools = CommandLine()->CheckParm( "-tools" ) != NULL;
  1144. m_nDepthTextureResolution = r_flashlightdepthres.GetInt();
  1145. m_nDepthTextureResolutionHigh = r_flashlightdepthreshigh.GetInt();
  1146. if ( bTools ) // Higher resolution shadow maps in tools mode
  1147. {
  1148. char defaultRes[] = "2048";
  1149. m_nDepthTextureResolution = atoi( CommandLine()->ParmValue( "-sfm_shadowmapres", defaultRes ) );
  1150. }
  1151. m_nMaxDepthTextureShadows = bTools ? MAX_DEPTH_TEXTURE_SHADOWS_TOOLS : MAX_DEPTH_TEXTURE_SHADOWS; // Just one shadow depth texture in games, more in tools
  1152. }
  1153. //-----------------------------------------------------------------------------
  1154. // Constructor
  1155. //-----------------------------------------------------------------------------
  1156. CClientShadowMgr::CClientShadowMgr() :
  1157. m_DirtyShadows( 0, 0, ShadowHandleCompareFunc ),
  1158. m_DirtyShadowsLeftOver( 0, 0, ShadowHandleCompareFunc ),
  1159. m_nPrevFrameCount( -1 ),
  1160. m_RenderToTextureActive( false ),
  1161. m_bDepthTextureActive( false ),
  1162. m_bDepthTexturesAllocated( false ),
  1163. m_bShadowFromWorldLights( false ),
  1164. m_bSuppressShadowFromWorldLights( false ),
  1165. m_uiDepthTextureCache( 0 )
  1166. {
  1167. }
  1168. //-----------------------------------------------------------------------------
  1169. // Changes the shadow direction...
  1170. //-----------------------------------------------------------------------------
  1171. CON_COMMAND_F( r_shadowdir, "Set shadow direction", FCVAR_CHEAT )
  1172. {
  1173. Vector dir;
  1174. if ( args.ArgC() == 1 )
  1175. {
  1176. Vector dir = s_ClientShadowMgr.GetShadowDirection();
  1177. Msg( "%.2f %.2f %.2f\n", dir.x, dir.y, dir.z );
  1178. return;
  1179. }
  1180. if ( args.ArgC() == 4 )
  1181. {
  1182. dir.x = atof( args[1] );
  1183. dir.y = atof( args[2] );
  1184. dir.z = atof( args[3] );
  1185. s_ClientShadowMgr.SetShadowDirection(dir);
  1186. }
  1187. }
  1188. CON_COMMAND_F( r_shadowangles, "Set shadow angles", FCVAR_CHEAT )
  1189. {
  1190. Vector dir;
  1191. QAngle angles;
  1192. if (args.ArgC() == 1)
  1193. {
  1194. Vector dir = s_ClientShadowMgr.GetShadowDirection();
  1195. QAngle angles;
  1196. VectorAngles( dir, angles );
  1197. Msg( "%.2f %.2f %.2f\n", angles.x, angles.y, angles.z );
  1198. return;
  1199. }
  1200. if (args.ArgC() == 4)
  1201. {
  1202. angles.x = atof( args[1] );
  1203. angles.y = atof( args[2] );
  1204. angles.z = atof( args[3] );
  1205. AngleVectors( angles, &dir );
  1206. s_ClientShadowMgr.SetShadowDirection(dir);
  1207. }
  1208. }
  1209. CON_COMMAND_F( r_shadowcolor, "Set shadow color", FCVAR_CHEAT )
  1210. {
  1211. if (args.ArgC() == 1)
  1212. {
  1213. unsigned char r, g, b;
  1214. s_ClientShadowMgr.GetShadowColor( &r, &g, &b );
  1215. Msg( "Shadow color %d %d %d\n", r, g, b );
  1216. return;
  1217. }
  1218. if (args.ArgC() == 4)
  1219. {
  1220. int r = atoi( args[1] );
  1221. int g = atoi( args[2] );
  1222. int b = atoi( args[3] );
  1223. s_ClientShadowMgr.SetShadowColor(r, g, b);
  1224. }
  1225. }
  1226. CON_COMMAND_F( r_shadowdist, "Set shadow distance", FCVAR_CHEAT )
  1227. {
  1228. if (args.ArgC() == 1)
  1229. {
  1230. float flDist;
  1231. flDist = s_ClientShadowMgr.GetShadowDistance( );
  1232. Msg( "Shadow distance %.2f\n", flDist );
  1233. return;
  1234. }
  1235. if (args.ArgC() == 2)
  1236. {
  1237. float flDistance = atof( args[1] );
  1238. s_ClientShadowMgr.SetShadowDistance( flDistance );
  1239. }
  1240. }
  1241. CON_COMMAND_F( r_shadowblobbycutoff, "some shadow stuff", FCVAR_CHEAT )
  1242. {
  1243. if (args.ArgC() == 1)
  1244. {
  1245. float flArea;
  1246. flArea = s_ClientShadowMgr.GetBlobbyCutoffArea( );
  1247. Msg( "Cutoff area %.2f\n", flArea );
  1248. return;
  1249. }
  1250. if (args.ArgC() == 2)
  1251. {
  1252. float flArea = atof( args[1] );
  1253. s_ClientShadowMgr.SetShadowBlobbyCutoffArea( flArea );
  1254. }
  1255. }
  1256. void OnShadowFromWorldLights( IConVar *var, const char *pOldValue, float flOldValue );
  1257. static ConVar r_shadowfromworldlights( "r_shadowfromworldlights", "1", FCVAR_NONE, "Enable shadowing from world lights", OnShadowFromWorldLights );
  1258. void OnShadowFromWorldLights( IConVar *var, const char *pOldValue, float flOldValue )
  1259. {
  1260. s_ClientShadowMgr.SuppressShadowFromWorldLights( !r_shadowfromworldlights.GetBool() );
  1261. }
  1262. static void ShadowRestoreFunc( int nChangeFlags )
  1263. {
  1264. s_ClientShadowMgr.RestoreRenderState();
  1265. }
  1266. //-----------------------------------------------------------------------------
  1267. // Initialization, shutdown
  1268. //-----------------------------------------------------------------------------
  1269. bool CClientShadowMgr::Init()
  1270. {
  1271. return true;
  1272. }
  1273. void CClientShadowMgr::InitRenderTargets()
  1274. {
  1275. m_bRenderTargetNeedsClear = false;
  1276. m_SimpleShadow.Init( "decals/simpleshadow", TEXTURE_GROUP_DECAL );
  1277. Vector dir( 0.1, 0.1, -1 );
  1278. SetShadowDirection(dir);
  1279. SetShadowDistance( 50 );
  1280. SetShadowBlobbyCutoffArea( 0.005 );
  1281. if ( r_shadowrendertotexture.GetBool() )
  1282. {
  1283. InitRenderToTextureShadows();
  1284. }
  1285. // If someone turned shadow depth mapping on but we can't do it, force it off
  1286. if ( r_flashlightdepthtexture.GetBool() && !g_pMaterialSystemHardwareConfig->SupportsShadowDepthTextures() )
  1287. {
  1288. r_flashlightdepthtexture.SetValue( 0 );
  1289. ShutdownDepthTextureShadows();
  1290. }
  1291. InitDepthTextureShadows();
  1292. r_flashlightdepthres.SetValue( m_nDepthTextureResolution );
  1293. r_flashlightdepthreshigh.SetValue( m_nDepthTextureResolutionHigh );
  1294. if ( m_DepthTextureCache.Count() )
  1295. {
  1296. bool bTools = CommandLine()->CheckParm( "-tools" ) != NULL;
  1297. int nNumShadows = bTools ? MAX_DEPTH_TEXTURE_SHADOWS_TOOLS : MAX_DEPTH_TEXTURE_SHADOWS;
  1298. m_nLowResStart = bTools ? MAX_DEPTH_TEXTURE_HIGHRES_SHADOWS_TOOLS : MAX_DEPTH_TEXTURE_HIGHRES_SHADOWS;
  1299. if ( m_nLowResStart > nNumShadows )
  1300. {
  1301. // All shadow slots filled with high res
  1302. m_nLowResStart = 0;
  1303. }
  1304. // Shadow may be resized during allocation (due to resolution constraints etc)
  1305. m_nDepthTextureResolution = m_DepthTextureCache[ m_nLowResStart ]->GetActualWidth();
  1306. r_flashlightdepthres.SetValue( m_nDepthTextureResolution );
  1307. m_nDepthTextureResolutionHigh = m_DepthTextureCache[ 0 ]->GetActualWidth();
  1308. r_flashlightdepthreshigh.SetValue( m_nDepthTextureResolutionHigh );
  1309. }
  1310. InitDeferredShadows();
  1311. materials->AddRestoreFunc( ShadowRestoreFunc );
  1312. }
  1313. void CClientShadowMgr::ShutdownRenderTargets( void )
  1314. {
  1315. if ( materials ) // ugh - this gets called during program shutdown, but with no mat system
  1316. {
  1317. materials->RemoveRestoreFunc( ShadowRestoreFunc );
  1318. }
  1319. }
  1320. void CClientShadowMgr::Shutdown()
  1321. {
  1322. ShutdownRenderTargets();
  1323. m_SimpleShadow.Shutdown();
  1324. m_Shadows.RemoveAll();
  1325. ShutdownRenderToTextureShadows();
  1326. ShutdownDepthTextureShadows();
  1327. ShutdownDeferredShadows();
  1328. }
  1329. //-----------------------------------------------------------------------------
  1330. // Initialize, shutdown depth-texture shadows
  1331. //-----------------------------------------------------------------------------
  1332. void CClientShadowMgr::InitDepthTextureShadows()
  1333. {
  1334. VPROF_BUDGET( "CClientShadowMgr::InitDepthTextureShadows", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  1335. if ( m_bDepthTextureActive )
  1336. return;
  1337. m_bDepthTextureActive = true;
  1338. if ( !r_flashlightdepthtexture.GetBool() )
  1339. return;
  1340. if( !m_bDepthTexturesAllocated || m_nDepthTextureResolution != r_flashlightdepthres.GetInt() || m_nDepthTextureResolutionHigh != r_flashlightdepthreshigh.GetInt() )
  1341. {
  1342. CalculateRenderTargetsAndSizes();
  1343. m_bDepthTexturesAllocated = true;
  1344. ImageFormat dstFormat = g_pMaterialSystemHardwareConfig->GetShadowDepthTextureFormat(); // Vendor-dependent depth texture format
  1345. #if !defined( _X360 )
  1346. ImageFormat nullFormat = g_pMaterialSystemHardwareConfig->GetNullTextureFormat(); // Vendor-dependent null texture format (takes as little memory as possible)
  1347. #endif
  1348. materials->BeginRenderTargetAllocation();
  1349. RenderTargetSizeMode_t sizeMode = RT_SIZE_OFFSCREEN;
  1350. if ( IsPS3() || IsPC() )
  1351. {
  1352. // Don't allow the shadow buffer render target's to get resized to always be <= the size of the backbuffer on the PC.
  1353. // This allows us to use 1024x1024 or larger shadow depth buffers when 1024x768 backbuffers, for example.
  1354. sizeMode = RT_SIZE_NO_CHANGE;
  1355. }
  1356. #if defined( _X360 )
  1357. // For the 360, we'll be rendering depth directly into the dummy depth and Resolve()ing to the depth texture.
  1358. // only need the dummy surface, don't care about color results
  1359. m_DummyColorTexture.InitRenderTargetTexture( m_nDepthTextureResolution, m_nDepthTextureResolution, RT_SIZE_OFFSCREEN, IMAGE_FORMAT_BGR565, MATERIAL_RT_DEPTH_SHARED, false, "_rt_ShadowDummy", CREATERENDERTARGETFLAGS_ALIASCOLORANDDEPTHSURFACES );
  1360. m_DummyColorTexture.InitRenderTargetSurface( m_nDepthTextureResolution, m_nDepthTextureResolution, IMAGE_FORMAT_BGR565, false );
  1361. #elif defined (_PS3)
  1362. m_DummyColorTexture.InitRenderTarget( 8, 8, sizeMode, nullFormat, MATERIAL_RT_DEPTH_NONE, false, "_rt_ShadowDummy" );
  1363. #else
  1364. m_DummyColorTexture.InitRenderTarget( m_nDepthTextureResolution, m_nDepthTextureResolution, sizeMode, nullFormat, MATERIAL_RT_DEPTH_NONE, false, "_rt_ShadowDummy" );
  1365. #endif
  1366. // Create some number of depth-stencil textures
  1367. m_DepthTextureCache.Purge();
  1368. m_DepthTextureCacheLocks.Purge();
  1369. for( int i=0; i < m_nMaxDepthTextureShadows; i++ )
  1370. {
  1371. CTextureReference depthTex; // Depth-stencil surface
  1372. bool bFalse = false;
  1373. char strRTName[64];
  1374. Q_snprintf( strRTName, ARRAYSIZE( strRTName ), "_rt_ShadowDepthTexture_%d", i );
  1375. int nTextureResolution = ( i < MAX_DEPTH_TEXTURE_HIGHRES_SHADOWS ? m_nDepthTextureResolutionHigh : m_nDepthTextureResolution );
  1376. #if defined( _X360 )
  1377. // create a render target to use as a resolve target to get the shared depth buffer
  1378. // surface is effectively never used
  1379. depthTex.InitRenderTargetTexture( nTextureResolution, nTextureResolution, RT_SIZE_OFFSCREEN, dstFormat, MATERIAL_RT_DEPTH_NONE, false, strRTName );
  1380. depthTex.InitRenderTargetSurface( 1, 1, dstFormat, false );
  1381. #else
  1382. depthTex.InitRenderTarget( nTextureResolution, nTextureResolution, sizeMode, dstFormat, MATERIAL_RT_DEPTH_NONE, false, strRTName );
  1383. #endif
  1384. m_DepthTextureCache.AddToTail( depthTex );
  1385. m_DepthTextureCacheLocks.AddToTail( bFalse );
  1386. }
  1387. #if 0 // 7LTODO #ifdef _PS3
  1388. AssertFatalEquals( m_nMaxDepthTextureShadows, 1 );
  1389. for( int i=0; i < m_nMaxDepthTextureShadows; i++ )
  1390. {
  1391. CTextureReference depthTex; // Depth-stencil surface
  1392. bool bFalse = false;
  1393. char strRTName[64];
  1394. Q_snprintf( strRTName, ARRAYSIZE( strRTName ), "_rt_ShadowDepthTexture_Cache%d", i );
  1395. int nTextureResolution = ( i < MAX_DEPTH_TEXTURE_HIGHRES_SHADOWS ? m_nDepthTextureResolutionHigh : m_nDepthTextureResolution );
  1396. depthTex.InitRenderTarget( nTextureResolution, nTextureResolution, sizeMode, dstFormat, MATERIAL_RT_DEPTH_NONE, false, strRTName );
  1397. m_DepthTextureCache.AddToTail( depthTex );
  1398. m_DepthTextureCacheLocks.AddToTail( bFalse );
  1399. g_ps3_ShadowDepth_TextureCache = m_uiDepthTextureCache = materials->EstablishGpuDataTransferCache( PS3GPU_DATA_TRANSFER_CREATECACHELINK, m_DepthTextureCache[0], depthTex );
  1400. }
  1401. #endif
  1402. materials->EndRenderTargetAllocation();
  1403. }
  1404. }
  1405. void CClientShadowMgr::ShutdownDepthTextureShadows()
  1406. {
  1407. if( m_bDepthTexturesAllocated )
  1408. {
  1409. // Shut down the dummy texture
  1410. m_DummyColorTexture.Shutdown();
  1411. while( m_DepthTextureCache.Count() )
  1412. {
  1413. m_DepthTextureCache[ m_DepthTextureCache.Count()-1 ].Shutdown();
  1414. m_DepthTextureCacheLocks.Remove( m_DepthTextureCache.Count()-1 );
  1415. m_DepthTextureCache.Remove( m_DepthTextureCache.Count()-1 );
  1416. }
  1417. m_bDepthTexturesAllocated = false;
  1418. }
  1419. m_bDepthTextureActive = false;
  1420. }
  1421. //-----------------------------------------------------------------------------
  1422. // Initialize, shutdown render-to-texture shadows
  1423. //-----------------------------------------------------------------------------
  1424. void CClientShadowMgr::InitRenderToTextureShadows()
  1425. {
  1426. if ( !m_RenderToTextureActive )
  1427. {
  1428. m_RenderToTextureActive = true;
  1429. g_pMaterialSystem->BeginRenderTargetAllocation();
  1430. m_ShadowAllocator.Init();
  1431. g_pMaterialSystem->EndRenderTargetAllocation();
  1432. m_RenderShadow.Init( "decals/rendershadow", TEXTURE_GROUP_DECAL );
  1433. m_RenderModelShadow.Init( "decals/rendermodelshadow", TEXTURE_GROUP_DECAL );
  1434. m_ShadowAllocator.Reset();
  1435. m_bRenderTargetNeedsClear = true;
  1436. float fr = (float)m_AmbientLightColor.r / 255.0f;
  1437. float fg = (float)m_AmbientLightColor.g / 255.0f;
  1438. float fb = (float)m_AmbientLightColor.b / 255.0f;
  1439. m_RenderShadow->ColorModulate( fr, fg, fb );
  1440. m_RenderModelShadow->ColorModulate( fr, fg, fb );
  1441. // Iterate over all existing textures and allocate shadow textures
  1442. for (ClientShadowHandle_t i = m_Shadows.Head(); i != m_Shadows.InvalidIndex(); i = m_Shadows.Next(i) )
  1443. {
  1444. ClientShadow_t& shadow = m_Shadows[i];
  1445. if ( shadow.m_Flags & SHADOW_FLAGS_USE_RENDER_TO_TEXTURE )
  1446. {
  1447. SetupRenderToTextureShadow( i );
  1448. MarkRenderToTextureShadowDirty( i );
  1449. // Switch the material to use render-to-texture shadows
  1450. shadowmgr->SetShadowMaterial( shadow.m_ShadowHandle, m_RenderShadow, m_RenderModelShadow, (void*)(uintp)i );
  1451. }
  1452. }
  1453. }
  1454. }
  1455. void CClientShadowMgr::ShutdownRenderToTextureShadows()
  1456. {
  1457. if (m_RenderToTextureActive)
  1458. {
  1459. // Iterate over all existing textures and deallocate shadow textures
  1460. for (ClientShadowHandle_t i = m_Shadows.Head(); i != m_Shadows.InvalidIndex(); i = m_Shadows.Next(i) )
  1461. {
  1462. CleanUpRenderToTextureShadow( i );
  1463. // Switch the material to use blobby shadows
  1464. ClientShadow_t& shadow = m_Shadows[i];
  1465. shadowmgr->SetShadowMaterial( shadow.m_ShadowHandle, m_SimpleShadow, m_SimpleShadow, (void*)CLIENTSHADOW_INVALID_HANDLE );
  1466. shadowmgr->SetShadowTexCoord( shadow.m_ShadowHandle, 0, 0, 1, 1 );
  1467. ClearExtraClipPlanes( i );
  1468. }
  1469. m_RenderShadow.Shutdown();
  1470. m_RenderModelShadow.Shutdown();
  1471. m_ShadowAllocator.DeallocateAllTextures();
  1472. m_ShadowAllocator.Shutdown();
  1473. // Cause the render target to go away
  1474. materials->UncacheUnusedMaterials();
  1475. m_RenderToTextureActive = false;
  1476. }
  1477. }
  1478. #define DEFERRED_SHADOW_BUFFER_WIDTH 320
  1479. #define DEFERRED_SHADOW_BUFFER_HEIGHT 180
  1480. void CClientShadowMgr::InitDeferredShadows()
  1481. {
  1482. if ( IsGameConsole() )
  1483. {
  1484. m_RenderDeferredShadowMat.Init( "engine/renderdeferredshadow", TEXTURE_GROUP_OTHER );
  1485. m_RenderDeferredSimpleShadowMat.Init( "engine/renderdeferredsimpleshadow", TEXTURE_GROUP_OTHER );
  1486. }
  1487. if ( r_shadow_deferred_downsample.GetBool() )
  1488. {
  1489. #if defined( _X360 )
  1490. m_downSampledNormals.InitRenderTargetTexture( DEFERRED_SHADOW_BUFFER_WIDTH, DEFERRED_SHADOW_BUFFER_HEIGHT, RT_SIZE_OFFSCREEN, IMAGE_FORMAT_ARGB8888, MATERIAL_RT_DEPTH_SEPARATE, false, "_rt_DownsampledNormals" );
  1491. m_downSampledNormals.InitRenderTargetSurface( DEFERRED_SHADOW_BUFFER_WIDTH, DEFERRED_SHADOW_BUFFER_HEIGHT, IMAGE_FORMAT_ARGB8888, true );
  1492. m_downSampledDepth.InitRenderTargetTexture( DEFERRED_SHADOW_BUFFER_WIDTH, DEFERRED_SHADOW_BUFFER_HEIGHT, RT_SIZE_OFFSCREEN, IMAGE_FORMAT_D24FS8, MATERIAL_RT_DEPTH_NONE, false, "_rt_DownsampledDepth" );
  1493. #endif
  1494. }
  1495. }
  1496. void CClientShadowMgr::ShutdownDeferredShadows()
  1497. {
  1498. m_RenderDeferredShadowMat.Shutdown();
  1499. m_RenderDeferredSimpleShadowMat.Shutdown();
  1500. m_downSampledNormals.Shutdown();
  1501. m_downSampledDepth.Shutdown();
  1502. }
  1503. //-----------------------------------------------------------------------------
  1504. // Sets the shadow color
  1505. //-----------------------------------------------------------------------------
  1506. void CClientShadowMgr::SetShadowColor( unsigned char r, unsigned char g, unsigned char b )
  1507. {
  1508. float fr = (float)r / 255.0f;
  1509. float fg = (float)g / 255.0f;
  1510. float fb = (float)b / 255.0f;
  1511. // Hook the shadow color into the shadow materials
  1512. m_SimpleShadow->ColorModulate( fr, fg, fb );
  1513. if (m_RenderToTextureActive)
  1514. {
  1515. if ( m_RenderShadow )
  1516. {
  1517. m_RenderShadow->ColorModulate( fr, fg, fb );
  1518. }
  1519. if ( m_RenderModelShadow )
  1520. {
  1521. m_RenderModelShadow->ColorModulate( fr, fg, fb );
  1522. }
  1523. if ( IsGameConsole() )
  1524. {
  1525. m_RenderDeferredShadowMat->ColorModulate( fr, fg, fb );
  1526. m_RenderDeferredSimpleShadowMat->ColorModulate( fr, fg, fb );
  1527. }
  1528. }
  1529. m_AmbientLightColor.r = r;
  1530. m_AmbientLightColor.g = g;
  1531. m_AmbientLightColor.b = b;
  1532. }
  1533. void CClientShadowMgr::GetShadowColor( unsigned char *r, unsigned char *g, unsigned char *b ) const
  1534. {
  1535. *r = m_AmbientLightColor.r;
  1536. *g = m_AmbientLightColor.g;
  1537. *b = m_AmbientLightColor.b;
  1538. }
  1539. //-----------------------------------------------------------------------------
  1540. // Level init... get the shadow color
  1541. //-----------------------------------------------------------------------------
  1542. void CClientShadowMgr::LevelInitPreEntity()
  1543. {
  1544. m_bUpdatingDirtyShadows = false;
  1545. // Default setting for this, can be overridden by shadow control entities
  1546. SetShadowFromWorldLightsEnabled( true );
  1547. Vector ambientColor;
  1548. engine->GetAmbientLightColor( ambientColor );
  1549. ambientColor *= 3;
  1550. ambientColor += Vector( 0.3f, 0.3f, 0.3f );
  1551. unsigned char r = ambientColor[0] > 1.0 ? 255 : 255 * ambientColor[0];
  1552. unsigned char g = ambientColor[1] > 1.0 ? 255 : 255 * ambientColor[1];
  1553. unsigned char b = ambientColor[2] > 1.0 ? 255 : 255 * ambientColor[2];
  1554. SetShadowColor(r, g, b);
  1555. // Set up the texture allocator
  1556. if ( m_RenderToTextureActive )
  1557. {
  1558. m_ShadowAllocator.Reset();
  1559. m_bRenderTargetNeedsClear = true;
  1560. }
  1561. }
  1562. //-----------------------------------------------------------------------------
  1563. // Clean up all shadows
  1564. //-----------------------------------------------------------------------------
  1565. void CClientShadowMgr::LevelShutdownPostEntity()
  1566. {
  1567. // Paranoid code to make sure all flashlights are deactivated.
  1568. // This should happen in the C_BasePlayer destructor, but I'm turning everything off to release the
  1569. // flashlight shadows just in case.
  1570. for ( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; i++ )
  1571. {
  1572. FlashlightEffectManager( i ).TurnOffFlashlight( true );
  1573. }
  1574. // All shadows *should* have been cleaned up when the entities went away
  1575. // but, just in case....
  1576. Assert( m_Shadows.Count() == 0 );
  1577. ClientShadowHandle_t h = m_Shadows.Head();
  1578. while (h != CLIENTSHADOW_INVALID_HANDLE)
  1579. {
  1580. ClientShadowHandle_t next = m_Shadows.Next(h);
  1581. DestroyShadow( h );
  1582. h = next;
  1583. }
  1584. // Deallocate all textures
  1585. if (m_RenderToTextureActive)
  1586. {
  1587. m_ShadowAllocator.DeallocateAllTextures();
  1588. }
  1589. r_shadows_gamecontrol.SetValue( -1 );
  1590. }
  1591. //-----------------------------------------------------------------------------
  1592. // Deals with alt-tab
  1593. //-----------------------------------------------------------------------------
  1594. void CClientShadowMgr::RestoreRenderState()
  1595. {
  1596. // Mark all shadows dirty; they need to regenerate their state
  1597. ClientShadowHandle_t h;
  1598. for ( h = m_Shadows.Head(); h != m_Shadows.InvalidIndex(); h = m_Shadows.Next(h) )
  1599. {
  1600. m_Shadows[h].m_Flags |= SHADOW_FLAGS_TEXTURE_DIRTY;
  1601. }
  1602. SetShadowColor( m_AmbientLightColor.r, m_AmbientLightColor.g, m_AmbientLightColor.b );
  1603. m_bRenderTargetNeedsClear = true;
  1604. }
  1605. //-----------------------------------------------------------------------------
  1606. // Does all the lovely stuff we need to do to have render-to-texture shadows
  1607. //-----------------------------------------------------------------------------
  1608. void CClientShadowMgr::SetupRenderToTextureShadow( ClientShadowHandle_t h )
  1609. {
  1610. // First, compute how much texture memory we want to use.
  1611. ClientShadow_t& shadow = m_Shadows[h];
  1612. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity );
  1613. if ( !pRenderable )
  1614. return;
  1615. Vector mins, maxs;
  1616. pRenderable->GetShadowRenderBounds( mins, maxs, GetActualShadowCastType( h ) );
  1617. // Compute the maximum dimension
  1618. Vector size;
  1619. VectorSubtract( maxs, mins, size );
  1620. float maxSize = MAX( size.x, size.y );
  1621. maxSize = MAX( maxSize, size.z );
  1622. // Figure out the texture size
  1623. // For now, we're going to assume a fixed number of shadow texels
  1624. // per shadow-caster size; add in some extra space at the boundary.
  1625. int texelCount = TEXEL_SIZE_PER_CASTER_SIZE * maxSize;
  1626. // Pick the first power of 2 larger...
  1627. int textureSize = 1;
  1628. while (textureSize < texelCount)
  1629. {
  1630. textureSize <<= 1;
  1631. }
  1632. shadow.m_ShadowTexture = m_ShadowAllocator.AllocateTexture( textureSize, textureSize );
  1633. }
  1634. void CClientShadowMgr::CleanUpRenderToTextureShadow( ClientShadowHandle_t h )
  1635. {
  1636. ClientShadow_t& shadow = m_Shadows[h];
  1637. if (m_RenderToTextureActive && (shadow.m_Flags & SHADOW_FLAGS_USE_RENDER_TO_TEXTURE))
  1638. {
  1639. m_ShadowAllocator.DeallocateTexture( shadow.m_ShadowTexture );
  1640. shadow.m_ShadowTexture = INVALID_TEXTURE_HANDLE;
  1641. }
  1642. }
  1643. //-----------------------------------------------------------------------------
  1644. // Causes all shadows to be re-updated
  1645. //-----------------------------------------------------------------------------
  1646. void CClientShadowMgr::UpdateAllShadows()
  1647. {
  1648. for ( ClientShadowHandle_t i = m_Shadows.Head(); i != m_Shadows.InvalidIndex(); i = m_Shadows.Next(i) )
  1649. {
  1650. ClientShadow_t& shadow = m_Shadows[i];
  1651. // Don't bother with flashlights
  1652. if ( ( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) != 0 )
  1653. continue;
  1654. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity );
  1655. if ( !pRenderable )
  1656. continue;
  1657. Assert( pRenderable->GetShadowHandle() == i );
  1658. AddToDirtyShadowList( pRenderable, true );
  1659. }
  1660. }
  1661. void CClientShadowMgr::RemoveAllShadowDecals()
  1662. {
  1663. for ( ClientShadowHandle_t i = m_Shadows.Head(); i != m_Shadows.InvalidIndex(); i = m_Shadows.Next(i) )
  1664. {
  1665. ClientShadow_t& shadow = m_Shadows[i];
  1666. // Don't bother with flashlights
  1667. if ( ( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) != 0 )
  1668. continue;
  1669. shadowmgr->RemoveAllDecalsFromShadow( shadow.m_ShadowHandle );
  1670. }
  1671. }
  1672. //-----------------------------------------------------------------------------
  1673. // Sets the shadow direction
  1674. //-----------------------------------------------------------------------------
  1675. void CClientShadowMgr::SetShadowDirection( const Vector& dir )
  1676. {
  1677. VectorCopy( dir, m_SimpleShadowDir );
  1678. VectorNormalize( m_SimpleShadowDir );
  1679. if ( m_RenderToTextureActive )
  1680. {
  1681. UpdateAllShadows();
  1682. }
  1683. }
  1684. const Vector &CClientShadowMgr::GetShadowDirection() const
  1685. {
  1686. // This will cause blobby shadows to always project straight down
  1687. static Vector s_vecDown( 0, 0, -1 );
  1688. if ( !m_RenderToTextureActive )
  1689. return s_vecDown;
  1690. return m_SimpleShadowDir;
  1691. }
  1692. //-----------------------------------------------------------------------------
  1693. // Gets shadow information for a particular renderable
  1694. //-----------------------------------------------------------------------------
  1695. float CClientShadowMgr::GetShadowDistance( IClientRenderable *pRenderable ) const
  1696. {
  1697. float flDist = m_flShadowCastDist;
  1698. // Allow the renderable to override the default
  1699. pRenderable->GetShadowCastDistance( &flDist, GetActualShadowCastType( pRenderable ) );
  1700. return flDist;
  1701. }
  1702. const Vector &CClientShadowMgr::GetShadowDirection( IClientRenderable *pRenderable ) const
  1703. {
  1704. Vector &vecResult = AllocTempVector();
  1705. vecResult = GetShadowDirection();
  1706. // Allow the renderable to override the default
  1707. pRenderable->GetShadowCastDirection( &vecResult, GetActualShadowCastType( pRenderable ) );
  1708. return vecResult;
  1709. }
  1710. const Vector &CClientShadowMgr::GetShadowDirection( ClientShadowHandle_t shadowHandle ) const
  1711. {
  1712. Assert( shadowHandle != CLIENTSHADOW_INVALID_HANDLE );
  1713. IClientRenderable* pRenderable = ClientEntityList().GetClientRenderableFromHandle( m_Shadows[shadowHandle].m_Entity );
  1714. Assert( pRenderable );
  1715. if ( !IsShadowingFromWorldLights() )
  1716. {
  1717. return GetShadowDirection( pRenderable );
  1718. }
  1719. Vector &vecResult = AllocTempVector();
  1720. vecResult = m_Shadows[shadowHandle].m_ShadowDir;
  1721. // Allow the renderable to override the default
  1722. pRenderable->GetShadowCastDirection( &vecResult, GetActualShadowCastType( pRenderable ) );
  1723. return vecResult;
  1724. }
  1725. void CClientShadowMgr::UpdateShadowDirectionFromLocalLightSource( ClientShadowHandle_t shadowHandle )
  1726. {
  1727. Assert( shadowHandle != CLIENTSHADOW_INVALID_HANDLE );
  1728. ClientShadow_t& shadow = m_Shadows[shadowHandle];
  1729. IClientRenderable* pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity );
  1730. // TODO: Figure out why this still gets hit
  1731. Assert( pRenderable );
  1732. if ( !pRenderable )
  1733. {
  1734. DevWarning( "%s(): Skipping shadow with invalid client renderable (shadow handle %d)\n", __FUNCTION__, shadowHandle );
  1735. return;
  1736. }
  1737. Vector bbMin, bbMax;
  1738. pRenderable->GetRenderBoundsWorldspace( bbMin, bbMax );
  1739. Vector origin( 0.5f * ( bbMin + bbMax ) );
  1740. origin.z = bbMin.z; // Putting origin at the bottom of the bounding box makes the shadows a little shorter
  1741. Vector lightPos;
  1742. Vector lightBrightness;
  1743. if ( shadow.m_LightPosLerp >= 1.0f ) // skip finding new light source if we're in the middle of a lerp
  1744. {
  1745. if( modelrender->GetBrightestShadowingLightSource( pRenderable->GetRenderOrigin(), lightPos, lightBrightness,
  1746. r_shadowfromanyworldlight.GetBool() ) == false )
  1747. {
  1748. // didn't find a light source at all, use default shadow direction
  1749. // TODO: Could switch to using blobby shadow in this case
  1750. lightPos.Init( FLT_MAX, FLT_MAX, FLT_MAX );
  1751. }
  1752. }
  1753. if ( shadow.m_LightPosLerp == FLT_MAX ) // first light pos ever, just init
  1754. {
  1755. shadow.m_CurrentLightPos = lightPos;
  1756. shadow.m_TargetLightPos = lightPos;
  1757. shadow.m_LightPosLerp = 1.0f;
  1758. }
  1759. else if ( shadow.m_LightPosLerp < 1.0f )
  1760. {
  1761. // We're in the middle of a lerp from current to target light. Finish it.
  1762. shadow.m_LightPosLerp += gpGlobals->frametime * 1.0f/r_shadow_lightpos_lerptime.GetFloat();
  1763. shadow.m_LightPosLerp = clamp( shadow.m_LightPosLerp, 0.0f, 1.0f );
  1764. Vector currLightPos( shadow.m_CurrentLightPos );
  1765. Vector targetLightPos( shadow.m_TargetLightPos );
  1766. if ( currLightPos.x == FLT_MAX )
  1767. {
  1768. currLightPos = origin - 200.0f * GetShadowDirection();
  1769. }
  1770. if ( targetLightPos.x == FLT_MAX )
  1771. {
  1772. targetLightPos = origin - 200.0f * GetShadowDirection();
  1773. }
  1774. // lerp light pos
  1775. Vector v1 = origin - shadow.m_CurrentLightPos;
  1776. v1.NormalizeInPlace();
  1777. Vector v2 = origin - shadow.m_TargetLightPos;
  1778. v2.NormalizeInPlace();
  1779. if ( v1.Dot( v2 ) < 0.0f )
  1780. {
  1781. // if change in shadow angle is more than 90 degrees, lerp over the renderable's top to avoid long sweeping shadows
  1782. Vector fakeOverheadLightPos( origin.x, origin.y, origin.z + 200.0f );
  1783. if( shadow.m_LightPosLerp < 0.5f )
  1784. {
  1785. lightPos = Lerp( 2.0f * shadow.m_LightPosLerp, currLightPos, fakeOverheadLightPos );
  1786. }
  1787. else
  1788. {
  1789. lightPos = Lerp( 2.0f * shadow.m_LightPosLerp - 1.0f, fakeOverheadLightPos, targetLightPos );
  1790. }
  1791. }
  1792. else
  1793. {
  1794. lightPos = Lerp( shadow.m_LightPosLerp, currLightPos, targetLightPos );
  1795. }
  1796. if ( shadow.m_LightPosLerp >= 1.0f )
  1797. {
  1798. shadow.m_CurrentLightPos = shadow.m_TargetLightPos;
  1799. }
  1800. }
  1801. else if ( shadow.m_LightPosLerp >= 1.0f )
  1802. {
  1803. // check if we have a new closest light position and start a new lerp
  1804. float flDistSq = ( lightPos - shadow.m_CurrentLightPos ).LengthSqr();
  1805. if ( flDistSq > 1.0f )
  1806. {
  1807. // light position has changed, which means we got a new light source. Initiate a lerp
  1808. shadow.m_TargetLightPos = lightPos;
  1809. shadow.m_LightPosLerp = 0.0f;
  1810. }
  1811. lightPos = shadow.m_CurrentLightPos;
  1812. }
  1813. if ( lightPos.x == FLT_MAX )
  1814. {
  1815. lightPos = origin - 200.0f * GetShadowDirection();
  1816. }
  1817. Vector vecResult( origin - lightPos );
  1818. vecResult.NormalizeInPlace();
  1819. vecResult.z *= r_shadow_shortenfactor.GetFloat();
  1820. vecResult.NormalizeInPlace();
  1821. shadow.m_ShadowDir = vecResult;
  1822. if ( r_shadowfromworldlights_debug.GetBool() )
  1823. {
  1824. NDebugOverlay::Line( lightPos, origin, 255, 255, 0, false, 0.0f );
  1825. }
  1826. }
  1827. //-----------------------------------------------------------------------------
  1828. // Sets the shadow distance
  1829. //-----------------------------------------------------------------------------
  1830. void CClientShadowMgr::SetShadowDistance( float flMaxDistance )
  1831. {
  1832. m_flShadowCastDist = flMaxDistance;
  1833. UpdateAllShadows();
  1834. }
  1835. float CClientShadowMgr::GetShadowDistance( ) const
  1836. {
  1837. return m_flShadowCastDist;
  1838. }
  1839. //-----------------------------------------------------------------------------
  1840. // Sets the screen area at which blobby shadows are always used
  1841. //-----------------------------------------------------------------------------
  1842. void CClientShadowMgr::SetShadowBlobbyCutoffArea( float flMinArea )
  1843. {
  1844. m_flMinShadowArea = flMinArea;
  1845. }
  1846. float CClientShadowMgr::GetBlobbyCutoffArea( ) const
  1847. {
  1848. return m_flMinShadowArea;
  1849. }
  1850. //-----------------------------------------------------------------------------
  1851. // Purpose:
  1852. //-----------------------------------------------------------------------------
  1853. void CClientShadowMgr::SetFalloffBias( ClientShadowHandle_t handle, unsigned char ucBias )
  1854. {
  1855. shadowmgr->SetFalloffBias( m_Shadows[handle].m_ShadowHandle, ucBias );
  1856. m_Shadows[handle].m_FalloffBias = ucBias;
  1857. }
  1858. //-----------------------------------------------------------------------------
  1859. // Returns the shadow texture
  1860. //-----------------------------------------------------------------------------
  1861. ITexture* CClientShadowMgr::GetShadowTexture( unsigned short h )
  1862. {
  1863. return m_ShadowAllocator.GetTexture();
  1864. }
  1865. //-----------------------------------------------------------------------------
  1866. // Returns information needed by the model proxy
  1867. //-----------------------------------------------------------------------------
  1868. const ShadowInfo_t& CClientShadowMgr::GetShadowInfo( ClientShadowHandle_t h )
  1869. {
  1870. return shadowmgr->GetInfo( m_Shadows[h].m_ShadowHandle );
  1871. }
  1872. //-----------------------------------------------------------------------------
  1873. // Renders the shadow texture to screen...
  1874. //-----------------------------------------------------------------------------
  1875. void CClientShadowMgr::RenderShadowTexture( int w, int h )
  1876. {
  1877. if (m_RenderToTextureActive)
  1878. {
  1879. CMatRenderContextPtr pRenderContext( materials );
  1880. pRenderContext->Bind( m_RenderShadow );
  1881. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  1882. CMeshBuilder meshBuilder;
  1883. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  1884. meshBuilder.Position3f( 0.0f, 0.0f, 0.0f );
  1885. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  1886. meshBuilder.Color4ub( 0, 0, 0, 0 );
  1887. meshBuilder.AdvanceVertex();
  1888. meshBuilder.Position3f( w, 0.0f, 0.0f );
  1889. meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
  1890. meshBuilder.Color4ub( 0, 0, 0, 0 );
  1891. meshBuilder.AdvanceVertex();
  1892. meshBuilder.Position3f( w, h, 0.0f );
  1893. meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
  1894. meshBuilder.Color4ub( 0, 0, 0, 0 );
  1895. meshBuilder.AdvanceVertex();
  1896. meshBuilder.Position3f( 0.0f, h, 0.0f );
  1897. meshBuilder.TexCoord2f( 0, 0.0f, 1.0f );
  1898. meshBuilder.Color4ub( 0, 0, 0, 0 );
  1899. meshBuilder.AdvanceVertex();
  1900. meshBuilder.End();
  1901. pMesh->Draw();
  1902. }
  1903. }
  1904. //-----------------------------------------------------------------------------
  1905. // Create/destroy a shadow
  1906. //-----------------------------------------------------------------------------
  1907. ClientShadowHandle_t CClientShadowMgr::CreateProjectedTexture( ClientEntityHandle_t entity, int nEntIndex, int flags, CBitVec< MAX_SPLITSCREEN_PLAYERS > *pSplitScreenBits,
  1908. bool bShareProjectedTextureBetweenSplitscreenPlayers )
  1909. {
  1910. // We need to know if it's a brush model for shadows
  1911. if( ( flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) == 0 )
  1912. {
  1913. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( entity );
  1914. if ( !pRenderable )
  1915. return m_Shadows.InvalidIndex();
  1916. int modelType = modelinfo->GetModelType( pRenderable->GetModel() );
  1917. if (modelType == mod_brush)
  1918. {
  1919. flags |= SHADOW_FLAGS_BRUSH_MODEL;
  1920. }
  1921. }
  1922. ClientShadowHandle_t h = m_Shadows.AddToTail();
  1923. ClientShadow_t& shadow = m_Shadows[h];
  1924. shadow.m_Entity = entity;
  1925. if ( ( flags & SHADOW_FLAGS_SIMPLE_PROJECTION ) == 0 )
  1926. {
  1927. shadow.m_ClientLeafShadowHandle = ClientLeafSystem()->AddShadow( h, flags );
  1928. }
  1929. else
  1930. {
  1931. shadow.m_ClientLeafShadowHandle = CLIENT_LEAF_SHADOW_INVALID_HANDLE;
  1932. }
  1933. shadow.m_Flags = flags;
  1934. shadow.m_nRenderFrame = -1;
  1935. shadow.m_ShadowDir = GetShadowDirection();
  1936. shadow.m_LastOrigin.Init( FLT_MAX, FLT_MAX, FLT_MAX );
  1937. shadow.m_LastAngles.Init( FLT_MAX, FLT_MAX, FLT_MAX );
  1938. shadow.m_CurrentLightPos.Init( FLT_MAX, FLT_MAX, FLT_MAX );
  1939. shadow.m_TargetLightPos.Init( FLT_MAX, FLT_MAX, FLT_MAX );
  1940. shadow.m_LightPosLerp = FLT_MAX;
  1941. Assert( ( ( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) == 0 ) !=
  1942. ( ( shadow.m_Flags & SHADOW_FLAGS_SHADOW ) == 0 ) );
  1943. shadow.m_nLastUpdateFrame = 0;
  1944. shadow.m_nSplitscreenOwner = -1; // No one owns this texture, it will be shared between all splitscreen players
  1945. if ( !bShareProjectedTextureBetweenSplitscreenPlayers )
  1946. {
  1947. if ( ( flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) || ( flags & SHADOW_FLAGS_USE_DEPTH_TEXTURE ) )
  1948. {
  1949. // The local player isn't always resolvable if this projected texture isn't the player's flashlight, so
  1950. // if the local player isn't resolvable, leave the splitscreen owner set to -1 so all splitscreen players render it
  1951. if ( engine->IsLocalPlayerResolvable() )
  1952. {
  1953. // Set ownership to this player
  1954. shadow.m_nSplitscreenOwner = GET_ACTIVE_SPLITSCREEN_SLOT();
  1955. }
  1956. }
  1957. }
  1958. // Set up the flags....
  1959. IMaterial* pShadowMaterial = m_SimpleShadow;
  1960. IMaterial* pShadowModelMaterial = m_SimpleShadow;
  1961. void* pShadowProxyData = (void*)CLIENTSHADOW_INVALID_HANDLE;
  1962. if ( m_RenderToTextureActive && (flags & SHADOW_FLAGS_USE_RENDER_TO_TEXTURE) )
  1963. {
  1964. SetupRenderToTextureShadow(h);
  1965. pShadowMaterial = m_RenderShadow;
  1966. pShadowModelMaterial = m_RenderModelShadow;
  1967. pShadowProxyData = (void*)(uintp)h;
  1968. }
  1969. if( ( flags & SHADOW_FLAGS_USE_DEPTH_TEXTURE ) || ( flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) )
  1970. {
  1971. pShadowMaterial = NULL; // these materials aren't used for shadow depth texture shadows.
  1972. pShadowModelMaterial = NULL;
  1973. pShadowProxyData = (void*)(uintp)h;
  1974. }
  1975. int createShadowFlags;
  1976. if( flags & SHADOW_FLAGS_SIMPLE_PROJECTION )
  1977. {
  1978. createShadowFlags = SHADOW_SIMPLE_PROJECTION;
  1979. }
  1980. else if( flags & SHADOW_FLAGS_FLASHLIGHT )
  1981. {
  1982. // don't use SHADOW_CACHE_VERTS with projective lightsources since we expect that they will change every frame.
  1983. // FIXME: might want to make it cache optionally if it's an entity light that is static.
  1984. createShadowFlags = SHADOW_FLASHLIGHT;
  1985. }
  1986. else
  1987. {
  1988. createShadowFlags = SHADOW_CACHE_VERTS;
  1989. }
  1990. if ( -1 == shadow.m_nSplitscreenOwner )
  1991. {
  1992. createShadowFlags |= SHADOW_ANY_SPLITSCREEN_SLOT;
  1993. }
  1994. shadow.m_ShadowHandle = shadowmgr->CreateShadowEx( pShadowMaterial, pShadowModelMaterial, pShadowProxyData, createShadowFlags, nEntIndex );
  1995. shadow.m_bUseSplitScreenBits = pSplitScreenBits ? true : false;
  1996. if ( pSplitScreenBits )
  1997. {
  1998. shadow.m_SplitScreenBits.Copy( *pSplitScreenBits );
  1999. }
  2000. return h;
  2001. }
  2002. ClientShadowHandle_t CClientShadowMgr::CreateFlashlight( const FlashlightState_t &lightState )
  2003. {
  2004. // We don't really need a model entity handle for a projective light source, so use an invalid one.
  2005. static ClientEntityHandle_t invalidHandle = INVALID_CLIENTENTITY_HANDLE;
  2006. int shadowFlags = SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_LIGHT_WORLD;
  2007. if( lightState.m_bEnableShadows && r_flashlightdepthtexture.GetBool() )
  2008. {
  2009. shadowFlags |= SHADOW_FLAGS_USE_DEPTH_TEXTURE;
  2010. }
  2011. ClientShadowHandle_t shadowHandle = CreateProjectedTexture( invalidHandle, -1, shadowFlags, NULL, lightState.m_bShareBetweenSplitscreenPlayers );
  2012. UpdateFlashlightState( shadowHandle, lightState );
  2013. UpdateProjectedTexture( shadowHandle, true );
  2014. return shadowHandle;
  2015. }
  2016. ClientShadowHandle_t CClientShadowMgr::CreateShadow( ClientEntityHandle_t entity, int nEntIndex, int flags, CBitVec< MAX_SPLITSCREEN_PLAYERS > *pSplitScreenBits /*= NULL*/ )
  2017. {
  2018. // We don't really need a model entity handle for a projective light source, so use an invalid one.
  2019. flags &= ~SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK;
  2020. flags |= SHADOW_FLAGS_SHADOW | SHADOW_FLAGS_TEXTURE_DIRTY;
  2021. ClientShadowHandle_t shadowHandle = CreateProjectedTexture( entity, nEntIndex, flags, pSplitScreenBits, false );
  2022. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( entity );
  2023. if ( pRenderable )
  2024. {
  2025. Assert( !pRenderable->IsShadowDirty( ) );
  2026. pRenderable->MarkShadowDirty( true );
  2027. CClientAlphaProperty *pAlphaProperty = static_cast<CClientAlphaProperty*>( pRenderable->GetIClientUnknown()->GetClientAlphaProperty() );
  2028. if ( pAlphaProperty )
  2029. {
  2030. pAlphaProperty->SetShadowHandle( shadowHandle );
  2031. }
  2032. }
  2033. // NOTE: We *have* to call the version that takes a shadow handle
  2034. // even if we have an entity because this entity hasn't set its shadow handle yet
  2035. AddToDirtyShadowList( shadowHandle, true );
  2036. return shadowHandle;
  2037. }
  2038. //-----------------------------------------------------------------------------
  2039. // Updates the flashlight direction and re-computes surfaces it should lie on
  2040. //-----------------------------------------------------------------------------
  2041. void CClientShadowMgr::UpdateFlashlightState( ClientShadowHandle_t shadowHandle, const FlashlightState_t &flashlightState )
  2042. {
  2043. VPROF_BUDGET( "CClientShadowMgr::UpdateFlashlightState", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  2044. if( flashlightState.m_bEnableShadows && r_flashlightdepthtexture.GetBool() )
  2045. {
  2046. m_Shadows[shadowHandle].m_Flags |= SHADOW_FLAGS_USE_DEPTH_TEXTURE;
  2047. }
  2048. else
  2049. {
  2050. m_Shadows[shadowHandle].m_Flags &= ~SHADOW_FLAGS_USE_DEPTH_TEXTURE;
  2051. }
  2052. if ( flashlightState.m_bOrtho )
  2053. {
  2054. BuildOrthoWorldToFlashlightMatrix( m_Shadows[shadowHandle].m_WorldToShadow, flashlightState );
  2055. }
  2056. else
  2057. {
  2058. BuildPerspectiveWorldToFlashlightMatrix( m_Shadows[shadowHandle].m_WorldToShadow, flashlightState );
  2059. }
  2060. shadowmgr->UpdateFlashlightState( m_Shadows[shadowHandle].m_ShadowHandle, flashlightState );
  2061. }
  2062. void CClientShadowMgr::DestroyFlashlight( ClientShadowHandle_t shadowHandle )
  2063. {
  2064. DestroyShadow( shadowHandle );
  2065. }
  2066. ClientShadowHandle_t CClientShadowMgr::CreateProjection( const FlashlightState_t &lightState )
  2067. {
  2068. // return CreateFlashlight(lightState);
  2069. // We don't really need a model entity handle for a projective light source, so use an invalid one.
  2070. static ClientEntityHandle_t invalidHandle = INVALID_CLIENTENTITY_HANDLE;
  2071. int shadowFlags = SHADOW_FLAGS_SIMPLE_PROJECTION;
  2072. ClientShadowHandle_t shadowHandle = CreateProjectedTexture( invalidHandle, -1, shadowFlags, NULL, lightState.m_bShareBetweenSplitscreenPlayers );
  2073. UpdateFlashlightState( shadowHandle, lightState );
  2074. UpdateProjectedTexture( shadowHandle, true );
  2075. return shadowHandle;
  2076. }
  2077. //-----------------------------------------------------------------------------
  2078. // Updates the flashlight direction and re-computes surfaces it should lie on
  2079. //-----------------------------------------------------------------------------
  2080. void CClientShadowMgr::UpdateProjectionState( ClientShadowHandle_t shadowHandle, const FlashlightState_t &flashlightState )
  2081. {
  2082. // UpdateFlashlightState(shadowHandle, flashlightState );
  2083. // return;
  2084. VPROF_BUDGET( "CClientShadowMgr::UpdateProjectionState", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  2085. if ( flashlightState.m_bOrtho )
  2086. {
  2087. BuildOrthoWorldToFlashlightMatrix( m_Shadows[shadowHandle].m_WorldToShadow, flashlightState );
  2088. }
  2089. else
  2090. {
  2091. BuildPerspectiveWorldToFlashlightMatrix( m_Shadows[shadowHandle].m_WorldToShadow, flashlightState );
  2092. }
  2093. shadowmgr->UpdateFlashlightState( m_Shadows[shadowHandle].m_ShadowHandle, flashlightState );
  2094. }
  2095. void CClientShadowMgr::DestroyProjection( ClientShadowHandle_t shadowHandle )
  2096. {
  2097. DestroyShadow( shadowHandle );
  2098. }
  2099. //-----------------------------------------------------------------------------
  2100. // Remove a shadow from the dirty list
  2101. //-----------------------------------------------------------------------------
  2102. void CClientShadowMgr::RemoveShadowFromDirtyList( ClientShadowHandle_t handle )
  2103. {
  2104. int idx = m_DirtyShadows.Find( handle );
  2105. if ( idx != m_DirtyShadows.InvalidIndex() )
  2106. {
  2107. // Clean up the shadow update bit.
  2108. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( m_Shadows[handle].m_Entity );
  2109. if ( pRenderable )
  2110. {
  2111. pRenderable->MarkShadowDirty( false );
  2112. }
  2113. m_DirtyShadows.RemoveAt( idx );
  2114. }
  2115. idx = m_DirtyShadowsLeftOver.Find( handle );
  2116. if ( idx != m_DirtyShadowsLeftOver.InvalidIndex() )
  2117. {
  2118. // Clean up the shadow update bit.
  2119. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( m_Shadows[handle].m_Entity );
  2120. if ( pRenderable )
  2121. {
  2122. pRenderable->MarkShadowDirty( false );
  2123. }
  2124. m_DirtyShadowsLeftOver.RemoveAt( idx );
  2125. }
  2126. }
  2127. //-----------------------------------------------------------------------------
  2128. // Remove a shadow
  2129. //-----------------------------------------------------------------------------
  2130. void CClientShadowMgr::DestroyShadow( ClientShadowHandle_t handle )
  2131. {
  2132. if ( m_bUpdatingDirtyShadows )
  2133. {
  2134. // While we're updating dirty shadows, destroying a shadow can cause an RB-Tree we're currently iterating to be changed.
  2135. // This can cause tree corruption resulting in infinite loops or crashes. Instead, we queue the shadow handle for deletion and
  2136. // service the queue after we're done updating.
  2137. QueueShadowForDestruction( handle );
  2138. return;
  2139. }
  2140. Assert( m_Shadows.IsValidIndex(handle) );
  2141. RemoveShadowFromDirtyList( handle );
  2142. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( m_Shadows[handle].m_Entity );
  2143. if ( pRenderable )
  2144. {
  2145. CClientAlphaProperty *pAlphaProperty = static_cast<CClientAlphaProperty*>( pRenderable->GetIClientUnknown()->GetClientAlphaProperty() );
  2146. if ( pAlphaProperty )
  2147. {
  2148. pAlphaProperty->SetShadowHandle( CLIENTSHADOW_INVALID_HANDLE );
  2149. }
  2150. }
  2151. shadowmgr->DestroyShadow( m_Shadows[handle].m_ShadowHandle );
  2152. if ( m_Shadows[handle].m_ClientLeafShadowHandle != CLIENT_LEAF_SHADOW_INVALID_HANDLE )
  2153. {
  2154. ClientLeafSystem()->RemoveShadow( m_Shadows[handle].m_ClientLeafShadowHandle );
  2155. }
  2156. CleanUpRenderToTextureShadow( handle );
  2157. m_Shadows.Remove(handle);
  2158. }
  2159. //-----------------------------------------------------------------------------
  2160. // Queues a shadow for removal
  2161. //-----------------------------------------------------------------------------
  2162. void CClientShadowMgr::QueueShadowForDestruction( ClientShadowHandle_t handle )
  2163. {
  2164. // this function should be called infrequently (it is a failsafe)
  2165. // so check to make sure it's not queued to delete twice
  2166. if ( m_shadowsToDestroy.IsValidIndex( m_shadowsToDestroy.Find(handle) ) )
  2167. {
  2168. AssertMsg1( false, "Tried to queue shadow %d for deletion twice!\n", (int)(handle) );
  2169. }
  2170. else
  2171. {
  2172. m_shadowsToDestroy.AddToTail( handle );
  2173. }
  2174. }
  2175. //-----------------------------------------------------------------------------
  2176. // Removes queued shadows
  2177. //-----------------------------------------------------------------------------
  2178. void CClientShadowMgr::DestroyQueuedShadows()
  2179. {
  2180. Assert( !m_bUpdatingDirtyShadows );
  2181. for ( int i = 0; i < m_shadowsToDestroy.Count(); i++ )
  2182. {
  2183. DestroyShadow( m_shadowsToDestroy[i] );
  2184. }
  2185. m_shadowsToDestroy.RemoveAll();
  2186. }
  2187. //-----------------------------------------------------------------------------
  2188. // Build the worldtotexture matrix
  2189. //-----------------------------------------------------------------------------
  2190. void CClientShadowMgr::BuildGeneralWorldToShadowMatrix( VMatrix& matWorldToShadow,
  2191. const Vector& origin, const Vector& dir, const Vector& xvec, const Vector& yvec )
  2192. {
  2193. // We're assuming here that xvec + yvec aren't necessary perpendicular
  2194. // The shadow->world matrix is pretty simple:
  2195. // Just stick the origin in the translation component
  2196. // and the vectors in the columns...
  2197. matWorldToShadow.SetBasisVectors( xvec, yvec, dir );
  2198. matWorldToShadow.SetTranslation( origin );
  2199. matWorldToShadow[3][0] = matWorldToShadow[3][1] = matWorldToShadow[3][2] = 0.0f;
  2200. matWorldToShadow[3][3] = 1.0f;
  2201. // Now do a general inverse to get matWorldToShadow
  2202. MatrixInverseGeneral( matWorldToShadow, matWorldToShadow );
  2203. }
  2204. void CClientShadowMgr::BuildWorldToShadowMatrix( VMatrix& matWorldToShadow, const Vector& origin, const Quaternion& quatOrientation )
  2205. {
  2206. // The shadow->world matrix is pretty simple:
  2207. // Just stick the origin in the translation component
  2208. // and the vectors in the columns...
  2209. // The inverse of this transposes the rotational component
  2210. // and the translational component = - (rotation transpose) * origin
  2211. matrix3x4_t matOrientation;
  2212. QuaternionMatrix( quatOrientation, matOrientation ); // Convert quat to matrix3x4
  2213. PositionMatrix( vec3_origin, matOrientation ); // Zero out translation elements
  2214. VMatrix matBasis( matOrientation ); // Convert matrix3x4 to VMatrix
  2215. Vector vForward, vLeft, vUp;
  2216. matBasis.GetBasisVectors( vForward, vLeft, vUp );
  2217. matBasis.SetForward( vLeft ); // Bizarre vector flip inherited from earlier code, WTF?
  2218. matBasis.SetLeft( vUp );
  2219. matBasis.SetUp( vForward );
  2220. matWorldToShadow = matBasis.Transpose(); // Transpose
  2221. Vector translation;
  2222. Vector3DMultiply( matWorldToShadow, origin, translation );
  2223. translation *= -1.0f;
  2224. matWorldToShadow.SetTranslation( translation );
  2225. // The the bottom row.
  2226. matWorldToShadow[3][0] = matWorldToShadow[3][1] = matWorldToShadow[3][2] = 0.0f;
  2227. matWorldToShadow[3][3] = 1.0f;
  2228. }
  2229. void CClientShadowMgr::BuildPerspectiveWorldToFlashlightMatrix( VMatrix& matWorldToShadow, const FlashlightState_t &flashlightState )
  2230. {
  2231. VPROF_BUDGET( "CClientShadowMgr::BuildPerspectiveWorldToFlashlightMatrix", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  2232. // Buildworld to shadow matrix, then perspective projection and concatenate
  2233. VMatrix matWorldToShadowView, matPerspective;
  2234. BuildWorldToShadowMatrix( matWorldToShadowView, flashlightState.m_vecLightOrigin,
  2235. flashlightState.m_quatOrientation );
  2236. MatrixBuildPerspective( matPerspective, flashlightState.m_fHorizontalFOVDegrees,
  2237. flashlightState.m_fVerticalFOVDegrees,
  2238. flashlightState.m_NearZ, flashlightState.m_FarZ );
  2239. MatrixMultiply( matPerspective, matWorldToShadowView, matWorldToShadow );
  2240. }
  2241. void CClientShadowMgr::BuildOrthoWorldToFlashlightMatrix( VMatrix& matWorldToShadow, const FlashlightState_t &flashlightState )
  2242. {
  2243. VPROF_BUDGET( "CClientShadowMgr::BuildPerspectiveWorldToFlashlightMatrix", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  2244. // Buildworld to shadow matrix, then perspective projection and concatenate
  2245. VMatrix matWorldToShadowView, matPerspective;
  2246. BuildWorldToShadowMatrix( matWorldToShadowView, flashlightState.m_vecLightOrigin,
  2247. flashlightState.m_quatOrientation );
  2248. MatrixBuildOrtho( matPerspective,
  2249. flashlightState.m_fOrthoLeft, flashlightState.m_fOrthoTop, flashlightState.m_fOrthoRight, flashlightState.m_fOrthoBottom,
  2250. flashlightState.m_NearZ, flashlightState.m_FarZ );
  2251. // Shift it z/y to 0 to -2 space
  2252. VMatrix addW;
  2253. addW.Identity();
  2254. addW[0][3] = -1.0f;
  2255. addW[1][3] = -1.0f;
  2256. addW[2][3] = 0.0f;
  2257. MatrixMultiply( addW, matPerspective, matPerspective );
  2258. // Flip x/y to positive 0 to 1... flip z to negative
  2259. VMatrix scaleHalf;
  2260. scaleHalf.Identity();
  2261. scaleHalf[0][0] = -0.5f;
  2262. scaleHalf[1][1] = -0.5f;
  2263. scaleHalf[2][2] = -1.0f;
  2264. MatrixMultiply( scaleHalf, matPerspective, matPerspective );
  2265. MatrixMultiply( matPerspective, matWorldToShadowView, matWorldToShadow );
  2266. }
  2267. //-----------------------------------------------------------------------------
  2268. // Compute the shadow origin and attenuation start distance
  2269. //-----------------------------------------------------------------------------
  2270. float CClientShadowMgr::ComputeLocalShadowOrigin( IClientRenderable* pRenderable,
  2271. const Vector& mins, const Vector& maxs, const Vector& localShadowDir, float backupFactor, Vector& origin )
  2272. {
  2273. // Compute the centroid of the object...
  2274. Vector vecCentroid;
  2275. VectorAdd( mins, maxs, vecCentroid );
  2276. vecCentroid *= 0.5f;
  2277. Vector vecSize;
  2278. VectorSubtract( maxs, mins, vecSize );
  2279. float flRadius = vecSize.Length() * 0.5f;
  2280. // NOTE: The *origin* of the shadow cast is a point on a line passing through
  2281. // the centroid of the caster. The direction of this line is the shadow cast direction,
  2282. // and the point on that line corresponds to the endpoint of the box that is
  2283. // furthest *back* along the shadow direction
  2284. // For the first point at which the shadow could possibly start falling off,
  2285. // we need to use the point at which the ray described above leaves the
  2286. // bounding sphere surrounding the entity. This is necessary because otherwise,
  2287. // tall, thin objects would have their shadows appear + disappear as then spun about their origin
  2288. // Figure out the corner corresponding to the min + max projection
  2289. // along the shadow direction
  2290. // We're basically finding the point on the cube that has the largest and smallest
  2291. // dot product with the local shadow dir. Then we're taking the dot product
  2292. // of that with the localShadowDir. lastly, we're subtracting out the
  2293. // centroid projection to give us a distance along the localShadowDir to
  2294. // the front and back of the cube along the direction of the ray.
  2295. float centroidProjection = DotProduct( vecCentroid, localShadowDir );
  2296. float minDist = -centroidProjection;
  2297. for (int i = 0; i < 3; ++i)
  2298. {
  2299. if ( localShadowDir[i] > 0.0f )
  2300. {
  2301. minDist += localShadowDir[i] * mins[i];
  2302. }
  2303. else
  2304. {
  2305. minDist += localShadowDir[i] * maxs[i];
  2306. }
  2307. }
  2308. minDist *= backupFactor;
  2309. VectorMA( vecCentroid, minDist, localShadowDir, origin );
  2310. return flRadius - minDist;
  2311. }
  2312. //-----------------------------------------------------------------------------
  2313. // Sorts the components of a vector
  2314. //-----------------------------------------------------------------------------
  2315. static inline void SortAbsVectorComponents( const Vector& src, int* pVecIdx )
  2316. {
  2317. Vector absVec( fabs(src[0]), fabs(src[1]), fabs(src[2]) );
  2318. int maxIdx = (absVec[0] > absVec[1]) ? 0 : 1;
  2319. if (absVec[2] > absVec[maxIdx])
  2320. {
  2321. maxIdx = 2;
  2322. }
  2323. // always choose something right-handed....
  2324. switch( maxIdx )
  2325. {
  2326. case 0:
  2327. pVecIdx[0] = 1;
  2328. pVecIdx[1] = 2;
  2329. pVecIdx[2] = 0;
  2330. break;
  2331. case 1:
  2332. pVecIdx[0] = 2;
  2333. pVecIdx[1] = 0;
  2334. pVecIdx[2] = 1;
  2335. break;
  2336. case 2:
  2337. pVecIdx[0] = 0;
  2338. pVecIdx[1] = 1;
  2339. pVecIdx[2] = 2;
  2340. break;
  2341. }
  2342. }
  2343. //-----------------------------------------------------------------------------
  2344. // Build the worldtotexture matrix
  2345. //-----------------------------------------------------------------------------
  2346. static void BuildWorldToTextureMatrix( const VMatrix& matWorldToShadow,
  2347. const Vector2D& size, VMatrix& matWorldToTexture )
  2348. {
  2349. // Build a matrix that maps from shadow space to (u,v) coordinates
  2350. VMatrix shadowToUnit;
  2351. MatrixBuildScale( shadowToUnit, 1.0f / size.x, 1.0f / size.y, 1.0f );
  2352. shadowToUnit[0][3] = shadowToUnit[1][3] = 0.5f;
  2353. // Store off the world to (u,v) transformation
  2354. MatrixMultiply( shadowToUnit, matWorldToShadow, matWorldToTexture );
  2355. }
  2356. static void BuildOrthoWorldToShadowMatrix( VMatrix& worldToShadow,
  2357. const Vector& origin, const Vector& dir, const Vector& xvec, const Vector& yvec )
  2358. {
  2359. // This version is faster and assumes dir, xvec, yvec are perpendicular
  2360. AssertFloatEquals( DotProduct( dir, xvec ), 0.0f, 1e-3 );
  2361. AssertFloatEquals( DotProduct( dir, yvec ), 0.0f, 1e-3 );
  2362. AssertFloatEquals( DotProduct( xvec, yvec ), 0.0f, 1e-3 );
  2363. // The shadow->world matrix is pretty simple:
  2364. // Just stick the origin in the translation component
  2365. // and the vectors in the columns...
  2366. // The inverse of this transposes the rotational component
  2367. // and the translational component = - (rotation transpose) * origin
  2368. worldToShadow.SetBasisVectors( xvec, yvec, dir );
  2369. MatrixTranspose( worldToShadow, worldToShadow );
  2370. Vector translation;
  2371. Vector3DMultiply( worldToShadow, origin, translation );
  2372. translation *= -1.0f;
  2373. worldToShadow.SetTranslation( translation );
  2374. // The the bottom row.
  2375. worldToShadow[3][0] = worldToShadow[3][1] = worldToShadow[3][2] = 0.0f;
  2376. worldToShadow[3][3] = 1.0f;
  2377. }
  2378. //-----------------------------------------------------------------------------
  2379. // Set extra clip planes related to shadows...
  2380. //-----------------------------------------------------------------------------
  2381. void CClientShadowMgr::ClearExtraClipPlanes( ClientShadowHandle_t h )
  2382. {
  2383. if ( !r_shadow_deferred.GetBool() )
  2384. shadowmgr->ClearExtraClipPlanes( m_Shadows[h].m_ShadowHandle );
  2385. }
  2386. void CClientShadowMgr::AddExtraClipPlane( ClientShadowHandle_t h, const Vector& normal, float dist )
  2387. {
  2388. if ( !r_shadow_deferred.GetBool() )
  2389. shadowmgr->AddExtraClipPlane( m_Shadows[h].m_ShadowHandle, normal, dist );
  2390. }
  2391. //-----------------------------------------------------------------------------
  2392. // Compute the extra shadow planes
  2393. //-----------------------------------------------------------------------------
  2394. void CClientShadowMgr::ComputeExtraClipPlanes( IClientRenderable* pRenderable,
  2395. ClientShadowHandle_t handle, const Vector* vec,
  2396. const Vector& mins, const Vector& maxs, const Vector& localShadowDir )
  2397. {
  2398. // Compute the world-space position of the corner of the bounding box
  2399. // that's got the highest dotproduct with the local shadow dir...
  2400. Vector origin = pRenderable->GetRenderOrigin( );
  2401. float dir[3];
  2402. int i;
  2403. for ( i = 0; i < 3; ++i )
  2404. {
  2405. if (localShadowDir[i] < 0.0f)
  2406. {
  2407. VectorMA( origin, maxs[i], vec[i], origin );
  2408. dir[i] = 1;
  2409. }
  2410. else
  2411. {
  2412. VectorMA( origin, mins[i], vec[i], origin );
  2413. dir[i] = -1;
  2414. }
  2415. }
  2416. // Now that we have it, create 3 planes...
  2417. Vector normal;
  2418. ClearExtraClipPlanes(handle);
  2419. for ( i = 0; i < 3; ++i )
  2420. {
  2421. VectorMultiply( vec[i], dir[i], normal );
  2422. float dist = DotProduct( normal, origin );
  2423. AddExtraClipPlane( handle, normal, dist );
  2424. }
  2425. ClientShadow_t& shadow = m_Shadows[handle];
  2426. C_BaseEntity *pEntity = ClientEntityList().GetBaseEntityFromHandle( shadow.m_Entity );
  2427. if ( pEntity && pEntity->m_bEnableRenderingClipPlane )
  2428. {
  2429. normal[ 0 ] = -pEntity->m_fRenderingClipPlane[ 0 ];
  2430. normal[ 1 ] = -pEntity->m_fRenderingClipPlane[ 1 ];
  2431. normal[ 2 ] = -pEntity->m_fRenderingClipPlane[ 2 ];
  2432. AddExtraClipPlane( handle, normal, -pEntity->m_fRenderingClipPlane[ 3 ] - 0.5f );
  2433. }
  2434. }
  2435. inline ShadowType_t CClientShadowMgr::GetActualShadowCastType( ClientShadowHandle_t handle ) const
  2436. {
  2437. if ( handle == CLIENTSHADOW_INVALID_HANDLE )
  2438. {
  2439. return SHADOWS_NONE;
  2440. }
  2441. if ( m_Shadows[handle].m_Flags & SHADOW_FLAGS_USE_RENDER_TO_TEXTURE )
  2442. {
  2443. return ( m_RenderToTextureActive ? SHADOWS_RENDER_TO_TEXTURE : SHADOWS_SIMPLE );
  2444. }
  2445. else if( m_Shadows[handle].m_Flags & SHADOW_FLAGS_USE_DEPTH_TEXTURE )
  2446. {
  2447. return SHADOWS_RENDER_TO_DEPTH_TEXTURE;
  2448. }
  2449. else
  2450. {
  2451. return SHADOWS_SIMPLE;
  2452. }
  2453. }
  2454. inline ShadowType_t CClientShadowMgr::GetActualShadowCastType( IClientRenderable *pEnt ) const
  2455. {
  2456. return GetActualShadowCastType( pEnt->GetShadowHandle() );
  2457. }
  2458. //-----------------------------------------------------------------------------
  2459. // Adds a shadow to all leaves along a ray
  2460. //-----------------------------------------------------------------------------
  2461. class CShadowLeafEnum : public ISpatialLeafEnumerator
  2462. {
  2463. public:
  2464. bool EnumerateLeaf( int leaf, intp context )
  2465. {
  2466. m_LeafList.AddToTail( leaf );
  2467. return true;
  2468. }
  2469. void ExtractUnconnectedLeaves( const Vector &vecOrigin )
  2470. {
  2471. VPROF_BUDGET( "ExtractUnconnectedLeaves", "ExtractUnconnectedLeaves" );
  2472. int nCount = m_LeafList.Count();
  2473. bool *pIsConnected = (bool*)stackalloc( nCount * sizeof(bool) );
  2474. engine->ComputeLeavesConnected( vecOrigin, nCount, m_LeafList.Base(), pIsConnected );
  2475. int nCountRemoved = 0;
  2476. for ( int i = nCount; --i >= 0; )
  2477. {
  2478. if ( !pIsConnected[i] )
  2479. {
  2480. ++nCountRemoved;
  2481. m_LeafList.FastRemove( i );
  2482. }
  2483. }
  2484. }
  2485. CUtlVectorFixedGrowable< int, 512 > m_LeafList;
  2486. };
  2487. //-----------------------------------------------------------------------------
  2488. // Builds a list of leaves inside the shadow volume
  2489. //-----------------------------------------------------------------------------
  2490. static void BuildShadowLeafList( CShadowLeafEnum *pEnum, const Vector& origin,
  2491. const Vector& dir, const Vector2D& size, float maxDist )
  2492. {
  2493. Ray_t ray;
  2494. VectorCopy( origin, ray.m_Start );
  2495. VectorMultiply( dir, maxDist, ray.m_Delta );
  2496. ray.m_StartOffset.Init( 0, 0, 0 );
  2497. float flRadius = sqrt( size.x * size.x + size.y * size.y ) * 0.5f;
  2498. ray.m_Extents.Init( flRadius, flRadius, flRadius );
  2499. ray.m_IsRay = false;
  2500. ray.m_IsSwept = true;
  2501. ISpatialQuery* pQuery = engine->GetBSPTreeQuery();
  2502. pQuery->EnumerateLeavesAlongRay( ray, pEnum, 0 );
  2503. }
  2504. //-----------------------------------------------------------------------------
  2505. // Builds a simple blobby shadow
  2506. //-----------------------------------------------------------------------------
  2507. void CClientShadowMgr::BuildOrthoShadow( IClientRenderable* pRenderable,
  2508. ClientShadowHandle_t handle, const Vector& mins, const Vector& maxs)
  2509. {
  2510. // Get the object's basis
  2511. Vector vec[3];
  2512. AngleVectors( pRenderable->GetRenderAngles(), &vec[0], &vec[1], &vec[2] );
  2513. vec[1] *= -1.0f;
  2514. Vector vecShadowDir = GetShadowDirection( handle );
  2515. // Project the shadow casting direction into the space of the object
  2516. Vector localShadowDir;
  2517. localShadowDir[0] = DotProduct( vec[0], vecShadowDir );
  2518. localShadowDir[1] = DotProduct( vec[1], vecShadowDir );
  2519. localShadowDir[2] = DotProduct( vec[2], vecShadowDir );
  2520. // Figure out which vector has the largest component perpendicular
  2521. // to the shadow handle...
  2522. // Sort by how perpendicular it is
  2523. int vecIdx[3];
  2524. SortAbsVectorComponents( localShadowDir, vecIdx );
  2525. // Here's our shadow basis vectors; namely the ones that are
  2526. // most perpendicular to the shadow casting direction
  2527. Vector xvec = vec[vecIdx[0]];
  2528. Vector yvec = vec[vecIdx[1]];
  2529. // Project them into a plane perpendicular to the shadow direction
  2530. xvec -= vecShadowDir * DotProduct( vecShadowDir, xvec );
  2531. yvec -= vecShadowDir * DotProduct( vecShadowDir, yvec );
  2532. VectorNormalize( xvec );
  2533. VectorNormalize( yvec );
  2534. // Compute the box size
  2535. Vector boxSize;
  2536. VectorSubtract( maxs, mins, boxSize );
  2537. // We project the two longest sides into the vectors perpendicular
  2538. // to the projection direction, then add in the projection of the perp direction
  2539. Vector2D size( boxSize[vecIdx[0]], boxSize[vecIdx[1]] );
  2540. size.x *= fabs( DotProduct( vec[vecIdx[0]], xvec ) );
  2541. size.y *= fabs( DotProduct( vec[vecIdx[1]], yvec ) );
  2542. // Add the third component into x and y
  2543. size.x += boxSize[vecIdx[2]] * fabs( DotProduct( vec[vecIdx[2]], xvec ) );
  2544. size.y += boxSize[vecIdx[2]] * fabs( DotProduct( vec[vecIdx[2]], yvec ) );
  2545. // Bloat a bit, since the shadow wants to extend outside the model a bit
  2546. size.x += 10.0f;
  2547. size.y += 10.0f;
  2548. // Clamp the minimum size
  2549. Vector2DMax( size, Vector2D(10.0f, 10.0f), size );
  2550. // Place the origin at the point with min dot product with shadow dir
  2551. Vector org;
  2552. float falloffStart = ComputeLocalShadowOrigin( pRenderable, mins, maxs, localShadowDir, 2.0f, org );
  2553. // Transform the local origin into world coordinates
  2554. Vector worldOrigin = pRenderable->GetRenderOrigin( );
  2555. VectorMA( worldOrigin, org.x, vec[0], worldOrigin );
  2556. VectorMA( worldOrigin, org.y, vec[1], worldOrigin );
  2557. VectorMA( worldOrigin, org.z, vec[2], worldOrigin );
  2558. // FUNKY: A trick to reduce annoying texelization artifacts!?
  2559. float dx = 1.0f / TEXEL_SIZE_PER_CASTER_SIZE;
  2560. worldOrigin.x = (int)(worldOrigin.x / dx) * dx;
  2561. worldOrigin.y = (int)(worldOrigin.y / dx) * dx;
  2562. worldOrigin.z = (int)(worldOrigin.z / dx) * dx;
  2563. // NOTE: We gotta use the general matrix because xvec and yvec aren't perp
  2564. VMatrix matWorldToShadow, matWorldToTexture;
  2565. // negate xvec so that the matrix will have the same handedness as for an RTT shadow
  2566. BuildGeneralWorldToShadowMatrix( m_Shadows[handle].m_WorldToShadow, worldOrigin, vecShadowDir, -xvec, yvec );
  2567. BuildWorldToTextureMatrix( m_Shadows[handle].m_WorldToShadow, size, matWorldToTexture );
  2568. Vector2DCopy( size, m_Shadows[handle].m_WorldSize );
  2569. MatrixCopy( matWorldToTexture, m_Shadows[handle].m_WorldToTexture );
  2570. // Compute the falloff attenuation
  2571. // Area computation isn't exact since xvec is not perp to yvec, but close enough
  2572. // float shadowArea = size.x * size.y;
  2573. // The entity may be overriding our shadow cast distance
  2574. float flShadowCastDistance = GetShadowDistance( pRenderable );
  2575. float maxHeight = flShadowCastDistance + falloffStart; //3.0f * sqrt( shadowArea );
  2576. CShadowLeafEnum leafList;
  2577. BuildShadowLeafList( &leafList, worldOrigin, vecShadowDir, size, maxHeight );
  2578. int nCount = leafList.m_LeafList.Count();
  2579. const int *pLeafList = leafList.m_LeafList.Base();
  2580. if ( !r_shadow_deferred.GetBool() )
  2581. {
  2582. shadowmgr->ProjectShadow( m_Shadows[handle].m_ShadowHandle, worldOrigin,
  2583. vecShadowDir, matWorldToTexture, size, nCount, pLeafList, maxHeight, falloffStart, MAX_FALLOFF_AMOUNT, pRenderable->GetRenderOrigin() );
  2584. }
  2585. m_Shadows[handle].m_MaxDist = maxHeight;
  2586. m_Shadows[handle].m_FalloffStart = falloffStart;
  2587. // Compute extra clip planes to prevent poke-thru
  2588. // FIXME!!!!!!!!!!!!!! Removing this for now since it seems to mess up the blobby shadows.
  2589. // ComputeExtraClipPlanes( pEnt, handle, vec, mins, maxs, localShadowDir );
  2590. // Add the shadow to the client leaf system so it correctly marks
  2591. // leafs as being affected by a particular shadow
  2592. ClientLeafSystem()->ProjectShadow( m_Shadows[handle].m_ClientLeafShadowHandle, nCount, pLeafList );
  2593. }
  2594. //-----------------------------------------------------------------------------
  2595. // Visualization....
  2596. //-----------------------------------------------------------------------------
  2597. void CClientShadowMgr::DrawRenderToTextureDebugInfo( IClientRenderable* pRenderable, const Vector& mins, const Vector& maxs )
  2598. {
  2599. // Get the object's basis
  2600. Vector vec[3];
  2601. AngleVectors( pRenderable->GetRenderAngles(), &vec[0], &vec[1], &vec[2] );
  2602. vec[1] *= -1.0f;
  2603. Vector vecSize;
  2604. VectorSubtract( maxs, mins, vecSize );
  2605. Vector vecOrigin = pRenderable->GetRenderOrigin();
  2606. Vector start, end, end2;
  2607. VectorMA( vecOrigin, mins.x, vec[0], start );
  2608. VectorMA( start, mins.y, vec[1], start );
  2609. VectorMA( start, mins.z, vec[2], start );
  2610. VectorMA( start, vecSize.x, vec[0], end );
  2611. VectorMA( end, vecSize.z, vec[2], end2 );
  2612. debugoverlay->AddLineOverlay( start, end, 255, 0, 0, true, 0.01 );
  2613. debugoverlay->AddLineOverlay( end2, end, 255, 0, 0, true, 0.01 );
  2614. VectorMA( start, vecSize.y, vec[1], end );
  2615. VectorMA( end, vecSize.z, vec[2], end2 );
  2616. debugoverlay->AddLineOverlay( start, end, 255, 0, 0, true, 0.01 );
  2617. debugoverlay->AddLineOverlay( end2, end, 255, 0, 0, true, 0.01 );
  2618. VectorMA( start, vecSize.z, vec[2], end );
  2619. debugoverlay->AddLineOverlay( start, end, 255, 0, 0, true, 0.01 );
  2620. start = end;
  2621. VectorMA( start, vecSize.x, vec[0], end );
  2622. debugoverlay->AddLineOverlay( start, end, 255, 0, 0, true, 0.01 );
  2623. VectorMA( start, vecSize.y, vec[1], end );
  2624. debugoverlay->AddLineOverlay( start, end, 255, 0, 0, true, 0.01 );
  2625. VectorMA( end, vecSize.x, vec[0], start );
  2626. VectorMA( start, -vecSize.x, vec[0], end );
  2627. debugoverlay->AddLineOverlay( start, end, 255, 0, 0, true, 0.01 );
  2628. VectorMA( start, -vecSize.y, vec[1], end );
  2629. debugoverlay->AddLineOverlay( start, end, 255, 0, 0, true, 0.01 );
  2630. VectorMA( start, -vecSize.z, vec[2], end );
  2631. debugoverlay->AddLineOverlay( start, end, 255, 0, 0, true, 0.01 );
  2632. start = end;
  2633. VectorMA( start, -vecSize.x, vec[0], end );
  2634. debugoverlay->AddLineOverlay( start, end, 255, 0, 0, true, 0.01 );
  2635. VectorMA( start, -vecSize.y, vec[1], end );
  2636. debugoverlay->AddLineOverlay( start, end, 255, 0, 0, true, 0.01 );
  2637. C_BaseEntity *pEnt = pRenderable->GetIClientUnknown()->GetBaseEntity();
  2638. if ( pEnt )
  2639. {
  2640. debugoverlay->AddTextOverlay( vecOrigin, 0, "%d", pEnt->entindex() );
  2641. }
  2642. else
  2643. {
  2644. debugoverlay->AddTextOverlay( vecOrigin, 0, "%X", (size_t)pRenderable );
  2645. }
  2646. }
  2647. extern ConVar cl_drawshadowtexture;
  2648. extern ConVar cl_shadowtextureoverlaysize;
  2649. //-----------------------------------------------------------------------------
  2650. // Builds a more complex shadow...
  2651. //-----------------------------------------------------------------------------
  2652. void CClientShadowMgr::BuildRenderToTextureShadow( IClientRenderable* pRenderable,
  2653. ClientShadowHandle_t handle, const Vector& mins, const Vector& maxs)
  2654. {
  2655. if ( cl_drawshadowtexture.GetInt() )
  2656. {
  2657. // Red wireframe bounding box around objects whose RTT shadows are being updated that frame
  2658. DrawRenderToTextureDebugInfo( pRenderable, mins, maxs );
  2659. }
  2660. // Get the object's basis
  2661. Vector vec[3];
  2662. AngleVectors( pRenderable->GetRenderAngles(), &vec[0], &vec[1], &vec[2] );
  2663. vec[1] *= -1.0f;
  2664. Vector vecShadowDir = GetShadowDirection( handle );
  2665. // Debugging aid
  2666. // const model_t *pModel = pRenderable->GetModel();
  2667. // const char *pDebugName = modelinfo->GetModelName( pModel );
  2668. // Project the shadow casting direction into the space of the object
  2669. Vector localShadowDir;
  2670. localShadowDir[0] = DotProduct( vec[0], vecShadowDir );
  2671. localShadowDir[1] = DotProduct( vec[1], vecShadowDir );
  2672. localShadowDir[2] = DotProduct( vec[2], vecShadowDir );
  2673. // Compute the box size
  2674. Vector boxSize;
  2675. VectorSubtract( maxs, mins, boxSize );
  2676. Vector yvec;
  2677. float fProjMax = 0.0f;
  2678. for( int i = 0; i != 3; ++i )
  2679. {
  2680. Vector test = vec[i] - ( vecShadowDir * DotProduct( vecShadowDir, vec[i] ) );
  2681. test *= boxSize[i]; //doing after the projection to simplify projection math
  2682. float fLengthSqr = test.LengthSqr();
  2683. if( fLengthSqr > fProjMax )
  2684. {
  2685. fProjMax = fLengthSqr;
  2686. yvec = test;
  2687. }
  2688. }
  2689. VectorNormalize( yvec );
  2690. // Compute the x vector
  2691. Vector xvec;
  2692. CrossProduct( yvec, vecShadowDir, xvec );
  2693. // We project the two longest sides into the vectors perpendicular
  2694. // to the projection direction, then add in the projection of the perp direction
  2695. Vector2D size;
  2696. size.x = boxSize.x * fabs( DotProduct( vec[0], xvec ) ) +
  2697. boxSize.y * fabs( DotProduct( vec[1], xvec ) ) +
  2698. boxSize.z * fabs( DotProduct( vec[2], xvec ) );
  2699. size.y = boxSize.x * fabs( DotProduct( vec[0], yvec ) ) +
  2700. boxSize.y * fabs( DotProduct( vec[1], yvec ) ) +
  2701. boxSize.z * fabs( DotProduct( vec[2], yvec ) );
  2702. size.x += 2.0f * TEXEL_SIZE_PER_CASTER_SIZE;
  2703. size.y += 2.0f * TEXEL_SIZE_PER_CASTER_SIZE;
  2704. // Place the origin at the point with min dot product with shadow dir
  2705. Vector org;
  2706. float falloffStart = ComputeLocalShadowOrigin( pRenderable, mins, maxs, localShadowDir, 1.0f, org );
  2707. // Transform the local origin into world coordinates
  2708. Vector worldOrigin = pRenderable->GetRenderOrigin( );
  2709. VectorMA( worldOrigin, org.x, vec[0], worldOrigin );
  2710. VectorMA( worldOrigin, org.y, vec[1], worldOrigin );
  2711. VectorMA( worldOrigin, org.z, vec[2], worldOrigin );
  2712. VMatrix matWorldToTexture;
  2713. BuildOrthoWorldToShadowMatrix( m_Shadows[handle].m_WorldToShadow, worldOrigin, vecShadowDir, xvec, yvec );
  2714. BuildWorldToTextureMatrix( m_Shadows[handle].m_WorldToShadow, size, matWorldToTexture );
  2715. Vector2DCopy( size, m_Shadows[handle].m_WorldSize );
  2716. MatrixCopy( matWorldToTexture, m_Shadows[handle].m_WorldToTexture );
  2717. // Compute the falloff attenuation
  2718. // Area computation isn't exact since xvec is not perp to yvec, but close enough
  2719. // Extra factor of 4 in the maxHeight due to the size being half as big
  2720. // float shadowArea = size.x * size.y;
  2721. // The entity may be overriding our shadow cast distance
  2722. float flShadowCastDistance = GetShadowDistance( pRenderable );
  2723. float maxHeight = flShadowCastDistance + falloffStart; //3.0f * sqrt( shadowArea );
  2724. CShadowLeafEnum leafList;
  2725. BuildShadowLeafList( &leafList, worldOrigin, vecShadowDir, size, maxHeight );
  2726. int nCount = leafList.m_LeafList.Count();
  2727. const int *pLeafList = leafList.m_LeafList.Base();
  2728. if ( !r_shadow_deferred.GetBool() )
  2729. {
  2730. shadowmgr->ProjectShadow( m_Shadows[handle].m_ShadowHandle, worldOrigin,
  2731. vecShadowDir, matWorldToTexture, size, nCount, pLeafList, maxHeight, falloffStart, MAX_FALLOFF_AMOUNT, pRenderable->GetRenderOrigin() );
  2732. // Compute extra clip planes to prevent poke-thru
  2733. ComputeExtraClipPlanes( pRenderable, handle, vec, mins, maxs, localShadowDir );
  2734. }
  2735. m_Shadows[handle].m_MaxDist = maxHeight;
  2736. m_Shadows[handle].m_FalloffStart = falloffStart;
  2737. // Add the shadow to the client leaf system so it correctly marks
  2738. // leafs as being affected by a particular shadow
  2739. ClientLeafSystem()->ProjectShadow( m_Shadows[handle].m_ClientLeafShadowHandle, nCount, pLeafList );
  2740. }
  2741. static void LineDrawHelperProjective( const Vector &startShadowSpace, const Vector &endShadowSpace,
  2742. const VMatrix &shadowToWorld, unsigned char r = 255, unsigned char g = 255, unsigned char b = 255 )
  2743. {
  2744. Vector startWorldSpace, endWorldSpace;
  2745. Vector3DMultiplyPositionProjective( shadowToWorld, startShadowSpace, startWorldSpace );
  2746. Vector3DMultiplyPositionProjective( shadowToWorld, endShadowSpace, endWorldSpace );
  2747. debugoverlay->AddLineOverlay( startWorldSpace, endWorldSpace, r, g, b, false, -1 );
  2748. }
  2749. static void LineDrawHelper( const Vector &start, const Vector &end,
  2750. const VMatrix &viewMatrixInverse, unsigned char r = 255, unsigned char g = 255, unsigned char b = 255 )
  2751. {
  2752. Vector startWorldSpace, endWorldSpace;
  2753. Vector3DMultiplyPosition( viewMatrixInverse, start, startWorldSpace );
  2754. Vector3DMultiplyPosition( viewMatrixInverse, end, endWorldSpace );
  2755. debugoverlay->AddLineOverlay( startWorldSpace, endWorldSpace, r, g, b, false, -1 );
  2756. }
  2757. // We're going to sweep out an inner and outer superellipse. Each superellipse has the equation:
  2758. //
  2759. // 2 2
  2760. // - -
  2761. // ( x )d ( y )d
  2762. // (---) + (---) = 1
  2763. // ( a ) ( b )
  2764. //
  2765. // where,
  2766. // d is what we're calling m_fRoundness
  2767. //
  2768. // The inner superellipse uses a = m_fWidth and b = m_fHeight
  2769. // The outer superellipse uses a = (m_fWidth + m_fWedge) and b = (m_fHeight + m_fHedge)
  2770. //
  2771. // Controls density of wireframe uberlight
  2772. #define NUM_SUPER_ELLIPSE_POINTS 192
  2773. #define CONNECTOR_FREQ 24
  2774. void CClientShadowMgr::DrawUberlightRig( const Vector &vOrigin, const VMatrix &matWorldToFlashlight, FlashlightState_t state )
  2775. {
  2776. int i;
  2777. float fXNear, fXFar, fYNear, fYFar, fXNearEdge, fXFarEdge, fYNearEdge, fYFarEdge, m;
  2778. UberlightState_t uber = state.m_uberlightState;
  2779. VMatrix viewMatrixInverse, viewMatrix;
  2780. // A set of scratch points on the +x +y quadrants of the near and far ends of the swept superellipse wireframe
  2781. Vector vecNearInnerPoints[(NUM_SUPER_ELLIPSE_POINTS / 4) + 1]; // Inner points for four superellipses
  2782. Vector vecFarInnerPoints[(NUM_SUPER_ELLIPSE_POINTS / 4) + 1];
  2783. Vector vecNearEdgeInnerPoints[(NUM_SUPER_ELLIPSE_POINTS / 4) + 1];
  2784. Vector vecFarEdgeInnerPoints[(NUM_SUPER_ELLIPSE_POINTS / 4) + 1];
  2785. Vector vecNearOuterPoints[(NUM_SUPER_ELLIPSE_POINTS / 4) + 1]; // Outer points for four superellipses
  2786. Vector vecFarOuterPoints[(NUM_SUPER_ELLIPSE_POINTS / 4) + 1];
  2787. Vector vecNearEdgeOuterPoints[(NUM_SUPER_ELLIPSE_POINTS / 4) + 1];
  2788. Vector vecFarEdgeOuterPoints[(NUM_SUPER_ELLIPSE_POINTS / 4) + 1];
  2789. // Clock hand which sweeps out a full circle
  2790. float fTheta = 0;
  2791. float fThetaIncrement = (2.0f * 3.14159) / ((float)NUM_SUPER_ELLIPSE_POINTS);
  2792. // precompute the 2/d exponent
  2793. float r = 2.0f / uber.m_fRoundness;
  2794. // Initialize arrays of points in light's local space defining +x +y quadrants of extruded superellipses (including x==0 and y==0 vertices)
  2795. for ( i = 0; i<(NUM_SUPER_ELLIPSE_POINTS / 4) + 1; i++ )
  2796. {
  2797. if ( i == 0 ) // If this is the 0th vertex
  2798. {
  2799. fXFar = uber.m_fWidth * uber.m_fCutOff; // compute near and far x's
  2800. fXNear = uber.m_fWidth * uber.m_fCutOn;
  2801. fXFarEdge = uber.m_fWidth * (uber.m_fCutOff + uber.m_fFarEdge);
  2802. fXNearEdge = uber.m_fWidth * (uber.m_fCutOn - uber.m_fNearEdge);
  2803. fYFar = fYNear = fYFarEdge = fYNearEdge =0; // y's are zero
  2804. }
  2805. else if ( i == (NUM_SUPER_ELLIPSE_POINTS / 4) ) // If this is the vertex on the y axis, avoid numerical problems
  2806. {
  2807. fXFar = fXNear = fXFarEdge = fXNearEdge = 0; // x's are zero
  2808. fYFar = uber.m_fHeight * uber.m_fCutOff; // compute near and far y's
  2809. fYNear = uber.m_fHeight * uber.m_fCutOn;
  2810. fYFarEdge = uber.m_fHeight * (uber.m_fCutOff + uber.m_fFarEdge);
  2811. fYNearEdge = uber.m_fHeight * (uber.m_fCutOn - uber.m_fNearEdge);
  2812. }
  2813. else
  2814. {
  2815. m = sinf(fTheta) / cosf(fTheta); // compute slope of line from origin
  2816. // Solve for inner x's (intersect line of slope m with inner superellipses)
  2817. fXFar = (powf(powf(1.0f/uber.m_fWidth,r) + powf(m/uber.m_fHeight,r), -1.0f/r) * uber.m_fCutOff);
  2818. fXNear = (powf(powf(1.0f/uber.m_fWidth,r) + powf(m/uber.m_fHeight,r), -1.0f/r) * uber.m_fCutOn);
  2819. fXFarEdge = (powf(powf(1.0f/uber.m_fWidth,r) + powf(m/uber.m_fHeight,r), -1.0f/r) * (uber.m_fCutOff + uber.m_fFarEdge));
  2820. fXNearEdge = (powf(powf(1.0f/uber.m_fWidth,r) + powf(m/uber.m_fHeight,r), -1.0f/r) * (uber.m_fCutOn - uber.m_fNearEdge));
  2821. // Solve for inner y's using line equations
  2822. fYFar = m * fXFar;
  2823. fYNear = m * fXNear;
  2824. fYFarEdge = m * fXFarEdge;
  2825. fYNearEdge = m * fXNearEdge;
  2826. }
  2827. // World to Light's View matrix
  2828. BuildWorldToShadowMatrix( viewMatrix, state.m_vecLightOrigin, state.m_quatOrientation );
  2829. viewMatrixInverse = viewMatrix.InverseTR();
  2830. // Store world space positions in array
  2831. vecFarInnerPoints[i] = Vector( fXFar, fYFar, uber.m_fCutOff );
  2832. vecNearInnerPoints[i] = Vector( fXNear, fYNear, uber.m_fCutOn );
  2833. vecFarEdgeInnerPoints[i] = Vector( fXFarEdge, fYFarEdge, uber.m_fCutOff + uber.m_fFarEdge );
  2834. vecNearEdgeInnerPoints[i] = Vector( fXNearEdge, fYNearEdge, uber.m_fCutOn - uber.m_fNearEdge );
  2835. if ( i == 0 ) // If this is the 0th vertex
  2836. {
  2837. fXFar = (uber.m_fWidth + uber.m_fWedge) * uber.m_fCutOff; // compute near and far x's
  2838. fXNear = (uber.m_fWidth + uber.m_fWedge) * uber.m_fCutOn;
  2839. fXFarEdge = (uber.m_fWidth + uber.m_fWedge) * (uber.m_fCutOff + uber.m_fFarEdge);
  2840. fXNearEdge = (uber.m_fWidth + uber.m_fWedge) * (uber.m_fCutOn - uber.m_fNearEdge);
  2841. fYFar = fYNear = fYFarEdge = fYNearEdge = 0; // y's are zero
  2842. }
  2843. else if ( i == (NUM_SUPER_ELLIPSE_POINTS / 4) ) // If this is the vertex on the y axis, avoid numerical problems
  2844. {
  2845. fXFar = fXNear = fXFarEdge = fXNearEdge = 0; // x's are zero
  2846. fYFar = (uber.m_fHeight + uber.m_fHedge) * uber.m_fCutOff; // compute near and far y's
  2847. fYNear = (uber.m_fHeight + uber.m_fHedge) * uber.m_fCutOn;
  2848. fYFarEdge = (uber.m_fHeight + uber.m_fHedge) * (uber.m_fCutOff + uber.m_fFarEdge);
  2849. fYNearEdge = (uber.m_fHeight + uber.m_fHedge) * (uber.m_fCutOn - uber.m_fNearEdge);
  2850. }
  2851. else
  2852. {
  2853. m = sinf(fTheta) / cosf(fTheta); // compute slope of line from origin
  2854. // Solve for inner x's (intersect line of slope m with inner superellipses)
  2855. fXFar = (powf(powf(1.0f/(uber.m_fWidth + uber.m_fWedge),r) + powf(m/(uber.m_fHeight + uber.m_fHedge),r), -1.0f/r) * uber.m_fCutOff);
  2856. fXNear = (powf(powf(1.0f/(uber.m_fWidth + uber.m_fWedge),r) + powf(m/(uber.m_fHeight + uber.m_fHedge),r), -1.0f/r) * uber.m_fCutOn);
  2857. fXFarEdge = (powf(powf(1.0f/(uber.m_fWidth + uber.m_fWedge),r) + powf(m/(uber.m_fHeight + uber.m_fHedge),r), -1.0f/r) * (uber.m_fCutOff+ uber.m_fFarEdge));
  2858. fXNearEdge = (powf(powf(1.0f/(uber.m_fWidth + uber.m_fWedge),r) + powf(m/(uber.m_fHeight + uber.m_fHedge),r), -1.0f/r) * (uber.m_fCutOn - uber.m_fNearEdge));
  2859. // Solve for inner y's using line equations
  2860. fYFar = m * fXFar;
  2861. fYNear = m * fXNear;
  2862. fYFarEdge = m * fXFarEdge;
  2863. fYNearEdge = m * fXNearEdge;
  2864. }
  2865. // Store in array
  2866. vecFarOuterPoints[i] = Vector( fXFar, fYFar, uber.m_fCutOff );
  2867. vecNearOuterPoints[i] = Vector( fXNear, fYNear, uber.m_fCutOn );
  2868. vecFarEdgeOuterPoints[i] = Vector( fXFarEdge, fYFarEdge, uber.m_fCutOff + uber.m_fFarEdge );
  2869. vecNearEdgeOuterPoints[i] = Vector( fXNearEdge, fYNearEdge, uber.m_fCutOn - uber.m_fNearEdge );
  2870. fTheta += fThetaIncrement;
  2871. }
  2872. Vector preVector, curVector;
  2873. // Near inner superellipse
  2874. for ( i=0; i<NUM_SUPER_ELLIPSE_POINTS; i++ )
  2875. {
  2876. if ( i <= (NUM_SUPER_ELLIPSE_POINTS / 4)) // +x +y quadrant, copy from scratch array directly
  2877. {
  2878. curVector = vecNearInnerPoints[i];
  2879. curVector.x += uber.m_fShearx * curVector.z;
  2880. curVector.y += uber.m_fSheary * curVector.z;
  2881. }
  2882. else if ( i <= (NUM_SUPER_ELLIPSE_POINTS / 2)) // -x +y quadrant, negate x when copying from scratch array
  2883. {
  2884. curVector = vecNearInnerPoints[(NUM_SUPER_ELLIPSE_POINTS / 2)-i];
  2885. curVector.x *= -1;
  2886. curVector.x += uber.m_fShearx * curVector.z;
  2887. curVector.y += uber.m_fSheary * curVector.z;
  2888. }
  2889. else if ( i <= (3*NUM_SUPER_ELLIPSE_POINTS / 4)) // -x -y quadrant, negate when copying from scratch array
  2890. {
  2891. curVector = vecNearInnerPoints[i-(NUM_SUPER_ELLIPSE_POINTS / 2)];
  2892. curVector.x *= -1;
  2893. curVector.y *= -1;
  2894. curVector.x += uber.m_fShearx * curVector.z;
  2895. curVector.y += uber.m_fSheary * curVector.z;
  2896. }
  2897. else // +x -y quadrant, negate y when copying from scratch array
  2898. {
  2899. curVector = vecNearInnerPoints[NUM_SUPER_ELLIPSE_POINTS-i];
  2900. curVector.y *= -1;
  2901. curVector.x += uber.m_fShearx * curVector.z;
  2902. curVector.y += uber.m_fSheary * curVector.z;
  2903. }
  2904. if ( i != 0 )
  2905. {
  2906. LineDrawHelper( preVector, curVector, viewMatrixInverse, 255, 10, 10 );
  2907. }
  2908. preVector = curVector;
  2909. }
  2910. LineDrawHelper( preVector, vecNearInnerPoints[0], viewMatrixInverse, 255, 10, 10 );
  2911. // Far inner superellipse
  2912. for (i=0; i<NUM_SUPER_ELLIPSE_POINTS; i++)
  2913. {
  2914. if ( i <= (NUM_SUPER_ELLIPSE_POINTS / 4)) // +x +y quadrant, copy from scratch array directly
  2915. {
  2916. curVector = vecFarInnerPoints[i];
  2917. curVector.x += uber.m_fShearx * curVector.z;
  2918. curVector.y += uber.m_fSheary * curVector.z;
  2919. }
  2920. else if ( i <= (NUM_SUPER_ELLIPSE_POINTS / 2)) // -x +y quadrant, negate x when copying from scratch array
  2921. {
  2922. curVector = vecFarInnerPoints[(NUM_SUPER_ELLIPSE_POINTS / 2)-i];
  2923. curVector.x *= -1;
  2924. curVector.x += uber.m_fShearx * curVector.z;
  2925. curVector.y += uber.m_fSheary * curVector.z;
  2926. }
  2927. else if ( i <= (3*NUM_SUPER_ELLIPSE_POINTS / 4)) // -x -y quadrant, negate when copying from scratch array
  2928. {
  2929. curVector = vecFarInnerPoints[i-(NUM_SUPER_ELLIPSE_POINTS / 2)];
  2930. curVector.x *= -1;
  2931. curVector.y *= -1;
  2932. curVector.x += uber.m_fShearx * curVector.z;
  2933. curVector.y += uber.m_fSheary * curVector.z;
  2934. }
  2935. else // +x -y quadrant, negate y when copying from scratch array
  2936. {
  2937. curVector = vecFarInnerPoints[NUM_SUPER_ELLIPSE_POINTS-i];
  2938. curVector.y *= -1;
  2939. curVector.x += uber.m_fShearx * curVector.z;
  2940. curVector.y += uber.m_fSheary * curVector.z;
  2941. }
  2942. if ( i != 0 )
  2943. {
  2944. LineDrawHelper( preVector, curVector, viewMatrixInverse, 10, 10, 255 );
  2945. }
  2946. preVector = curVector;
  2947. }
  2948. LineDrawHelper( preVector, vecFarInnerPoints[0], viewMatrixInverse, 10, 10, 255 );
  2949. // Near outer superellipse
  2950. for (i=0; i<NUM_SUPER_ELLIPSE_POINTS; i++)
  2951. {
  2952. if ( i <= (NUM_SUPER_ELLIPSE_POINTS / 4)) // +x +y quadrant, copy from scratch array directly
  2953. {
  2954. curVector = vecNearOuterPoints[i];
  2955. curVector.x += uber.m_fShearx * curVector.z;
  2956. curVector.y += uber.m_fSheary * curVector.z;
  2957. }
  2958. else if ( i <= (NUM_SUPER_ELLIPSE_POINTS / 2)) // -x +y quadrant, negate x when copying from scratch array
  2959. {
  2960. curVector = vecNearOuterPoints[(NUM_SUPER_ELLIPSE_POINTS / 2)-i];
  2961. curVector.x *= -1;
  2962. curVector.x += uber.m_fShearx * curVector.z;
  2963. curVector.y += uber.m_fSheary * curVector.z;
  2964. }
  2965. else if ( i <= (3*NUM_SUPER_ELLIPSE_POINTS / 4)) // -x -y quadrant, negate when copying from scratch array
  2966. {
  2967. curVector = vecNearOuterPoints[i-(NUM_SUPER_ELLIPSE_POINTS / 2)];
  2968. curVector.x *= -1;
  2969. curVector.y *= -1;
  2970. curVector.x += uber.m_fShearx * curVector.z;
  2971. curVector.y += uber.m_fSheary * curVector.z;
  2972. }
  2973. else // +x -y quadrant, negate y when copying from scratch array
  2974. {
  2975. curVector = vecNearOuterPoints[NUM_SUPER_ELLIPSE_POINTS-i];
  2976. curVector.y *= -1;
  2977. curVector.x += uber.m_fShearx * curVector.z;
  2978. curVector.y += uber.m_fSheary * curVector.z;
  2979. }
  2980. if ( i != 0 )
  2981. {
  2982. LineDrawHelper( preVector, curVector, viewMatrixInverse, 255, 10, 10);
  2983. }
  2984. preVector = curVector;
  2985. }
  2986. LineDrawHelper( preVector, vecNearOuterPoints[0], viewMatrixInverse, 255, 10, 10 );
  2987. // Far outer superellipse
  2988. for (i=0; i<NUM_SUPER_ELLIPSE_POINTS; i++)
  2989. {
  2990. if ( i <= (NUM_SUPER_ELLIPSE_POINTS / 4)) // +x +y quadrant, copy from scratch array directly
  2991. {
  2992. curVector = vecFarOuterPoints[i];
  2993. curVector.x += uber.m_fShearx * curVector.z;
  2994. curVector.y += uber.m_fSheary * curVector.z;
  2995. }
  2996. else if ( i <= (NUM_SUPER_ELLIPSE_POINTS / 2)) // -x +y quadrant, negate x when copying from scratch array
  2997. {
  2998. curVector = vecFarOuterPoints[(NUM_SUPER_ELLIPSE_POINTS / 2)-i];
  2999. curVector.x *= -1;
  3000. curVector.x += uber.m_fShearx * curVector.z;
  3001. curVector.y += uber.m_fSheary * curVector.z;
  3002. }
  3003. else if ( i <= (3*NUM_SUPER_ELLIPSE_POINTS / 4)) // -x -y quadrant, negate when copying from scratch array
  3004. {
  3005. curVector = vecFarOuterPoints[i-(NUM_SUPER_ELLIPSE_POINTS / 2)];
  3006. curVector.x *= -1;
  3007. curVector.y *= -1;
  3008. curVector.x += uber.m_fShearx * curVector.z;
  3009. curVector.y += uber.m_fSheary * curVector.z;
  3010. }
  3011. else // +x -y quadrant, negate y when copying from scratch array
  3012. {
  3013. curVector = vecFarOuterPoints[NUM_SUPER_ELLIPSE_POINTS-i];
  3014. curVector.y *= -1;
  3015. curVector.x += uber.m_fShearx * curVector.z;
  3016. curVector.y += uber.m_fSheary * curVector.z;
  3017. }
  3018. if ( i != 0 )
  3019. {
  3020. LineDrawHelper( preVector, curVector, viewMatrixInverse, 10, 10, 255 );
  3021. }
  3022. preVector = curVector;
  3023. }
  3024. LineDrawHelper( preVector, vecFarOuterPoints[0], viewMatrixInverse, 10, 10, 255 );
  3025. // Near edge inner superellipse
  3026. for (i=0; i<NUM_SUPER_ELLIPSE_POINTS; i++)
  3027. {
  3028. if ( i <= (NUM_SUPER_ELLIPSE_POINTS / 4)) // +x +y quadrant, copy from scratch array directly
  3029. {
  3030. curVector = vecNearEdgeInnerPoints[i];
  3031. curVector.x += uber.m_fShearx * curVector.z;
  3032. curVector.y += uber.m_fSheary * curVector.z;
  3033. }
  3034. else if ( i <= (NUM_SUPER_ELLIPSE_POINTS / 2)) // -x +y quadrant, negate x when copying from scratch array
  3035. {
  3036. curVector = vecNearEdgeInnerPoints[(NUM_SUPER_ELLIPSE_POINTS / 2)-i];
  3037. curVector.x *= -1;
  3038. curVector.x += uber.m_fShearx * curVector.z;
  3039. curVector.y += uber.m_fSheary * curVector.z;
  3040. }
  3041. else if ( i <= (3*NUM_SUPER_ELLIPSE_POINTS / 4)) // -x -y quadrant, negate when copying from scratch array
  3042. {
  3043. curVector = vecNearEdgeInnerPoints[i-(NUM_SUPER_ELLIPSE_POINTS / 2)];
  3044. curVector.x *= -1;
  3045. curVector.y *= -1;
  3046. curVector.x += uber.m_fShearx * curVector.z;
  3047. curVector.y += uber.m_fSheary * curVector.z;
  3048. }
  3049. else // +x -y quadrant, negate y when copying from scratch array
  3050. {
  3051. curVector = vecNearEdgeInnerPoints[NUM_SUPER_ELLIPSE_POINTS-i];
  3052. curVector.y *= -1;
  3053. curVector.x += uber.m_fShearx * curVector.z;
  3054. curVector.y += uber.m_fSheary * curVector.z;
  3055. }
  3056. if ( i != 0 )
  3057. {
  3058. LineDrawHelper( preVector, curVector, viewMatrixInverse, 255, 10, 10 );
  3059. }
  3060. preVector = curVector;
  3061. }
  3062. LineDrawHelper( preVector, vecNearEdgeInnerPoints[0], viewMatrixInverse, 255, 10, 10 );
  3063. // Far inner superellipse
  3064. for (i=0; i<NUM_SUPER_ELLIPSE_POINTS; i++)
  3065. {
  3066. if ( i <= (NUM_SUPER_ELLIPSE_POINTS / 4)) // +x +y quadrant, copy from scratch array directly
  3067. {
  3068. curVector = vecFarEdgeInnerPoints[i];
  3069. curVector.x += uber.m_fShearx * curVector.z;
  3070. curVector.y += uber.m_fSheary * curVector.z;
  3071. }
  3072. else if ( i <= (NUM_SUPER_ELLIPSE_POINTS / 2)) // -x +y quadrant, negate x when copying from scratch array
  3073. {
  3074. curVector = vecFarEdgeInnerPoints[(NUM_SUPER_ELLIPSE_POINTS / 2)-i];
  3075. curVector.x *= -1;
  3076. curVector.x += uber.m_fShearx * curVector.z;
  3077. curVector.y += uber.m_fSheary * curVector.z;
  3078. }
  3079. else if ( i <= (3*NUM_SUPER_ELLIPSE_POINTS / 4)) // -x -y quadrant, negate when copying from scratch array
  3080. {
  3081. curVector = vecFarEdgeInnerPoints[i-(NUM_SUPER_ELLIPSE_POINTS / 2)];
  3082. curVector.x *= -1;
  3083. curVector.y *= -1;
  3084. curVector.x += uber.m_fShearx * curVector.z;
  3085. curVector.y += uber.m_fSheary * curVector.z;
  3086. }
  3087. else // +x -y quadrant, negate y when copying from scratch array
  3088. {
  3089. curVector = vecFarEdgeInnerPoints[NUM_SUPER_ELLIPSE_POINTS-i];
  3090. curVector.y *= -1;
  3091. curVector.x += uber.m_fShearx * curVector.z;
  3092. curVector.y += uber.m_fSheary * curVector.z;
  3093. }
  3094. if ( i != 0 )
  3095. {
  3096. LineDrawHelper( preVector, curVector, viewMatrixInverse, 10, 10, 255 );
  3097. }
  3098. preVector = curVector;
  3099. }
  3100. LineDrawHelper( preVector, vecFarEdgeInnerPoints[0], viewMatrixInverse, 10, 10, 255 );
  3101. // Near outer superellipse
  3102. for (i=0; i<NUM_SUPER_ELLIPSE_POINTS; i++)
  3103. {
  3104. if ( i <= (NUM_SUPER_ELLIPSE_POINTS / 4)) // +x +y quadrant, copy from scratch array directly
  3105. {
  3106. curVector = vecNearEdgeOuterPoints[i];
  3107. curVector.x += uber.m_fShearx * curVector.z;
  3108. curVector.y += uber.m_fSheary * curVector.z;
  3109. }
  3110. else if ( i <= (NUM_SUPER_ELLIPSE_POINTS / 2)) // -x +y quadrant, negate x when copying from scratch array
  3111. {
  3112. curVector = vecNearEdgeOuterPoints[(NUM_SUPER_ELLIPSE_POINTS / 2)-i];
  3113. curVector.x *= -1;
  3114. curVector.x += uber.m_fShearx * curVector.z;
  3115. curVector.y += uber.m_fSheary * curVector.z;
  3116. }
  3117. else if ( i <= (3*NUM_SUPER_ELLIPSE_POINTS / 4)) // -x -y quadrant, negate when copying from scratch array
  3118. {
  3119. curVector = vecNearEdgeOuterPoints[i-(NUM_SUPER_ELLIPSE_POINTS / 2)];
  3120. curVector.x *= -1;
  3121. curVector.y *= -1;
  3122. curVector.x += uber.m_fShearx * curVector.z;
  3123. curVector.y += uber.m_fSheary * curVector.z;
  3124. }
  3125. else // +x -y quadrant, negate y when copying from scratch array
  3126. {
  3127. curVector = vecNearEdgeOuterPoints[NUM_SUPER_ELLIPSE_POINTS-i];
  3128. curVector.y *= -1;
  3129. curVector.x += uber.m_fShearx * curVector.z;
  3130. curVector.y += uber.m_fSheary * curVector.z;
  3131. }
  3132. if ( i != 0 )
  3133. {
  3134. LineDrawHelper( preVector, curVector, viewMatrixInverse, 255, 10, 10 );
  3135. }
  3136. preVector = curVector;
  3137. }
  3138. LineDrawHelper( preVector, vecNearEdgeOuterPoints[0], viewMatrixInverse, 255, 10, 10 );
  3139. // Far outer superellipse
  3140. for ( i=0; i<NUM_SUPER_ELLIPSE_POINTS; i++ )
  3141. {
  3142. if ( i <= (NUM_SUPER_ELLIPSE_POINTS / 4)) // +x +y quadrant, copy from scratch array directly
  3143. {
  3144. curVector = vecFarEdgeOuterPoints[i];
  3145. curVector.x += uber.m_fShearx * curVector.z;
  3146. curVector.y += uber.m_fSheary * curVector.z;
  3147. }
  3148. else if ( i <= (NUM_SUPER_ELLIPSE_POINTS / 2)) // -x +y quadrant, negate x when copying from scratch array
  3149. {
  3150. curVector = vecFarEdgeOuterPoints[(NUM_SUPER_ELLIPSE_POINTS / 2)-i];
  3151. curVector.x *= -1;
  3152. curVector.x += uber.m_fShearx * curVector.z;
  3153. curVector.y += uber.m_fSheary * curVector.z;
  3154. }
  3155. else if ( i <= (3*NUM_SUPER_ELLIPSE_POINTS / 4)) // -x -y quadrant, negate when copying from scratch array
  3156. {
  3157. curVector = vecFarEdgeOuterPoints[i-(NUM_SUPER_ELLIPSE_POINTS / 2)];
  3158. curVector.x *= -1;
  3159. curVector.y *= -1;
  3160. curVector.x += uber.m_fShearx * curVector.z;
  3161. curVector.y += uber.m_fSheary * curVector.z;
  3162. }
  3163. else // +x -y quadrant, negate y when copying from scratch array
  3164. {
  3165. curVector = vecFarEdgeOuterPoints[NUM_SUPER_ELLIPSE_POINTS-i];
  3166. curVector.y *= -1;
  3167. curVector.x += uber.m_fShearx * curVector.z;
  3168. curVector.y += uber.m_fSheary * curVector.z;
  3169. }
  3170. if ( i != 0 )
  3171. {
  3172. LineDrawHelper( preVector, curVector, viewMatrixInverse, 10, 10, 255 );
  3173. }
  3174. preVector = curVector;
  3175. }
  3176. LineDrawHelper( preVector, vecFarEdgeOuterPoints[0], viewMatrixInverse, 10, 10, 255 );
  3177. // Connectors
  3178. for ( i=0; i< NUM_SUPER_ELLIPSE_POINTS; i++ )
  3179. {
  3180. if ( ( i % CONNECTOR_FREQ ) == 0 )
  3181. {
  3182. Vector vecNearEdgeOuter, vecNearOuter, vecFarOuter, vecFarEdgeOuter;
  3183. if ( i <= (NUM_SUPER_ELLIPSE_POINTS / 4)) // +x +y quadrant, copy from scratch array directly
  3184. {
  3185. vecNearEdgeOuter = vecNearEdgeOuterPoints[i];
  3186. vecNearEdgeOuter.x += uber.m_fShearx * vecNearEdgeOuter.z;
  3187. vecNearEdgeOuter.y += uber.m_fSheary * vecNearEdgeOuter.z;
  3188. vecNearOuter = vecNearOuterPoints[i];
  3189. vecNearOuter.x += uber.m_fShearx * vecNearOuter.z;
  3190. vecNearOuter.y += uber.m_fSheary * vecNearOuter.z;
  3191. vecFarEdgeOuter = vecFarEdgeOuterPoints[i];
  3192. vecFarEdgeOuter.x += uber.m_fShearx * vecFarEdgeOuter.z;
  3193. vecFarEdgeOuter.y += uber.m_fSheary * vecFarEdgeOuter.z;
  3194. vecFarOuter = vecFarOuterPoints[i];
  3195. vecFarOuter.x += uber.m_fShearx * vecFarOuter.z;
  3196. vecFarOuter.y += uber.m_fSheary * vecFarOuter.z;
  3197. }
  3198. else if ( i <= (NUM_SUPER_ELLIPSE_POINTS / 2)) // -x +y quadrant, negate x when copying from scratch array
  3199. {
  3200. vecNearEdgeOuter = vecNearEdgeOuterPoints[(NUM_SUPER_ELLIPSE_POINTS / 2)-i];
  3201. vecNearEdgeOuter.x *= -1;
  3202. vecNearEdgeOuter.x += uber.m_fShearx * vecNearEdgeOuter.z;
  3203. vecNearEdgeOuter.y += uber.m_fSheary * vecNearEdgeOuter.z;
  3204. vecNearOuter = vecNearOuterPoints[(NUM_SUPER_ELLIPSE_POINTS / 2)-i];
  3205. vecNearOuter.x *= -1;
  3206. vecNearOuter.x += uber.m_fShearx * vecNearOuter.z;
  3207. vecNearOuter.y += uber.m_fSheary * vecNearOuter.z;
  3208. vecFarEdgeOuter = vecFarEdgeOuterPoints[(NUM_SUPER_ELLIPSE_POINTS / 2)-i];
  3209. vecFarEdgeOuter.x *= -1;
  3210. vecFarEdgeOuter.x += uber.m_fShearx * vecFarEdgeOuter.z;
  3211. vecFarEdgeOuter.y += uber.m_fSheary * vecFarEdgeOuter.z;
  3212. vecFarOuter = vecFarOuterPoints[(NUM_SUPER_ELLIPSE_POINTS / 2)-i];
  3213. vecFarOuter.x *= -1;
  3214. vecFarOuter.x += uber.m_fShearx * vecFarOuter.z;
  3215. vecFarOuter.y += uber.m_fSheary * vecFarOuter.z;
  3216. }
  3217. else if ( i <= (3*NUM_SUPER_ELLIPSE_POINTS / 4)) // -x -y quadrant, negate when copying from scratch array
  3218. {
  3219. vecNearEdgeOuter = vecNearEdgeOuterPoints[i-(NUM_SUPER_ELLIPSE_POINTS / 2)];
  3220. vecNearEdgeOuter.x *= -1;
  3221. vecNearEdgeOuter.y *= -1;
  3222. vecNearEdgeOuter.x += uber.m_fShearx * vecNearEdgeOuter.z;
  3223. vecNearEdgeOuter.y += uber.m_fSheary * vecNearEdgeOuter.z;
  3224. vecNearOuter = vecNearOuterPoints[i-(NUM_SUPER_ELLIPSE_POINTS / 2)];
  3225. vecNearOuter.x *= -1;
  3226. vecNearOuter.y *= -1;
  3227. vecNearOuter.x += uber.m_fShearx * vecNearOuter.z;
  3228. vecNearOuter.y += uber.m_fSheary * vecNearOuter.z;
  3229. vecFarEdgeOuter = vecFarEdgeOuterPoints[i-(NUM_SUPER_ELLIPSE_POINTS / 2)];
  3230. vecFarEdgeOuter.x *= -1;
  3231. vecFarEdgeOuter.y *= -1;
  3232. vecFarEdgeOuter.x += uber.m_fShearx * vecFarEdgeOuter.z;
  3233. vecFarEdgeOuter.y += uber.m_fSheary * vecFarEdgeOuter.z;
  3234. vecFarOuter = vecFarOuterPoints[i-(NUM_SUPER_ELLIPSE_POINTS / 2)];
  3235. vecFarOuter.x *= -1;
  3236. vecFarOuter.y *= -1;
  3237. vecFarOuter.x += uber.m_fShearx * vecFarOuter.z;
  3238. vecFarOuter.y += uber.m_fSheary * vecFarOuter.z;
  3239. }
  3240. else // +x -y quadrant, negate y when copying from scratch array
  3241. {
  3242. vecNearEdgeOuter = vecNearEdgeOuterPoints[NUM_SUPER_ELLIPSE_POINTS-i];
  3243. vecNearEdgeOuter.y *= -1;
  3244. vecNearEdgeOuter.x += uber.m_fShearx * vecNearEdgeOuter.z;
  3245. vecNearEdgeOuter.y += uber.m_fSheary * vecNearEdgeOuter.z;
  3246. vecNearOuter = vecNearOuterPoints[NUM_SUPER_ELLIPSE_POINTS-i];
  3247. vecNearOuter.y *= -1;
  3248. vecNearOuter.x += uber.m_fShearx * vecNearOuter.z;
  3249. vecNearOuter.y += uber.m_fSheary * vecNearOuter.z;
  3250. vecFarEdgeOuter = vecFarEdgeOuterPoints[NUM_SUPER_ELLIPSE_POINTS-i];
  3251. vecFarEdgeOuter.y *= -1;
  3252. vecFarEdgeOuter.x += uber.m_fShearx * vecFarEdgeOuter.z;
  3253. vecFarEdgeOuter.y += uber.m_fSheary * vecFarEdgeOuter.z;
  3254. vecFarOuter = vecFarOuterPoints[NUM_SUPER_ELLIPSE_POINTS-i];
  3255. vecFarOuter.y *= -1;
  3256. vecFarOuter.x += uber.m_fShearx * vecFarOuter.z;
  3257. vecFarOuter.y += uber.m_fSheary * vecFarOuter.z;
  3258. }
  3259. LineDrawHelper( vecNearOuter, vecNearEdgeOuter, viewMatrixInverse, 255, 10, 10 );
  3260. LineDrawHelper( vecNearOuter, vecFarOuter, viewMatrixInverse, 220, 10, 220 );
  3261. LineDrawHelper( vecFarEdgeOuter, vecFarOuter, viewMatrixInverse, 10, 10, 255 );
  3262. }
  3263. }
  3264. }
  3265. void CClientShadowMgr::DrawFrustum( const Vector &vOrigin, const VMatrix &matWorldToFlashlight )
  3266. {
  3267. VMatrix flashlightToWorld;
  3268. MatrixInverseGeneral( matWorldToFlashlight, flashlightToWorld );
  3269. // Draw boundaries of frustum
  3270. LineDrawHelperProjective( Vector( 0.0f, 0.0f, 0.0f ), Vector( 0.0f, 0.0f, 1.0f ), flashlightToWorld, 255, 255, 255 );
  3271. LineDrawHelperProjective( Vector( 0.0f, 0.0f, 1.0f ), Vector( 0.0f, 1.0f, 1.0f ), flashlightToWorld, 255, 255, 255 );
  3272. LineDrawHelperProjective( Vector( 0.0f, 1.0f, 1.0f ), Vector( 0.0f, 1.0f, 0.0f ), flashlightToWorld, 255, 255, 255 );
  3273. LineDrawHelperProjective( Vector( 0.0f, 1.0f, 0.0f ), Vector( 0.0f, 0.0f, 0.0f ), flashlightToWorld, 255, 255, 255 );
  3274. LineDrawHelperProjective( Vector( 1.0f, 0.0f, 0.0f ), Vector( 1.0f, 0.0f, 1.0f ), flashlightToWorld, 255, 255, 255 );
  3275. LineDrawHelperProjective( Vector( 1.0f, 0.0f, 1.0f ), Vector( 1.0f, 1.0f, 1.0f ), flashlightToWorld, 255, 255, 255 );
  3276. LineDrawHelperProjective( Vector( 1.0f, 1.0f, 1.0f ), Vector( 1.0f, 1.0f, 0.0f ), flashlightToWorld, 255, 255, 255 );
  3277. LineDrawHelperProjective( Vector( 1.0f, 1.0f, 0.0f ), Vector( 1.0f, 0.0f, 0.0f ), flashlightToWorld, 255, 255, 255 );
  3278. LineDrawHelperProjective( Vector( 0.0f, 0.0f, 0.0f ), Vector( 1.0f, 0.0f, 0.0f ), flashlightToWorld, 255, 255, 255 );
  3279. LineDrawHelperProjective( Vector( 0.0f, 0.0f, 1.0f ), Vector( 1.0f, 0.0f, 1.0f ), flashlightToWorld, 255, 255, 255 );
  3280. LineDrawHelperProjective( Vector( 0.0f, 1.0f, 1.0f ), Vector( 1.0f, 1.0f, 1.0f ), flashlightToWorld, 255, 255, 255 );
  3281. LineDrawHelperProjective( Vector( 0.0f, 1.0f, 0.0f ), Vector( 1.0f, 1.0f, 0.0f ), flashlightToWorld, 255, 255, 255 );
  3282. // Draw RGB triad at front plane
  3283. LineDrawHelperProjective( Vector( 0.5f, 0.5f, 0.0f ), Vector( 1.0f, 0.5f, 0.0f ), flashlightToWorld, 255, 0, 0 );
  3284. LineDrawHelperProjective( Vector( 0.5f, 0.5f, 0.0f ), Vector( 0.5f, 1.0f, 0.0f ), flashlightToWorld, 0, 255, 0 );
  3285. LineDrawHelperProjective( Vector( 0.5f, 0.5f, 0.0f ), Vector( 0.5f, 0.5f, 0.35f ), flashlightToWorld, 0, 0, 255 );
  3286. }
  3287. //-----------------------------------------------------------------------------
  3288. // Builds a list of leaves inside the flashlight volume
  3289. //-----------------------------------------------------------------------------
  3290. static void BuildFlashlightLeafList( CShadowLeafEnum *pEnum, const Vector &vecOrigin, const VMatrix &worldToShadow )
  3291. {
  3292. // Use an AABB around the frustum to enumerate leaves.
  3293. Vector mins, maxs;
  3294. CalculateAABBFromProjectionMatrix( worldToShadow, &mins, &maxs );
  3295. ISpatialQuery* pQuery = engine->GetBSPTreeQuery();
  3296. pQuery->EnumerateLeavesInBox( mins, maxs, pEnum, 0 );
  3297. // pEnum->ExtractUnconnectedLeaves( vecOrigin );
  3298. }
  3299. void CClientShadowMgr::BuildFlashlight( ClientShadowHandle_t handle )
  3300. {
  3301. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  3302. // For the 360, we just draw flashlights with the main geometry
  3303. // and bypass the entire shadow casting system.
  3304. ClientShadow_t &shadow = m_Shadows[handle];
  3305. if ( shadowmgr->SinglePassFlashlightModeEnabled() && !pRenderContext->IsCullingEnabledForSinglePassFlashlight() )
  3306. {
  3307. // This will update the matrices, but not do work to add the flashlight to surfaces
  3308. shadowmgr->ProjectFlashlight( shadow.m_ShadowHandle, shadow.m_WorldToShadow, 0, NULL );
  3309. return;
  3310. }
  3311. VPROF_BUDGET( "CClientShadowMgr::BuildFlashlight", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  3312. bool bLightModels = r_flashlightmodels.GetBool();
  3313. bool bLightSpecificEntity = shadow.m_hTargetEntity.Get() != NULL;
  3314. bool bLightWorld = ( shadow.m_Flags & SHADOW_FLAGS_LIGHT_WORLD ) != 0;
  3315. int nCount = 0;
  3316. const int *pLeafList = 0;
  3317. CShadowLeafEnum leafList;
  3318. if ( bLightWorld || ( bLightModels && !bLightSpecificEntity ) )
  3319. {
  3320. const FlashlightState_t& flashlightState = shadowmgr->GetFlashlightState( shadow.m_ShadowHandle );
  3321. BuildFlashlightLeafList( &leafList, flashlightState.m_vecLightOrigin, shadow.m_WorldToShadow );
  3322. nCount = leafList.m_LeafList.Count();
  3323. pLeafList = leafList.m_LeafList.Base();
  3324. }
  3325. if( bLightWorld )
  3326. {
  3327. shadowmgr->ProjectFlashlight( shadow.m_ShadowHandle, shadow.m_WorldToShadow, nCount, pLeafList );
  3328. }
  3329. else
  3330. {
  3331. // This should clear all models and surfaces from this shadow
  3332. shadowmgr->EnableShadow( shadow.m_ShadowHandle, false );
  3333. shadowmgr->EnableShadow( shadow.m_ShadowHandle, true );
  3334. }
  3335. if( ( shadow.m_Flags & ( SHADOW_FLAGS_SIMPLE_PROJECTION ) ) != 0 )
  3336. {
  3337. return;
  3338. }
  3339. if ( !bLightModels )
  3340. return;
  3341. if ( !bLightSpecificEntity )
  3342. {
  3343. // Add the shadow to the client leaf system so it correctly marks
  3344. // leafs as being affected by a particular shadow
  3345. ClientLeafSystem()->ProjectFlashlight( shadow.m_ClientLeafShadowHandle, nCount, pLeafList );
  3346. return;
  3347. }
  3348. // We know what we are focused on, so just add the shadow directly to that receiver
  3349. Assert( shadow.m_hTargetEntity->GetModel() );
  3350. C_BaseEntity *pChild = shadow.m_hTargetEntity->FirstMoveChild();
  3351. while( pChild )
  3352. {
  3353. int modelType = modelinfo->GetModelType( pChild->GetModel() );
  3354. if (modelType == mod_brush)
  3355. {
  3356. AddShadowToReceiver( handle, pChild, SHADOW_RECEIVER_BRUSH_MODEL );
  3357. }
  3358. else if ( modelType == mod_studio )
  3359. {
  3360. AddShadowToReceiver( handle, pChild, SHADOW_RECEIVER_STUDIO_MODEL );
  3361. }
  3362. pChild = pChild->NextMovePeer();
  3363. }
  3364. int modelType = modelinfo->GetModelType( shadow.m_hTargetEntity->GetModel() );
  3365. if (modelType == mod_brush)
  3366. {
  3367. AddShadowToReceiver( handle, shadow.m_hTargetEntity, SHADOW_RECEIVER_BRUSH_MODEL );
  3368. }
  3369. else if ( modelType == mod_studio )
  3370. {
  3371. AddShadowToReceiver( handle, shadow.m_hTargetEntity, SHADOW_RECEIVER_STUDIO_MODEL );
  3372. }
  3373. }
  3374. //-----------------------------------------------------------------------------
  3375. // Adds the child bounds to the bounding box
  3376. //-----------------------------------------------------------------------------
  3377. void CClientShadowMgr::AddChildBounds( matrix3x4_t &matWorldToBBox, IClientRenderable* pParent, Vector &vecMins, Vector &vecMaxs )
  3378. {
  3379. Vector vecChildMins, vecChildMaxs;
  3380. Vector vecNewChildMins, vecNewChildMaxs;
  3381. matrix3x4_t childToBBox;
  3382. IClientRenderable *pChild = pParent->FirstShadowChild();
  3383. while( pChild )
  3384. {
  3385. // Transform the child bbox into the space of the main bbox
  3386. // FIXME: Optimize this?
  3387. if ( GetActualShadowCastType( pChild ) != SHADOWS_NONE)
  3388. {
  3389. pChild->GetShadowRenderBounds( vecChildMins, vecChildMaxs, SHADOWS_RENDER_TO_TEXTURE );
  3390. ConcatTransforms( matWorldToBBox, pChild->RenderableToWorldTransform(), childToBBox );
  3391. TransformAABB( childToBBox, vecChildMins, vecChildMaxs, vecNewChildMins, vecNewChildMaxs );
  3392. VectorMin( vecMins, vecNewChildMins, vecMins );
  3393. VectorMax( vecMaxs, vecNewChildMaxs, vecMaxs );
  3394. }
  3395. AddChildBounds( matWorldToBBox, pChild, vecMins, vecMaxs );
  3396. pChild = pChild->NextShadowPeer();
  3397. }
  3398. }
  3399. //-----------------------------------------------------------------------------
  3400. // Compute a bounds for the entity + children
  3401. //-----------------------------------------------------------------------------
  3402. void CClientShadowMgr::ComputeHierarchicalBounds( IClientRenderable *pRenderable, Vector &vecMins, Vector &vecMaxs )
  3403. {
  3404. ShadowType_t shadowType = GetActualShadowCastType( pRenderable );
  3405. pRenderable->GetShadowRenderBounds( vecMins, vecMaxs, shadowType );
  3406. // We could use a good solution for this in the regular PC build, since
  3407. // it causes lots of extra bone setups for entities you can't see.
  3408. if ( IsPC() )
  3409. {
  3410. IClientRenderable *pChild = pRenderable->FirstShadowChild();
  3411. // Don't recurse down the tree when we hit a blobby shadow
  3412. if ( pChild && shadowType != SHADOWS_SIMPLE )
  3413. {
  3414. matrix3x4_t matWorldToBBox;
  3415. MatrixInvert( pRenderable->RenderableToWorldTransform(), matWorldToBBox );
  3416. AddChildBounds( matWorldToBBox, pRenderable, vecMins, vecMaxs );
  3417. }
  3418. }
  3419. }
  3420. //-----------------------------------------------------------------------------
  3421. // Shadow update functions
  3422. //-----------------------------------------------------------------------------
  3423. void CClientShadowMgr::UpdateStudioShadow( IClientRenderable *pRenderable, ClientShadowHandle_t handle )
  3424. {
  3425. if( !( m_Shadows[handle].m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) )
  3426. {
  3427. Vector mins, maxs;
  3428. ComputeHierarchicalBounds( pRenderable, mins, maxs );
  3429. ShadowType_t shadowType = GetActualShadowCastType( handle );
  3430. if ( shadowType != SHADOWS_RENDER_TO_TEXTURE )
  3431. {
  3432. BuildOrthoShadow( pRenderable, handle, mins, maxs );
  3433. }
  3434. else
  3435. {
  3436. BuildRenderToTextureShadow( pRenderable, handle, mins, maxs );
  3437. }
  3438. }
  3439. else
  3440. {
  3441. BuildFlashlight( handle );
  3442. }
  3443. }
  3444. void CClientShadowMgr::UpdateBrushShadow( IClientRenderable *pRenderable, ClientShadowHandle_t handle )
  3445. {
  3446. if( !( m_Shadows[handle].m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) )
  3447. {
  3448. // Compute the bounding box in the space of the shadow...
  3449. Vector mins, maxs;
  3450. ComputeHierarchicalBounds( pRenderable, mins, maxs );
  3451. ShadowType_t shadowType = GetActualShadowCastType( handle );
  3452. if ( shadowType != SHADOWS_RENDER_TO_TEXTURE )
  3453. {
  3454. BuildOrthoShadow( pRenderable, handle, mins, maxs );
  3455. }
  3456. else
  3457. {
  3458. BuildRenderToTextureShadow( pRenderable, handle, mins, maxs );
  3459. }
  3460. }
  3461. else
  3462. {
  3463. VPROF_BUDGET( "CClientShadowMgr::UpdateBrushShadow", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  3464. BuildFlashlight( handle );
  3465. }
  3466. }
  3467. #ifdef _DEBUG
  3468. static bool s_bBreak = false;
  3469. void ShadowBreak_f()
  3470. {
  3471. s_bBreak = true;
  3472. }
  3473. static ConCommand r_shadowbreak("r_shadowbreak", ShadowBreak_f);
  3474. #endif // _DEBUG
  3475. bool CClientShadowMgr::WillParentRenderBlobbyShadow( IClientRenderable *pRenderable )
  3476. {
  3477. if ( !pRenderable )
  3478. return false;
  3479. IClientRenderable *pShadowParent = pRenderable->GetShadowParent();
  3480. if ( !pShadowParent )
  3481. return false;
  3482. // If there's *no* shadow casting type, then we want to see if we can render into its parent
  3483. ShadowType_t shadowType = GetActualShadowCastType( pShadowParent );
  3484. if ( shadowType == SHADOWS_NONE )
  3485. return WillParentRenderBlobbyShadow( pShadowParent );
  3486. return shadowType == SHADOWS_SIMPLE;
  3487. }
  3488. //-----------------------------------------------------------------------------
  3489. // Are we the child of a shadow with render-to-texture?
  3490. //-----------------------------------------------------------------------------
  3491. bool CClientShadowMgr::ShouldUseParentShadow( IClientRenderable *pRenderable )
  3492. {
  3493. if ( !pRenderable )
  3494. return false;
  3495. IClientRenderable *pShadowParent = pRenderable->GetShadowParent();
  3496. if ( !pShadowParent )
  3497. return false;
  3498. // Can't render into the parent if the parent is blobby
  3499. ShadowType_t shadowType = GetActualShadowCastType( pShadowParent );
  3500. if ( shadowType == SHADOWS_SIMPLE )
  3501. return false;
  3502. // If there's *no* shadow casting type, then we want to see if we can render into its parent
  3503. if ( shadowType == SHADOWS_NONE )
  3504. return ShouldUseParentShadow( pShadowParent );
  3505. // Here, the parent uses a render-to-texture shadow
  3506. return true;
  3507. }
  3508. //-----------------------------------------------------------------------------
  3509. // Before we render any view, make sure all shadows are re-projected vs world
  3510. //-----------------------------------------------------------------------------
  3511. void CClientShadowMgr::ReprojectShadows()
  3512. {
  3513. // only update shadows once per frame
  3514. Assert( gpGlobals->framecount != m_nPrevFrameCount );
  3515. m_nPrevFrameCount = gpGlobals->framecount;
  3516. VPROF_BUDGET( "CClientShadowMgr::ReprojectShadows", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  3517. MDLCACHE_CRITICAL_SECTION();
  3518. //
  3519. // -- Shadow Depth Textures -----------------------
  3520. //
  3521. {
  3522. // VPROF scope
  3523. //VPROF_BUDGET( "CClientShadowMgr::PreRender", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  3524. // If someone turned shadow depth mapping on but we can't do it, force it off
  3525. if ( r_flashlightdepthtexture.GetBool() && !g_pMaterialSystemHardwareConfig->SupportsShadowDepthTextures() )
  3526. {
  3527. r_flashlightdepthtexture.SetValue( 0 );
  3528. ShutdownDepthTextureShadows();
  3529. }
  3530. bool bDepthTextureActive = r_flashlightdepthtexture.GetBool();
  3531. int nDepthTextureResolution = r_flashlightdepthres.GetInt();
  3532. int nDepthTextureResolutionHigh = r_flashlightdepthreshigh.GetInt();
  3533. if ( ( bDepthTextureActive == true ) && ( m_bDepthTextureActive == true ) &&
  3534. ( nDepthTextureResolution != m_nDepthTextureResolution || nDepthTextureResolutionHigh != m_nDepthTextureResolutionHigh ) )
  3535. {
  3536. // If shadow depth texturing remains on, but resolution changed, shut down and reinitialize depth textures
  3537. ShutdownDepthTextureShadows();
  3538. InitDepthTextureShadows();
  3539. }
  3540. else
  3541. {
  3542. if ( bDepthTextureActive && !m_bDepthTextureActive )
  3543. {
  3544. // If shadow depth texture is now needed but wasn't allocated, allocate it
  3545. // Turning on shadow depth mapping
  3546. materials->ReEnableRenderTargetAllocation_IRealizeIfICallThisAllTexturesWillBeUnloadedAndLoadTimeWillSufferHorribly();
  3547. InitDepthTextureShadows(); // only allocates buffers if they don't already exist
  3548. materials->FinishRenderTargetAllocation();
  3549. }
  3550. }
  3551. }
  3552. //
  3553. // -- Render to Texture Shadows -----------------------
  3554. //
  3555. if ( !r_shadows.GetBool() )
  3556. {
  3557. return;
  3558. }
  3559. bool bRenderToTextureActive = r_shadowrendertotexture.GetBool();
  3560. #ifdef CSTRIKE15
  3561. // Slamming this to always disabled in cstrike, because every map has CSM now and this is causing problems with reloading envmaps from BSP's on the 2nd time through maps with a dedicated server.
  3562. // 3/28 - this is now slammed to 0 in CS:GO's cpu_level.csv
  3563. //if ( g_CascadeLightManager.IsEnabledAndActive() && engine->MapHasLightMapAlphaData() )
  3564. bRenderToTextureActive = false;
  3565. #endif
  3566. if ( !m_RenderToTextureActive && bRenderToTextureActive )
  3567. {
  3568. materials->ReEnableRenderTargetAllocation_IRealizeIfICallThisAllTexturesWillBeUnloadedAndLoadTimeWillSufferHorribly();
  3569. InitRenderToTextureShadows();
  3570. materials->FinishRenderTargetAllocation();
  3571. UpdateAllShadows();
  3572. return;
  3573. }
  3574. if ( m_RenderToTextureActive && !bRenderToTextureActive )
  3575. {
  3576. materials->ReEnableRenderTargetAllocation_IRealizeIfICallThisAllTexturesWillBeUnloadedAndLoadTimeWillSufferHorribly();
  3577. ShutdownRenderToTextureShadows();
  3578. materials->FinishRenderTargetAllocation();
  3579. UpdateAllShadows();
  3580. return;
  3581. }
  3582. m_bUpdatingDirtyShadows = true;
  3583. if ( r_shadow_half_update_rate.GetBool() )
  3584. {
  3585. UpdateDirtyShadowsHalfRate();
  3586. }
  3587. else
  3588. {
  3589. UpdateDirtyShadows();
  3590. }
  3591. m_bUpdatingDirtyShadows = false;
  3592. DestroyQueuedShadows();
  3593. }
  3594. //-----------------------------------------------------------------------------
  3595. // Update all shadows in the dirty shadow set
  3596. //-----------------------------------------------------------------------------
  3597. void CClientShadowMgr::UpdateDirtyShadows()
  3598. {
  3599. if ( r_shadow_debug_spew.GetBool() )
  3600. {
  3601. DevMsg( "dirty shadows: %3d\n", m_DirtyShadows.Count() );
  3602. }
  3603. unsigned short i = m_DirtyShadows.FirstInorder();
  3604. while ( i != m_DirtyShadows.InvalidIndex() )
  3605. {
  3606. MDLCACHE_CRITICAL_SECTION();
  3607. ClientShadowHandle_t& handle = m_DirtyShadows[ i ];
  3608. UpdateDirtyShadow( handle );
  3609. i = m_DirtyShadows.NextInorder(i);
  3610. }
  3611. m_DirtyShadows.RemoveAll();
  3612. // Transparent shadows must remain dirty, since they were not re-projected
  3613. int nCount = m_TransparentShadows.Count();
  3614. for ( int i = 0; i < nCount; ++i )
  3615. {
  3616. m_DirtyShadows.Insert( m_TransparentShadows[i] );
  3617. }
  3618. m_TransparentShadows.RemoveAll();
  3619. }
  3620. //-----------------------------------------------------------------------------
  3621. // Update half the shadows in the dirty shadow set, leaving the rest for next frame
  3622. //-----------------------------------------------------------------------------
  3623. void CClientShadowMgr::UpdateDirtyShadowsHalfRate()
  3624. {
  3625. unsigned short i = m_DirtyShadowsLeftOver.FirstInorder();
  3626. while ( i != m_DirtyShadowsLeftOver.InvalidIndex() )
  3627. {
  3628. MDLCACHE_CRITICAL_SECTION();
  3629. ClientShadowHandle_t& handle = m_DirtyShadowsLeftOver[ i ];
  3630. UpdateDirtyShadow( handle );
  3631. // remove from real dirty set, so that we don't touch shadows twice
  3632. unsigned short nIdx = m_DirtyShadows.Find( handle );
  3633. if ( nIdx != m_DirtyShadows.InvalidIndex() )
  3634. {
  3635. m_DirtyShadows.RemoveAt( nIdx );
  3636. }
  3637. i = m_DirtyShadowsLeftOver.NextInorder( i );
  3638. }
  3639. int nNumShadowsProcessed = m_DirtyShadowsLeftOver.Count();
  3640. int nNumTotalDirtyShadows = nNumShadowsProcessed + m_DirtyShadows.Count();
  3641. int nNumShadowsToProcess = nNumTotalDirtyShadows / 2 + 1;
  3642. if ( r_shadow_debug_spew.GetBool() )
  3643. {
  3644. DevMsg( "dirty shadows: %3d\n", nNumShadowsToProcess );
  3645. }
  3646. nNumShadowsToProcess -= nNumShadowsProcessed;
  3647. nNumShadowsToProcess = MAX( 0, nNumShadowsToProcess );
  3648. nNumShadowsToProcess = MIN( m_DirtyShadows.Count(), nNumShadowsToProcess );
  3649. //DevMsg( "dirty: %2d leftover: %2d total: %2d from main list: %2d processed: %d\n", m_DirtyShadows.Count(), m_DirtyShadowsLeftOver.Count(), nNumTotalDirtyShadows, nNumShadowsToProcess, nNumShadowsProcessed + nNumShadowsToProcess );
  3650. m_DirtyShadowsLeftOver.RemoveAll();
  3651. //
  3652. // process any additional dirty shadows
  3653. //
  3654. i = m_DirtyShadows.FirstInorder();
  3655. for ( int j = 0; j < nNumShadowsToProcess; j++ )
  3656. {
  3657. MDLCACHE_CRITICAL_SECTION();
  3658. ClientShadowHandle_t& handle = m_DirtyShadows[ i ];
  3659. UpdateDirtyShadow( handle );
  3660. i = m_DirtyShadows.NextInorder( i );
  3661. }
  3662. // put the leftover shadows into the leftover bucket
  3663. while ( i != m_DirtyShadows.InvalidIndex() )
  3664. {
  3665. ClientShadowHandle_t& handle = m_DirtyShadows[ i ];
  3666. i = m_DirtyShadows.NextInorder( i );
  3667. m_DirtyShadowsLeftOver.Insert( handle );
  3668. }
  3669. m_DirtyShadows.RemoveAll();
  3670. // Transparent shadows must remain dirty, since they were not re-projected
  3671. int nCount = m_TransparentShadows.Count();
  3672. for ( int i = 0; i < nCount; ++i )
  3673. {
  3674. m_DirtyShadows.Insert( m_TransparentShadows[i] );
  3675. }
  3676. m_TransparentShadows.RemoveAll();
  3677. }
  3678. //-----------------------------------------------------------------------------
  3679. // Updates a single dirty shadow
  3680. //-----------------------------------------------------------------------------
  3681. void CClientShadowMgr::UpdateDirtyShadow( ClientShadowHandle_t handle )
  3682. {
  3683. Assert( m_Shadows.IsValidIndex( handle ) );
  3684. if ( IsShadowingFromWorldLights() )
  3685. {
  3686. UpdateShadowDirectionFromLocalLightSource( handle );
  3687. }
  3688. UpdateProjectedTextureInternal( handle, false );
  3689. }
  3690. //-----------------------------------------------------------------------------
  3691. // Convar callback
  3692. //-----------------------------------------------------------------------------
  3693. void HalfUpdateRateCallback( IConVar *var, const char *pOldValue, float flOldValue )
  3694. {
  3695. s_ClientShadowMgr.FlushLeftOverDirtyShadows();
  3696. }
  3697. //-----------------------------------------------------------------------------
  3698. // Flushes any leftover dirty shadows into the main dirty shadow set
  3699. //-----------------------------------------------------------------------------
  3700. void CClientShadowMgr::FlushLeftOverDirtyShadows()
  3701. {
  3702. unsigned short i = m_DirtyShadowsLeftOver.FirstInorder();
  3703. while ( i != m_DirtyShadowsLeftOver.InvalidIndex() )
  3704. {
  3705. m_DirtyShadows.InsertIfNotFound( m_DirtyShadowsLeftOver[ i ] );
  3706. i = m_DirtyShadowsLeftOver.NextInorder(i);
  3707. }
  3708. m_DirtyShadowsLeftOver.RemoveAll();
  3709. }
  3710. //-----------------------------------------------------------------------------
  3711. // Gets the entity whose shadow this shadow will render into
  3712. //-----------------------------------------------------------------------------
  3713. IClientRenderable *CClientShadowMgr::GetParentShadowEntity( ClientShadowHandle_t handle )
  3714. {
  3715. ClientShadow_t& shadow = m_Shadows[handle];
  3716. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity );
  3717. if ( pRenderable )
  3718. {
  3719. if ( ShouldUseParentShadow( pRenderable ) )
  3720. {
  3721. IClientRenderable *pParent = pRenderable->GetShadowParent();
  3722. while ( GetActualShadowCastType( pParent ) == SHADOWS_NONE )
  3723. {
  3724. pParent = pParent->GetShadowParent();
  3725. Assert( pParent );
  3726. }
  3727. return pParent;
  3728. }
  3729. }
  3730. return NULL;
  3731. }
  3732. //-----------------------------------------------------------------------------
  3733. // Marks a shadow as needing re-projection
  3734. //-----------------------------------------------------------------------------
  3735. CThreadFastMutex g_DirtyListAddMutex; // This should be made lock free? [3/19/2008 tom]
  3736. void CClientShadowMgr::AddToDirtyShadowList( ClientShadowHandle_t handle, bool bForce )
  3737. {
  3738. // Don't add to the dirty shadow list while we're iterating over it
  3739. // The only way this can happen is if a child is being rendered into a parent
  3740. // shadow, and we don't need it to be added to the dirty list in that case.
  3741. if ( m_bUpdatingDirtyShadows )
  3742. return;
  3743. if ( handle == CLIENTSHADOW_INVALID_HANDLE )
  3744. return;
  3745. AUTO_LOCK( g_DirtyListAddMutex );
  3746. Assert( m_DirtyShadows.Find( handle ) == m_DirtyShadows.InvalidIndex() );
  3747. m_DirtyShadows.Insert( handle );
  3748. // This pretty much guarantees we'll recompute the shadow
  3749. if ( bForce )
  3750. {
  3751. m_Shadows[handle].m_LastAngles.Init( FLT_MAX, FLT_MAX, FLT_MAX );
  3752. }
  3753. // If we use our parent shadow, then it's dirty too...
  3754. IClientRenderable *pParent = GetParentShadowEntity( handle );
  3755. if ( pParent )
  3756. {
  3757. AddToDirtyShadowList( pParent, bForce );
  3758. }
  3759. }
  3760. //-----------------------------------------------------------------------------
  3761. // Marks a shadow as needing re-projection
  3762. //-----------------------------------------------------------------------------
  3763. void CClientShadowMgr::AddToDirtyShadowList( IClientRenderable *pRenderable, bool bForce )
  3764. {
  3765. // Don't add to the dirty shadow list while we're iterating over it
  3766. // The only way this can happen is if a child is being rendered into a parent
  3767. // shadow, and we don't need it to be added to the dirty list in that case.
  3768. if ( m_bUpdatingDirtyShadows )
  3769. return;
  3770. AUTO_LOCK( g_DirtyListAddMutex );
  3771. // Are we already in the dirty list?
  3772. if ( pRenderable->IsShadowDirty( ) )
  3773. return;
  3774. ClientShadowHandle_t handle = pRenderable->GetShadowHandle();
  3775. if ( handle == CLIENTSHADOW_INVALID_HANDLE )
  3776. return;
  3777. #ifdef _DEBUG
  3778. // Make sure everything's consistent
  3779. if ( handle != CLIENTSHADOW_INVALID_HANDLE )
  3780. {
  3781. IClientRenderable *pShadowRenderable = ClientEntityList().GetClientRenderableFromHandle( m_Shadows[handle].m_Entity );
  3782. Assert( pRenderable == pShadowRenderable );
  3783. }
  3784. #endif
  3785. pRenderable->MarkShadowDirty( true );
  3786. AddToDirtyShadowList( handle, bForce );
  3787. }
  3788. //-----------------------------------------------------------------------------
  3789. // Marks the render-to-texture shadow as needing to be re-rendered
  3790. //-----------------------------------------------------------------------------
  3791. void CClientShadowMgr::MarkRenderToTextureShadowDirty( ClientShadowHandle_t handle )
  3792. {
  3793. // Don't add bogus handles!
  3794. if (handle != CLIENTSHADOW_INVALID_HANDLE)
  3795. {
  3796. // Mark the shadow has having a dirty renter-to-texture
  3797. ClientShadow_t& shadow = m_Shadows[handle];
  3798. shadow.m_Flags |= SHADOW_FLAGS_TEXTURE_DIRTY;
  3799. // If we use our parent shadow, then it's dirty too...
  3800. IClientRenderable *pParent = GetParentShadowEntity( handle );
  3801. if ( pParent )
  3802. {
  3803. ClientShadowHandle_t parentHandle = pParent->GetShadowHandle();
  3804. if ( parentHandle != CLIENTSHADOW_INVALID_HANDLE )
  3805. {
  3806. m_Shadows[parentHandle].m_Flags |= SHADOW_FLAGS_TEXTURE_DIRTY;
  3807. }
  3808. }
  3809. }
  3810. }
  3811. //-----------------------------------------------------------------------------
  3812. // Update a shadow
  3813. //-----------------------------------------------------------------------------
  3814. void CClientShadowMgr::UpdateShadow( ClientShadowHandle_t handle, bool force )
  3815. {
  3816. ClientShadow_t& shadow = m_Shadows[handle];
  3817. // Get the client entity....
  3818. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity );
  3819. if ( !pRenderable )
  3820. {
  3821. // Retire the shadow if the entity is gone
  3822. DestroyShadow( handle );
  3823. return;
  3824. }
  3825. if ( r_disable_update_shadow.GetBool() )
  3826. {
  3827. pRenderable->MarkShadowDirty( false );
  3828. shadowmgr->EnableShadow( shadow.m_ShadowHandle, false );
  3829. return;
  3830. }
  3831. // Don't bother if there's no model on the renderable
  3832. if ( !pRenderable->GetModel() )
  3833. {
  3834. pRenderable->MarkShadowDirty( false );
  3835. return;
  3836. }
  3837. // Mark shadow as dirty if no split screen user needs it
  3838. bool bShouldDraw = false;
  3839. FOR_EACH_VALID_SPLITSCREEN_PLAYER( i )
  3840. {
  3841. if ( pRenderable->ShouldDrawForSplitScreenUser( i ) )
  3842. {
  3843. bShouldDraw = true;
  3844. break;
  3845. }
  3846. }
  3847. if ( !bShouldDraw )
  3848. {
  3849. pRenderable->MarkShadowDirty( false );
  3850. return;
  3851. }
  3852. // FIXME: NOTE! Because this is called from PreRender, the falloff bias is
  3853. // off by a frame. We could move the code in PreRender to occur after world
  3854. // list building is done to fix this issue.
  3855. // Don't bother with it if the shadow is totally transparent
  3856. if ( shadow.m_FalloffBias == 255 )
  3857. {
  3858. if ( !r_shadow_deferred.GetBool() )
  3859. {
  3860. shadowmgr->EnableShadow( shadow.m_ShadowHandle, false );
  3861. }
  3862. m_TransparentShadows.AddToTail( handle );
  3863. return;
  3864. }
  3865. #ifdef _DEBUG
  3866. if (s_bBreak)
  3867. {
  3868. s_bBreak = false;
  3869. }
  3870. #endif
  3871. // Hierarchical children shouldn't be projecting shadows...
  3872. // Check to see if it's a child of an entity with a render-to-texture shadow...
  3873. if ( ShouldUseParentShadow( pRenderable ) || WillParentRenderBlobbyShadow( pRenderable ) )
  3874. {
  3875. if ( !r_shadow_deferred.GetBool() )
  3876. {
  3877. shadowmgr->EnableShadow( shadow.m_ShadowHandle, false );
  3878. }
  3879. pRenderable->MarkShadowDirty( false );
  3880. return;
  3881. }
  3882. if ( !r_shadow_deferred.GetBool() )
  3883. {
  3884. shadowmgr->EnableShadow( shadow.m_ShadowHandle, true );
  3885. }
  3886. // Figure out if the shadow moved...
  3887. // Even though we have dirty bits, some entities
  3888. // never clear those dirty bits
  3889. const Vector& origin = pRenderable->GetRenderOrigin();
  3890. const QAngle& angles = pRenderable->GetRenderAngles();
  3891. if (force || (origin != shadow.m_LastOrigin) || (angles != shadow.m_LastAngles))
  3892. {
  3893. // Store off the new pos/orientation
  3894. VectorCopy( origin, shadow.m_LastOrigin );
  3895. VectorCopy( angles, shadow.m_LastAngles );
  3896. CMatRenderContextPtr pRenderContext( materials );
  3897. const model_t *pModel = pRenderable->GetModel();
  3898. MaterialFogMode_t fogMode = pRenderContext->GetFogMode();
  3899. pRenderContext->FogMode( MATERIAL_FOG_NONE );
  3900. switch( modelinfo->GetModelType( pModel ) )
  3901. {
  3902. case mod_brush:
  3903. UpdateBrushShadow( pRenderable, handle );
  3904. break;
  3905. case mod_studio:
  3906. UpdateStudioShadow( pRenderable, handle );
  3907. break;
  3908. default:
  3909. // Shouldn't get here if not a brush or studio
  3910. Assert(0);
  3911. break;
  3912. }
  3913. pRenderContext->FogMode( fogMode );
  3914. }
  3915. // NOTE: We can't do this earlier because pEnt->GetRenderOrigin() can
  3916. // provoke a recomputation of render origin, which, for aiments, can cause everything
  3917. // to be marked as dirty. So don't clear the flag until this point.
  3918. pRenderable->MarkShadowDirty( false );
  3919. }
  3920. //-----------------------------------------------------------------------------
  3921. // Update a shadow
  3922. //-----------------------------------------------------------------------------
  3923. void CClientShadowMgr::UpdateProjectedTextureInternal( ClientShadowHandle_t handle, bool force )
  3924. {
  3925. ClientShadow_t& shadow = m_Shadows[handle];
  3926. if( ( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) != 0 )
  3927. {
  3928. VPROF_BUDGET( "CClientShadowMgr::UpdateProjectedTextureInternal", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  3929. Assert( ( shadow.m_Flags & SHADOW_FLAGS_SHADOW ) == 0 );
  3930. ClientShadow_t& shadow = m_Shadows[handle];
  3931. shadowmgr->EnableShadow( shadow.m_ShadowHandle, true );
  3932. // FIXME: What's the difference between brush and model shadows for light projectors? Answer: nothing.
  3933. UpdateBrushShadow( NULL, handle );
  3934. }
  3935. else
  3936. {
  3937. Assert( shadow.m_Flags & SHADOW_FLAGS_SHADOW );
  3938. Assert( ( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) == 0 );
  3939. UpdateShadow( handle, force );
  3940. }
  3941. }
  3942. //-----------------------------------------------------------------------------
  3943. // Update a shadow
  3944. //-----------------------------------------------------------------------------
  3945. void CClientShadowMgr::UpdateProjectedTexture( ClientShadowHandle_t handle, bool force )
  3946. {
  3947. VPROF_BUDGET( "CClientShadowMgr::UpdateProjectedTexture", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  3948. if ( handle == CLIENTSHADOW_INVALID_HANDLE )
  3949. return;
  3950. // NOTE: This can only work for flashlights, since UpdateProjectedTextureInternal
  3951. // depends on the falloff offset to cull shadows.
  3952. ClientShadow_t &shadow = m_Shadows[ handle ];
  3953. if( ( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) == 0 )
  3954. {
  3955. Warning( "CClientShadowMgr::UpdateProjectedTexture can only be used with flashlights!\n" );
  3956. return;
  3957. }
  3958. UpdateProjectedTextureInternal( handle, force );
  3959. RemoveShadowFromDirtyList( handle );
  3960. }
  3961. //-----------------------------------------------------------------------------
  3962. // Computes bounding sphere
  3963. //-----------------------------------------------------------------------------
  3964. void CClientShadowMgr::ComputeBoundingSphere( IClientRenderable* pRenderable, Vector& origin, float& radius )
  3965. {
  3966. Assert( pRenderable );
  3967. Vector mins, maxs;
  3968. pRenderable->GetShadowRenderBounds( mins, maxs, GetActualShadowCastType( pRenderable ) );
  3969. Vector size;
  3970. VectorSubtract( maxs, mins, size );
  3971. radius = size.Length() * 0.5f;
  3972. // Compute centroid (local space)
  3973. Vector centroid;
  3974. VectorAdd( mins, maxs, centroid );
  3975. centroid *= 0.5f;
  3976. // Transform centroid into world space
  3977. Vector vec[3];
  3978. AngleVectors( pRenderable->GetRenderAngles(), &vec[0], &vec[1], &vec[2] );
  3979. vec[1] *= -1.0f;
  3980. VectorCopy( pRenderable->GetRenderOrigin(), origin );
  3981. VectorMA( origin, centroid.x, vec[0], origin );
  3982. VectorMA( origin, centroid.y, vec[1], origin );
  3983. VectorMA( origin, centroid.z, vec[2], origin );
  3984. }
  3985. //-----------------------------------------------------------------------------
  3986. // Computes a rough AABB encompassing the volume of the shadow
  3987. //-----------------------------------------------------------------------------
  3988. void CClientShadowMgr::ComputeShadowBBox( IClientRenderable *pRenderable, ClientShadowHandle_t shadowHandle, const Vector &vecAbsCenter, float flRadius, Vector *pAbsMins, Vector *pAbsMaxs )
  3989. {
  3990. // This is *really* rough. Basically we simply determine the
  3991. // maximum shadow casting length and extrude the box by that distance
  3992. Vector vecShadowDir = GetShadowDirection( shadowHandle );
  3993. for (int i = 0; i < 3; ++i)
  3994. {
  3995. float flShadowCastDistance = GetShadowDistance( pRenderable );
  3996. float flDist = flShadowCastDistance * vecShadowDir[i];
  3997. if (vecShadowDir[i] < 0)
  3998. {
  3999. (*pAbsMins)[i] = vecAbsCenter[i] - flRadius + flDist;
  4000. (*pAbsMaxs)[i] = vecAbsCenter[i] + flRadius;
  4001. }
  4002. else
  4003. {
  4004. (*pAbsMins)[i] = vecAbsCenter[i] - flRadius;
  4005. (*pAbsMaxs)[i] = vecAbsCenter[i] + flRadius + flDist;
  4006. }
  4007. }
  4008. }
  4009. //-----------------------------------------------------------------------------
  4010. // Compute a separating axis...
  4011. //-----------------------------------------------------------------------------
  4012. bool CClientShadowMgr::ComputeSeparatingPlane( IClientRenderable* pRend1, IClientRenderable* pRend2, cplane_t* pPlane )
  4013. {
  4014. Vector min1, max1, min2, max2;
  4015. pRend1->GetShadowRenderBounds( min1, max1, GetActualShadowCastType( pRend1 ) );
  4016. pRend2->GetShadowRenderBounds( min2, max2, GetActualShadowCastType( pRend2 ) );
  4017. return ::ComputeSeparatingPlane(
  4018. pRend1->GetRenderOrigin(), pRend1->GetRenderAngles(), min1, max1,
  4019. pRend2->GetRenderOrigin(), pRend2->GetRenderAngles(), min2, max2,
  4020. 3.0f, pPlane );
  4021. }
  4022. //-----------------------------------------------------------------------------
  4023. // Cull shadows based on rough bounding volumes
  4024. //-----------------------------------------------------------------------------
  4025. bool CClientShadowMgr::CullReceiver( ClientShadowHandle_t handle, IClientRenderable* pRenderable,
  4026. IClientRenderable* pSourceRenderable )
  4027. {
  4028. // check flags here instead and assert !pSourceRenderable
  4029. if( m_Shadows[handle].m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) )
  4030. {
  4031. VPROF_BUDGET( "CClientShadowMgr::CullReceiver", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  4032. Assert( !pSourceRenderable );
  4033. const Frustum_t &frustum = shadowmgr->GetFlashlightFrustum( m_Shadows[handle].m_ShadowHandle );
  4034. Vector mins, maxs;
  4035. pRenderable->GetRenderBoundsWorldspace( mins, maxs );
  4036. return frustum.CullBox( mins, maxs );
  4037. }
  4038. Assert( pSourceRenderable );
  4039. // Compute a bounding sphere for the renderable
  4040. Vector origin;
  4041. float radius;
  4042. ComputeBoundingSphere( pRenderable, origin, radius );
  4043. // Transform the sphere center into the space of the shadow
  4044. Vector localOrigin;
  4045. const ClientShadow_t& shadow = m_Shadows[handle];
  4046. Vector3DMultiplyPosition( shadow.m_WorldToShadow, origin, localOrigin );
  4047. // Compute a rough bounding box for the shadow (in shadow space)
  4048. Vector shadowMin, shadowMax;
  4049. shadowMin.Init( -shadow.m_WorldSize.x * 0.5f, -shadow.m_WorldSize.y * 0.5f, 0 );
  4050. shadowMax.Init( shadow.m_WorldSize.x * 0.5f, shadow.m_WorldSize.y * 0.5f, shadow.m_MaxDist );
  4051. // If the bounding sphere doesn't intersect with the shadow volume, cull
  4052. if (!IsBoxIntersectingSphere( shadowMin, shadowMax, localOrigin, radius ))
  4053. return true;
  4054. Vector originSource;
  4055. float radiusSource;
  4056. ComputeBoundingSphere( pSourceRenderable, originSource, radiusSource );
  4057. // Fast check for separating plane...
  4058. bool foundSeparatingPlane = false;
  4059. cplane_t plane;
  4060. if (!IsSphereIntersectingSphere( originSource, radiusSource, origin, radius ))
  4061. {
  4062. foundSeparatingPlane = true;
  4063. // the plane normal doesn't need to be normalized...
  4064. VectorSubtract( origin, originSource, plane.normal );
  4065. }
  4066. else
  4067. {
  4068. foundSeparatingPlane = ComputeSeparatingPlane( pRenderable, pSourceRenderable, &plane );
  4069. }
  4070. if (foundSeparatingPlane)
  4071. {
  4072. // Compute which side of the plane the renderable is on..
  4073. Vector vecShadowDir = GetShadowDirection( handle );
  4074. float shadowDot = DotProduct( vecShadowDir, plane.normal );
  4075. float receiverDot = DotProduct( plane.normal, origin );
  4076. float sourceDot = DotProduct( plane.normal, originSource );
  4077. if (shadowDot > 0.0f)
  4078. {
  4079. if (receiverDot <= sourceDot)
  4080. {
  4081. // Vector dest;
  4082. // VectorMA( pSourceRenderable->GetRenderOrigin(), 50, plane.normal, dest );
  4083. // debugoverlay->AddLineOverlay( pSourceRenderable->GetRenderOrigin(), dest, 255, 255, 0, true, 1.0f );
  4084. return true;
  4085. }
  4086. else
  4087. {
  4088. // Vector dest;
  4089. // VectorMA( pSourceRenderable->GetRenderOrigin(), 50, plane.normal, dest );
  4090. // debugoverlay->AddLineOverlay( pSourceRenderable->GetRenderOrigin(), dest, 255, 0, 0, true, 1.0f );
  4091. }
  4092. }
  4093. else
  4094. {
  4095. if (receiverDot >= sourceDot)
  4096. {
  4097. // Vector dest;
  4098. // VectorMA( pSourceRenderable->GetRenderOrigin(), -50, plane.normal, dest );
  4099. // debugoverlay->AddLineOverlay( pSourceRenderable->GetRenderOrigin(), dest, 255, 255, 0, true, 1.0f );
  4100. return true;
  4101. }
  4102. else
  4103. {
  4104. // Vector dest;
  4105. // VectorMA( pSourceRenderable->GetRenderOrigin(), 50, plane.normal, dest );
  4106. // debugoverlay->AddLineOverlay( pSourceRenderable->GetRenderOrigin(), dest, 255, 0, 0, true, 1.0f );
  4107. }
  4108. }
  4109. }
  4110. // No additional clip planes? ok then it's a valid receiver
  4111. /*
  4112. if (shadow.m_ClipPlaneCount == 0)
  4113. return false;
  4114. // Check the additional cull planes
  4115. int i;
  4116. for ( i = 0; i < shadow.m_ClipPlaneCount; ++i)
  4117. {
  4118. // Fast sphere cull
  4119. if (DotProduct( origin, shadow.m_ClipPlane[i] ) - radius > shadow.m_ClipDist[i])
  4120. return true;
  4121. }
  4122. // More expensive box on plane side cull...
  4123. Vector vec[3];
  4124. Vector mins, maxs;
  4125. cplane_t plane;
  4126. AngleVectors( pRenderable->GetRenderAngles(), &vec[0], &vec[1], &vec[2] );
  4127. pRenderable->GetBounds( mins, maxs );
  4128. for ( i = 0; i < shadow.m_ClipPlaneCount; ++i)
  4129. {
  4130. // Transform the plane into the space of the receiver
  4131. plane.normal.x = DotProduct( vec[0], shadow.m_ClipPlane[i] );
  4132. plane.normal.y = DotProduct( vec[1], shadow.m_ClipPlane[i] );
  4133. plane.normal.z = DotProduct( vec[2], shadow.m_ClipPlane[i] );
  4134. plane.dist = shadow.m_ClipDist[i] - DotProduct( shadow.m_ClipPlane[i], pRenderable->GetRenderOrigin() );
  4135. // If the box is on the front side of the plane, we're done.
  4136. if (BoxOnPlaneSide2( mins, maxs, &plane, 3.0f ) == 1)
  4137. return true;
  4138. }
  4139. */
  4140. return false;
  4141. }
  4142. //-----------------------------------------------------------------------------
  4143. // deals with shadows being added to shadow receivers
  4144. //-----------------------------------------------------------------------------
  4145. void CClientShadowMgr::AddShadowToReceiver( ClientShadowHandle_t handle,
  4146. IClientRenderable* pRenderable, ShadowReceiver_t type )
  4147. {
  4148. ClientShadow_t &shadow = m_Shadows[handle];
  4149. // Don't add a shadow cast by an object to itself...
  4150. IClientRenderable* pSourceRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity );
  4151. // NOTE: if pSourceRenderable == NULL, the source is probably a flashlight since there is no entity.
  4152. if (pSourceRenderable == pRenderable)
  4153. return;
  4154. // Don't bother if this renderable doesn't receive shadows or light from flashlights
  4155. if( !pRenderable->ShouldReceiveProjectedTextures( SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK ) )
  4156. return;
  4157. // Cull if the origin is on the wrong side of a shadow clip plane....
  4158. if ( CullReceiver( handle, pRenderable, pSourceRenderable ) )
  4159. return;
  4160. // Do different things depending on the receiver type
  4161. switch( type )
  4162. {
  4163. case SHADOW_RECEIVER_BRUSH_MODEL:
  4164. if( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) )
  4165. {
  4166. VPROF_BUDGET( "CClientShadowMgr::AddShadowToReceiver", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  4167. if( (!shadow.m_hTargetEntity) || IsFlashlightTarget( handle, pRenderable ) )
  4168. {
  4169. shadowmgr->AddShadowToBrushModel( shadow.m_ShadowHandle,
  4170. const_cast<model_t*>(pRenderable->GetModel()),
  4171. pRenderable->GetRenderOrigin(), pRenderable->GetRenderAngles() );
  4172. }
  4173. }
  4174. else
  4175. {
  4176. if ( !r_shadow_deferred.GetBool() )
  4177. {
  4178. shadowmgr->AddShadowToBrushModel( shadow.m_ShadowHandle,
  4179. const_cast<model_t*>(pRenderable->GetModel()),
  4180. pRenderable->GetRenderOrigin(), pRenderable->GetRenderAngles() );
  4181. }
  4182. }
  4183. break;
  4184. case SHADOW_RECEIVER_STATIC_PROP:
  4185. // Don't add shadows to props if we're not using render-to-texture
  4186. if ( GetActualShadowCastType( handle ) == SHADOWS_RENDER_TO_TEXTURE )
  4187. {
  4188. if ( !r_shadow_deferred.GetBool() )
  4189. {
  4190. // Also don't add them unless an NPC or player casts them..
  4191. // They are wickedly expensive!!!
  4192. C_BaseEntity *pEnt = pSourceRenderable->GetIClientUnknown()->GetBaseEntity();
  4193. if ( pEnt && ( pEnt->GetFlags() & (FL_NPC | FL_CLIENT)) )
  4194. {
  4195. staticpropmgr->AddShadowToStaticProp( shadow.m_ShadowHandle, pRenderable );
  4196. }
  4197. }
  4198. }
  4199. else if( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) )
  4200. {
  4201. VPROF_BUDGET( "CClientShadowMgr::AddShadowToReceiver", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  4202. if( (!shadow.m_hTargetEntity) || IsFlashlightTarget( handle, pRenderable ) )
  4203. {
  4204. staticpropmgr->AddShadowToStaticProp( shadow.m_ShadowHandle, pRenderable );
  4205. }
  4206. }
  4207. break;
  4208. case SHADOW_RECEIVER_STUDIO_MODEL:
  4209. if( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) )
  4210. {
  4211. VPROF_BUDGET( "CClientShadowMgr::AddShadowToReceiver", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  4212. if( (!shadow.m_hTargetEntity) || IsFlashlightTarget( handle, pRenderable ) )
  4213. {
  4214. pRenderable->CreateModelInstance();
  4215. shadowmgr->AddShadowToModel( shadow.m_ShadowHandle, pRenderable->GetModelInstance() );
  4216. }
  4217. }
  4218. break;
  4219. // default:
  4220. }
  4221. }
  4222. //-----------------------------------------------------------------------------
  4223. // deals with shadows being added to shadow receivers
  4224. //-----------------------------------------------------------------------------
  4225. void CClientShadowMgr::RemoveAllShadowsFromReceiver(
  4226. IClientRenderable* pRenderable, ShadowReceiver_t type )
  4227. {
  4228. // Don't bother if this renderable doesn't receive shadows
  4229. if ( !pRenderable->ShouldReceiveProjectedTextures( SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK ) )
  4230. return;
  4231. // Do different things depending on the receiver type
  4232. switch( type )
  4233. {
  4234. case SHADOW_RECEIVER_BRUSH_MODEL:
  4235. {
  4236. model_t* pModel = const_cast<model_t*>(pRenderable->GetModel());
  4237. shadowmgr->RemoveAllShadowsFromBrushModel( pModel );
  4238. }
  4239. break;
  4240. case SHADOW_RECEIVER_STATIC_PROP:
  4241. staticpropmgr->RemoveAllShadowsFromStaticProp(pRenderable);
  4242. break;
  4243. case SHADOW_RECEIVER_STUDIO_MODEL:
  4244. if( pRenderable && pRenderable->GetModelInstance() != MODEL_INSTANCE_INVALID )
  4245. {
  4246. Assert(shadowmgr);
  4247. shadowmgr->RemoveAllShadowsFromModel( pRenderable->GetModelInstance() );
  4248. }
  4249. break;
  4250. // default:
  4251. // // FIXME: How do deal with this stuff? Add a method to IClientRenderable?
  4252. // C_BaseEntity* pEnt = static_cast<C_BaseEntity*>(pRenderable);
  4253. // pEnt->RemoveAllShadows();
  4254. }
  4255. }
  4256. //-----------------------------------------------------------------------------
  4257. // Computes + sets the render-to-texture texcoords
  4258. //-----------------------------------------------------------------------------
  4259. void CClientShadowMgr::SetRenderToTextureShadowTexCoords( ShadowHandle_t handle, int x, int y, int w, int h )
  4260. {
  4261. // Let the shadow mgr know about the texture coordinates...
  4262. // That way it'll be able to batch rendering better.
  4263. int textureW, textureH;
  4264. m_ShadowAllocator.GetTotalTextureSize( textureW, textureH );
  4265. // Go in a half-pixel to avoid blending with neighboring textures..
  4266. float u, v, du, dv;
  4267. u = ((float)x + 0.5f) / (float)textureW;
  4268. v = ((float)y + 0.5f) / (float)textureH;
  4269. du = ((float)w - 1) / (float)textureW;
  4270. dv = ((float)h - 1) / (float)textureH;
  4271. shadowmgr->SetShadowTexCoord( handle, u, v, du, dv );
  4272. }
  4273. void CClientShadowMgr::SetRenderToTextureShadowTexCoords( ClientShadow_t& shadow, int x, int y, int w, int h )
  4274. {
  4275. // Let the shadow mgr know about the texture coordinates...
  4276. // That way it'll be able to batch rendering better.
  4277. int textureW, textureH;
  4278. m_ShadowAllocator.GetTotalTextureSize( textureW, textureH );
  4279. // Go in a half-pixel to avoid blending with neighboring textures..
  4280. float u, v, du, dv;
  4281. u = ((float)x + 0.5f) / (float)textureW;
  4282. v = ((float)y + 0.5f) / (float)textureH;
  4283. du = ((float)w - 1) / (float)textureW;
  4284. dv = ((float)h - 1) / (float)textureH;
  4285. shadow.m_TexCoordOffset.Init( u, v );
  4286. shadow.m_TexCoordScale.Init( du, dv );
  4287. }
  4288. //-----------------------------------------------------------------------------
  4289. // Setup all children shadows
  4290. //-----------------------------------------------------------------------------
  4291. bool CClientShadowMgr::BuildSetupShadowHierarchy( IClientRenderable *pRenderable, const ClientShadow_t &shadow, bool bChild )
  4292. {
  4293. bool bDrewTexture = false;
  4294. // Stop traversing when we hit a blobby shadow
  4295. ShadowType_t shadowType = GetActualShadowCastType( pRenderable );
  4296. if ( pRenderable && shadowType == SHADOWS_SIMPLE )
  4297. return false;
  4298. if ( !pRenderable || shadowType != SHADOWS_NONE )
  4299. {
  4300. bool bDrawModelShadow;
  4301. if ( !bChild )
  4302. {
  4303. bDrawModelShadow = ((shadow.m_Flags & SHADOW_FLAGS_BRUSH_MODEL) == 0);
  4304. }
  4305. else
  4306. {
  4307. int nModelType = modelinfo->GetModelType( pRenderable->GetModel() );
  4308. bDrawModelShadow = nModelType == mod_studio;
  4309. }
  4310. if ( bDrawModelShadow )
  4311. {
  4312. C_BaseEntity *pEntity = pRenderable->GetIClientUnknown()->GetBaseEntity();
  4313. if ( pEntity )
  4314. {
  4315. if ( pEntity->IsNPC() )
  4316. {
  4317. s_NPCShadowBoneSetups.AddToTail( assert_cast<C_BaseAnimating *>( pEntity ) );
  4318. }
  4319. else if ( pEntity->GetBaseAnimating() )
  4320. {
  4321. s_NonNPCShadowBoneSetups.AddToTail( assert_cast<C_BaseAnimating *>( pEntity ) );
  4322. }
  4323. }
  4324. bDrewTexture = true;
  4325. }
  4326. }
  4327. if ( !pRenderable )
  4328. return bDrewTexture;
  4329. IClientRenderable *pChild;
  4330. for ( pChild = pRenderable->FirstShadowChild(); pChild; pChild = pChild->NextShadowPeer() )
  4331. {
  4332. if ( BuildSetupShadowHierarchy( pChild, shadow, true ) )
  4333. {
  4334. bDrewTexture = true;
  4335. }
  4336. }
  4337. return bDrewTexture;
  4338. }
  4339. //-----------------------------------------------------------------------------
  4340. // Draws all children shadows into our own
  4341. //-----------------------------------------------------------------------------
  4342. bool CClientShadowMgr::DrawShadowHierarchy( IClientRenderable *pRenderable, const ClientShadow_t &shadow, bool bChild )
  4343. {
  4344. bool bDrewTexture = false;
  4345. // Stop traversing when we hit a blobby shadow
  4346. ShadowType_t shadowType = GetActualShadowCastType( pRenderable );
  4347. if ( pRenderable && shadowType == SHADOWS_SIMPLE )
  4348. return false;
  4349. if ( !pRenderable || shadowType != SHADOWS_NONE )
  4350. {
  4351. bool bDrawModelShadow;
  4352. bool bDrawBrushShadow;
  4353. if ( !bChild )
  4354. {
  4355. bDrawModelShadow = ((shadow.m_Flags & SHADOW_FLAGS_BRUSH_MODEL) == 0);
  4356. bDrawBrushShadow = !bDrawModelShadow;
  4357. }
  4358. else
  4359. {
  4360. int nModelType = modelinfo->GetModelType( pRenderable->GetModel() );
  4361. bDrawModelShadow = nModelType == mod_studio;
  4362. bDrawBrushShadow = nModelType == mod_brush;
  4363. }
  4364. if ( pRenderable && ( shadow.m_Flags & SHADOW_FLAGS_CUSTOM_DRAW ) )
  4365. {
  4366. RenderableInstance_t instance;
  4367. instance.m_nAlpha = 255;
  4368. pRenderable->DrawModel( STUDIO_SHADOWTEXTURE, instance );
  4369. bDrewTexture = true;
  4370. }
  4371. else if ( bDrawModelShadow )
  4372. {
  4373. CMatRenderContextPtr pRenderContext( materials );
  4374. CMatRenderDataReference lock( pRenderContext );
  4375. DrawModelInfo_t info;
  4376. matrix3x4a_t *pBoneToWorld = modelrender->DrawModelShadowSetup( pRenderable, pRenderable->GetBody(), pRenderable->GetSkin(), &info );
  4377. if ( pBoneToWorld )
  4378. {
  4379. modelrender->DrawModelShadow( pRenderable, info, pBoneToWorld );
  4380. }
  4381. bDrewTexture = true;
  4382. }
  4383. else if ( bDrawBrushShadow )
  4384. {
  4385. render->DrawBrushModelShadow( pRenderable );
  4386. bDrewTexture = true;
  4387. }
  4388. }
  4389. if ( !pRenderable )
  4390. return bDrewTexture;
  4391. IClientRenderable *pChild;
  4392. for ( pChild = pRenderable->FirstShadowChild(); pChild; pChild = pChild->NextShadowPeer() )
  4393. {
  4394. if ( DrawShadowHierarchy( pChild, shadow, true ) )
  4395. {
  4396. bDrewTexture = true;
  4397. }
  4398. }
  4399. return bDrewTexture;
  4400. }
  4401. //-----------------------------------------------------------------------------
  4402. // This gets called with every shadow that potentially will need to re-render
  4403. //-----------------------------------------------------------------------------
  4404. bool CClientShadowMgr::BuildSetupListForRenderToTextureShadow( unsigned short clientShadowHandle, float flArea )
  4405. {
  4406. ClientShadow_t& shadow = m_Shadows[clientShadowHandle];
  4407. bool bDirtyTexture = (shadow.m_Flags & SHADOW_FLAGS_TEXTURE_DIRTY) != 0;
  4408. bool bNeedsRedraw = m_ShadowAllocator.UseTexture( shadow.m_ShadowTexture, bDirtyTexture, flArea );
  4409. if ( bNeedsRedraw || bDirtyTexture )
  4410. {
  4411. shadow.m_Flags |= SHADOW_FLAGS_TEXTURE_DIRTY;
  4412. if ( !m_ShadowAllocator.HasValidTexture( shadow.m_ShadowTexture ) )
  4413. return false;
  4414. // shadow to be redrawn; for now, we'll always do it.
  4415. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity );
  4416. if ( BuildSetupShadowHierarchy( pRenderable, shadow ) )
  4417. return true;
  4418. }
  4419. return false;
  4420. }
  4421. //-----------------------------------------------------------------------------
  4422. // This gets called with every shadow that potentially will need to re-render
  4423. //-----------------------------------------------------------------------------
  4424. bool CClientShadowMgr::DrawRenderToTextureShadow( int nSlot, unsigned short clientShadowHandle, float flArea )
  4425. {
  4426. ClientShadow_t& shadow = m_Shadows[clientShadowHandle];
  4427. if ( shadow.m_bUseSplitScreenBits &&
  4428. !shadow.m_SplitScreenBits.IsBitSet( nSlot ) )
  4429. {
  4430. return false;
  4431. }
  4432. // If we were previously using the LOD shadow, set the material
  4433. bool bPreviouslyUsingLODShadow = ( shadow.m_Flags & SHADOW_FLAGS_USING_LOD_SHADOW ) != 0;
  4434. shadow.m_Flags &= ~SHADOW_FLAGS_USING_LOD_SHADOW;
  4435. if ( bPreviouslyUsingLODShadow )
  4436. {
  4437. shadowmgr->SetShadowMaterial( shadow.m_ShadowHandle, m_RenderShadow, m_RenderModelShadow, (void*)(uintp)clientShadowHandle );
  4438. }
  4439. // Mark texture as being used...
  4440. bool bDirtyTexture = (shadow.m_Flags & SHADOW_FLAGS_TEXTURE_DIRTY) != 0;
  4441. bool bDrewTexture = false;
  4442. bool bNeedsRedraw = m_ShadowAllocator.UseTexture( shadow.m_ShadowTexture, bDirtyTexture, flArea );
  4443. if ( !m_ShadowAllocator.HasValidTexture( shadow.m_ShadowTexture ) )
  4444. {
  4445. DrawRenderToTextureShadowLOD( nSlot, clientShadowHandle );
  4446. return false;
  4447. }
  4448. if ( bNeedsRedraw || bDirtyTexture )
  4449. {
  4450. // shadow to be redrawn; for now, we'll always do it.
  4451. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity );
  4452. CMatRenderContextPtr pRenderContext( materials );
  4453. // Sets the viewport state
  4454. int x, y, w, h;
  4455. m_ShadowAllocator.GetTextureRect( shadow.m_ShadowTexture, x, y, w, h );
  4456. pRenderContext->Viewport( IsGameConsole() ? 0 : x, IsGameConsole() ? 0 : y, w, h );
  4457. // Clear the selected viewport only (don't need to clear depth)
  4458. pRenderContext->ClearBuffers( true, false );
  4459. pRenderContext->MatrixMode( MATERIAL_VIEW );
  4460. pRenderContext->LoadMatrix( shadow.m_WorldToTexture );
  4461. if ( DrawShadowHierarchy( pRenderable, shadow ) )
  4462. {
  4463. bDrewTexture = true;
  4464. if ( IsGameConsole() )
  4465. {
  4466. // resolve render target to system memory texture
  4467. Rect_t srcRect = { 0, 0, w, h };
  4468. Rect_t dstRect = { x, y, w, h };
  4469. pRenderContext->CopyRenderTargetToTextureEx( m_ShadowAllocator.GetTexture(), 0, &srcRect, &dstRect );
  4470. }
  4471. }
  4472. else
  4473. {
  4474. // NOTE: Think the flags reset + texcoord set should only happen in DrawShadowHierarchy
  4475. // but it's 2 days before 360 ship.. not going to change this now.
  4476. DevMsg( "Didn't draw shadow hierarchy.. bad shadow texcoords probably going to happen..grab Brian!\n" );
  4477. }
  4478. // Only clear the dirty flag if the caster isn't animating
  4479. if ( (shadow.m_Flags & SHADOW_FLAGS_ANIMATING_SOURCE) == 0 )
  4480. {
  4481. shadow.m_Flags &= ~SHADOW_FLAGS_TEXTURE_DIRTY;
  4482. }
  4483. SetRenderToTextureShadowTexCoords( shadow.m_ShadowHandle, x, y, w, h );
  4484. SetRenderToTextureShadowTexCoords( shadow, x, y, w, h );
  4485. }
  4486. else if ( bPreviouslyUsingLODShadow )
  4487. {
  4488. // In this case, we were previously using the LOD shadow, but we didn't
  4489. // have to reconstitute the texture. In this case, we need to reset the texcoord
  4490. int x, y, w, h;
  4491. m_ShadowAllocator.GetTextureRect( shadow.m_ShadowTexture, x, y, w, h );
  4492. SetRenderToTextureShadowTexCoords( shadow.m_ShadowHandle, x, y, w, h );
  4493. SetRenderToTextureShadowTexCoords( shadow, x, y, w, h );
  4494. }
  4495. return bDrewTexture;
  4496. }
  4497. //-----------------------------------------------------------------------------
  4498. // "Draws" the shadow LOD, which really means just set up the blobby shadow
  4499. //-----------------------------------------------------------------------------
  4500. void CClientShadowMgr::DrawRenderToTextureShadowLOD( int nSlot, unsigned short clientShadowHandle )
  4501. {
  4502. if ( r_shadow_deferred.GetBool() )
  4503. {
  4504. return;
  4505. }
  4506. ClientShadow_t &shadow = m_Shadows[clientShadowHandle];
  4507. if ( shadow.m_bUseSplitScreenBits &&
  4508. !shadow.m_SplitScreenBits.IsBitSet( nSlot ) )
  4509. {
  4510. return;
  4511. }
  4512. if ( (shadow.m_Flags & SHADOW_FLAGS_USING_LOD_SHADOW) == 0 )
  4513. {
  4514. shadowmgr->SetShadowMaterial( shadow.m_ShadowHandle, m_SimpleShadow, m_SimpleShadow, (void*)CLIENTSHADOW_INVALID_HANDLE );
  4515. shadowmgr->SetShadowTexCoord( shadow.m_ShadowHandle, 0, 0, 1, 1 );
  4516. ClearExtraClipPlanes( shadow.m_ShadowHandle );
  4517. shadow.m_Flags |= SHADOW_FLAGS_USING_LOD_SHADOW;
  4518. }
  4519. }
  4520. //-----------------------------------------------------------------------------
  4521. // Advances to the next frame,
  4522. //-----------------------------------------------------------------------------
  4523. void CClientShadowMgr::AdvanceFrame()
  4524. {
  4525. // We're starting the next frame
  4526. m_ShadowAllocator.AdvanceFrame();
  4527. }
  4528. //-----------------------------------------------------------------------------
  4529. // Re-render shadow depth textures that lie in the leaf list
  4530. //-----------------------------------------------------------------------------
  4531. int CClientShadowMgr::BuildActiveShadowDepthList( const CViewSetup &viewSetup, int nMaxDepthShadows, ClientShadowHandle_t *pActiveDepthShadows, int &nNumHighRes )
  4532. {
  4533. float fDots[ 1024 ];
  4534. nNumHighRes = 0;
  4535. Frustum_t viewFrustum;
  4536. GeneratePerspectiveFrustum( viewSetup.origin, viewSetup.angles, viewSetup.zNear, viewSetup.zFar, viewSetup.fov, viewSetup.m_flAspectRatio, viewFrustum );
  4537. // Get a general look position for
  4538. Vector vViewForward;
  4539. AngleVectors( viewSetup.angles, &vViewForward );
  4540. int nActiveDepthShadowCount = 0;
  4541. for ( ClientShadowHandle_t i = m_Shadows.Head(); i != m_Shadows.InvalidIndex(); i = m_Shadows.Next(i) )
  4542. {
  4543. if ( nActiveDepthShadowCount >= nMaxDepthShadows && nNumHighRes == nActiveDepthShadowCount )
  4544. {
  4545. // Easy out! There's nothing more we can do
  4546. break;
  4547. }
  4548. ClientShadow_t& shadow = m_Shadows[i];
  4549. // If this is not a flashlight which should use a shadow depth texture, skip!
  4550. if ( ( shadow.m_Flags & SHADOW_FLAGS_USE_DEPTH_TEXTURE ) == 0 )
  4551. continue;
  4552. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  4553. if ( ( shadow.m_nSplitscreenOwner >= 0 ) && ( shadow.m_nSplitscreenOwner != GET_ACTIVE_SPLITSCREEN_SLOT() ) )
  4554. continue;
  4555. const FlashlightState_t& flashlightState = shadowmgr->GetFlashlightState( shadow.m_ShadowHandle );
  4556. // Bail if this flashlight doesn't want shadows
  4557. if ( !flashlightState.m_bEnableShadows )
  4558. continue;
  4559. if ( r_flashlightenableculling.GetBool() )
  4560. {
  4561. // Calculate an AABB around the shadow frustum
  4562. Vector vecAbsMins, vecAbsMaxs;
  4563. CalculateAABBFromProjectionMatrix( shadow.m_WorldToShadow, &vecAbsMins, &vecAbsMaxs );
  4564. // FIXME: Could do other sorts of culling here, such as frustum-frustum test, distance etc.
  4565. // If it's not in the view frustum, move on
  4566. if ( !flashlightState.m_bOrtho && viewFrustum.CullBox( vecAbsMins, vecAbsMaxs ) )
  4567. {
  4568. shadowmgr->SetFlashlightDepthTexture( shadow.m_ShadowHandle, NULL, 0 );
  4569. continue;
  4570. }
  4571. }
  4572. if ( nActiveDepthShadowCount >= nMaxDepthShadows )
  4573. {
  4574. if ( !flashlightState.m_bShadowHighRes )
  4575. {
  4576. // All active shadows are high res
  4577. static bool s_bOverflowWarning = false;
  4578. if ( !s_bOverflowWarning )
  4579. {
  4580. Warning( "Too many depth textures rendered in a single view!\n" );
  4581. Assert( 0 );
  4582. s_bOverflowWarning = true;
  4583. }
  4584. shadowmgr->SetFlashlightDepthTexture( shadow.m_ShadowHandle, NULL, 0 );
  4585. continue;
  4586. }
  4587. else
  4588. {
  4589. // Lets take the place of other non high res active shadows
  4590. for ( int j = nActiveDepthShadowCount - 1; j >= 0; --j )
  4591. {
  4592. // Find a low res one to replace
  4593. ClientShadow_t& prevShadow = m_Shadows[ pActiveDepthShadows[ j ] ];
  4594. const FlashlightState_t& prevFlashlightState = shadowmgr->GetFlashlightState( prevShadow.m_ShadowHandle );
  4595. if ( !prevFlashlightState.m_bShadowHighRes )
  4596. {
  4597. pActiveDepthShadows[ j ] = i;
  4598. ++nNumHighRes;
  4599. break;
  4600. }
  4601. }
  4602. continue;
  4603. }
  4604. }
  4605. if ( flashlightState.m_bShadowHighRes )
  4606. {
  4607. ++nNumHighRes;
  4608. }
  4609. // Calculate the approximate distance to the nearest side
  4610. Vector vLightDirection = flashlightState.m_vecLightOrigin - viewSetup.origin;
  4611. VectorNormalize( vLightDirection );
  4612. fDots[ nActiveDepthShadowCount ] = vLightDirection.Dot( vViewForward );
  4613. pActiveDepthShadows[ nActiveDepthShadowCount++ ] = i;
  4614. }
  4615. // sort them
  4616. for ( int i = 0; i < nActiveDepthShadowCount - 1; i++ )
  4617. {
  4618. for ( int j = 0; j < nActiveDepthShadowCount - i - 1; j++ )
  4619. {
  4620. if ( fDots[ j ] < fDots[ j + 1 ] )
  4621. {
  4622. ClientShadowHandle_t nTemp = pActiveDepthShadows[ j ];
  4623. pActiveDepthShadows[ j ] = pActiveDepthShadows[ j + 1 ];
  4624. pActiveDepthShadows[ j + 1 ] = nTemp;
  4625. }
  4626. }
  4627. }
  4628. return nActiveDepthShadowCount;
  4629. }
  4630. //-----------------------------------------------------------------------------
  4631. // Re-render shadow depth textures that lie in the leaf list
  4632. //-----------------------------------------------------------------------------
  4633. int CClientShadowMgr::BuildActiveFlashlightList( const CViewSetup &viewSetup, int nMaxFlashlights, ClientShadowHandle_t *pActiveFlashlights )
  4634. {
  4635. int nActiveFlashlightCount = 0;
  4636. for ( ClientShadowHandle_t i = m_Shadows.Head(); i != m_Shadows.InvalidIndex(); i = m_Shadows.Next(i) )
  4637. {
  4638. ClientShadow_t& shadow = m_Shadows[i];
  4639. if ( ( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) == 0 )
  4640. continue;
  4641. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  4642. if ( ( shadow.m_nSplitscreenOwner >= 0 ) && ( shadow.m_nSplitscreenOwner != GET_ACTIVE_SPLITSCREEN_SLOT() ) )
  4643. continue;
  4644. // Calculate an AABB around the shadow frustum
  4645. Vector vecAbsMins, vecAbsMaxs;
  4646. CalculateAABBFromProjectionMatrix( shadow.m_WorldToShadow, &vecAbsMins, &vecAbsMaxs );
  4647. Frustum_t viewFrustum;
  4648. GeneratePerspectiveFrustum( viewSetup.origin, viewSetup.angles, viewSetup.zNear, viewSetup.zFar, viewSetup.fov, viewSetup.m_flAspectRatio, viewFrustum );
  4649. // FIXME: Could do other sorts of culling here, such as frustum-frustum test, distance etc.
  4650. // If it's not in the view frustum, move on
  4651. if ( viewFrustum.CullBox( vecAbsMins, vecAbsMaxs ) )
  4652. {
  4653. continue;
  4654. }
  4655. if ( nActiveFlashlightCount >= nMaxFlashlights )
  4656. {
  4657. static bool s_bOverflowWarning = false;
  4658. if ( !s_bOverflowWarning )
  4659. {
  4660. Warning( "Too many flashlights rendered in a single view!\n" );
  4661. Assert( 0 );
  4662. s_bOverflowWarning = true;
  4663. }
  4664. //shadowmgr->SetFlashlightDepthTexture( shadow.m_ShadowHandle, NULL, 0 );
  4665. continue;
  4666. }
  4667. pActiveFlashlights[nActiveFlashlightCount++] = i;
  4668. }
  4669. return nActiveFlashlightCount;
  4670. }
  4671. //-----------------------------------------------------------------------------
  4672. // Sets the view's active flashlight render state
  4673. //-----------------------------------------------------------------------------
  4674. void CClientShadowMgr::SetViewFlashlightState( int nActiveFlashlightCount, ClientShadowHandle_t* pActiveFlashlights )
  4675. {
  4676. // NOTE: On the 360, we render the entire scene with the flashlight state
  4677. // set and don't render flashlights additively in the shadow mgr at a far later time
  4678. // because the CPU costs are prohibitive
  4679. shadowmgr->PushSinglePassFlashlightStateEnabled( IsGameConsole() );
  4680. AssertOnce( nActiveFlashlightCount <= m_nMaxDepthTextureShadows );
  4681. if ( nActiveFlashlightCount > 0 )
  4682. {
  4683. Assert( ( m_Shadows[ pActiveFlashlights[0] ].m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) != 0 );
  4684. shadowmgr->SetSinglePassFlashlightRenderState( m_Shadows[ pActiveFlashlights[0] ].m_ShadowHandle );
  4685. }
  4686. else
  4687. {
  4688. shadowmgr->SetSinglePassFlashlightRenderState( SHADOW_HANDLE_INVALID );
  4689. }
  4690. }
  4691. //-----------------------------------------------------------------------------
  4692. // Kicks off rendering of volumetrics for the flashlights
  4693. //-----------------------------------------------------------------------------
  4694. void CClientShadowMgr::DrawVolumetrics( const CViewSetup &viewSetup )
  4695. {
  4696. CMatRenderContextPtr pRenderContext( materials );
  4697. PIXEVENT( pRenderContext, "Draw Flashlight Volumetrics" );
  4698. shadowmgr->DrawVolumetrics();
  4699. }
  4700. void AddPointToExtentsHelper( const VMatrix &flashlightToWorld, const Vector &vecPos, Vector &vecMin, Vector &vecMax )
  4701. {
  4702. Vector worldSpacePos;
  4703. Vector3DMultiplyPositionProjective( flashlightToWorld, vecPos, worldSpacePos );
  4704. VectorMin( vecMin, worldSpacePos, vecMin );
  4705. VectorMax( vecMax, worldSpacePos, vecMax );
  4706. }
  4707. void CClientShadowMgr::GetFrustumExtents( ClientShadowHandle_t handle, Vector &vecMin, Vector &vecMax )
  4708. {
  4709. Assert( m_Shadows.IsValidIndex( handle ) );
  4710. CClientShadowMgr::ClientShadow_t &shadow = m_Shadows[ handle ];
  4711. VMatrix flashlightToWorld;
  4712. MatrixInverseGeneral( shadow.m_WorldToShadow, flashlightToWorld );
  4713. vecMin = Vector( FLT_MAX, FLT_MAX, FLT_MAX );
  4714. vecMax = Vector( -FLT_MAX, -FLT_MAX, -FLT_MAX );
  4715. AddPointToExtentsHelper( flashlightToWorld, Vector( 0.0f, 0.0f, 0.0f ), vecMin, vecMax );
  4716. AddPointToExtentsHelper( flashlightToWorld, Vector( 0.0f, 0.0f, 1.0f ), vecMin, vecMax );
  4717. AddPointToExtentsHelper( flashlightToWorld, Vector( 0.0f, 1.0f, 0.0f ), vecMin, vecMax );
  4718. AddPointToExtentsHelper( flashlightToWorld, Vector( 1.0f, 0.0f, 0.0f ), vecMin, vecMax );
  4719. AddPointToExtentsHelper( flashlightToWorld, Vector( 0.0f, 1.0f, 1.0f ), vecMin, vecMax );
  4720. AddPointToExtentsHelper( flashlightToWorld, Vector( 1.0f, 0.0f, 1.0f ), vecMin, vecMax );
  4721. AddPointToExtentsHelper( flashlightToWorld, Vector( 1.0f, 1.0f, 0.0f ), vecMin, vecMax );
  4722. AddPointToExtentsHelper( flashlightToWorld, Vector( 1.0f, 1.0f, 1.0f ), vecMin, vecMax );
  4723. }
  4724. //-----------------------------------------------------------------------------
  4725. // Re-render shadow depth textures that lie in the leaf list
  4726. //
  4727. // bSetup currently only used on PS3 - to support 2 pass Build/Draw rendering
  4728. // bSetup indicates whether to execute once per frame setup code, do this in the buildlist (1st pass) pass only
  4729. // Needed since this will get called twice on PS3 if 2 pass drawing is on
  4730. // bSetup = true otherwise
  4731. //
  4732. //-----------------------------------------------------------------------------
  4733. void CClientShadowMgr::ComputeShadowDepthTextures( const CViewSetup &viewSetup, bool bSetup )
  4734. {
  4735. if ( !r_flashlightdepthtexture.GetBool() )
  4736. {
  4737. // Build list of active flashlights
  4738. ClientShadowHandle_t pActiveFlashlights[16];
  4739. int nActiveFlashlights = BuildActiveFlashlightList( viewSetup, ARRAYSIZE( pActiveFlashlights ), pActiveFlashlights );
  4740. SetViewFlashlightState( nActiveFlashlights, pActiveFlashlights );
  4741. return;
  4742. }
  4743. VPROF_BUDGET( "CClientShadowMgr::ComputeShadowDepthTextures", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  4744. CMatRenderContextPtr pRenderContext( materials );
  4745. PIXEVENT( pRenderContext, "Shadow Depth Textures" );
  4746. // Build list of active shadow depth textures / flashlights
  4747. int iNumHighRes = 0;
  4748. ClientShadowHandle_t pActiveDepthShadows[1024];
  4749. int nActiveDepthShadowCount = BuildActiveShadowDepthList( viewSetup, ARRAYSIZE( pActiveDepthShadows ), pActiveDepthShadows, iNumHighRes );
  4750. int iLowResStart = ( iNumHighRes >= m_nMaxDepthTextureShadows ? 0 : iNumHighRes );
  4751. // Iterate over all existing textures and allocate shadow textures
  4752. bool bDebugFrustum = r_flashlightdrawfrustum.GetBool();
  4753. bool bDebugFrustumBBox = r_flashlightdrawfrustumbbox.GetBool();
  4754. bool bPrintFlashlightInfo = r_flashlight_info.GetBool();
  4755. if ( bPrintFlashlightInfo )
  4756. {
  4757. engine->Con_NPrintf( 0, "%d active flashlights", nActiveDepthShadowCount );
  4758. }
  4759. for ( int j = 0; j < nActiveDepthShadowCount; ++j )
  4760. {
  4761. ClientShadow_t& shadow = m_Shadows[ pActiveDepthShadows[j] ];
  4762. FlashlightState_t& flashlightState = const_cast<FlashlightState_t&>( shadowmgr->GetFlashlightState( shadow.m_ShadowHandle ) );
  4763. CViewSetup shadowView;
  4764. CTextureReference shadowDepthTexture;
  4765. if( !bSetup )
  4766. {
  4767. bool bGotShadowDepthTexture = LockShadowDepthTexture( &shadowDepthTexture, flashlightState.m_bShadowHighRes ? 0 : iLowResStart );
  4768. if ( !bGotShadowDepthTexture )
  4769. {
  4770. // If we don't get one, that means we have too many this frame so bind no depth texture
  4771. static int bitchCount = 0;
  4772. if( bitchCount < 10 )
  4773. {
  4774. Warning( "Too many shadow maps this frame!\n" );
  4775. bitchCount++;
  4776. }
  4777. AssertOnce(0);
  4778. shadowmgr->SetFlashlightDepthTexture( shadow.m_ShadowHandle, NULL, 0 );
  4779. if ( bPrintFlashlightInfo )
  4780. {
  4781. engine->Con_NPrintf( j + 1, "[ERROR - no shadow] %f %f %f ", flashlightState.m_vecLightOrigin.x, flashlightState.m_vecLightOrigin.y, flashlightState.m_vecLightOrigin.z );
  4782. }
  4783. continue;
  4784. }
  4785. if ( bPrintFlashlightInfo )
  4786. {
  4787. engine->Con_NPrintf( j + 1, "[shadow] %f %f %f ", flashlightState.m_vecLightOrigin.x, flashlightState.m_vecLightOrigin.y, flashlightState.m_vecLightOrigin.z );
  4788. }
  4789. shadowView.m_flAspectRatio = 1.0f;
  4790. shadowView.x = shadowView.y = 0;
  4791. shadowView.width = shadowDepthTexture->GetActualWidth();
  4792. shadowView.height = shadowDepthTexture->GetActualHeight();
  4793. }
  4794. else
  4795. {
  4796. shadowView.m_flAspectRatio = 1.0f;
  4797. shadowView.x = shadowView.y = 0;
  4798. shadowView.width = 0;
  4799. shadowView.height = 0;
  4800. }
  4801. // Copy flashlight parameters
  4802. if ( !flashlightState.m_bOrtho )
  4803. {
  4804. shadowView.m_bOrtho = false;
  4805. }
  4806. else
  4807. {
  4808. shadowView.m_bOrtho = true;
  4809. shadowView.m_OrthoLeft = flashlightState.m_fOrthoLeft;
  4810. shadowView.m_OrthoTop = flashlightState.m_fOrthoTop;
  4811. shadowView.m_OrthoRight = flashlightState.m_fOrthoRight;
  4812. shadowView.m_OrthoBottom = flashlightState.m_fOrthoBottom;
  4813. }
  4814. shadowView.m_bDoBloomAndToneMapping = false;
  4815. shadowView.m_nMotionBlurMode = MOTION_BLUR_DISABLE;
  4816. shadowView.fov = shadowView.fovViewmodel = flashlightState.m_fHorizontalFOVDegrees;
  4817. shadowView.origin = flashlightState.m_vecLightOrigin;
  4818. QuaternionAngles( flashlightState.m_quatOrientation, shadowView.angles ); // Convert from Quaternion to QAngle
  4819. shadowView.zNear = shadowView.zNearViewmodel = flashlightState.m_NearZ;
  4820. shadowView.zFar = shadowView.zFarViewmodel = flashlightState.m_FarZ;
  4821. // Can turn on all light frustum overlays or per light with flashlightState parameter...
  4822. if ( ( bDebugFrustum || flashlightState.m_bDrawShadowFrustum ) && !bSetup )
  4823. {
  4824. if ( flashlightState.m_bUberlight )
  4825. {
  4826. DrawUberlightRig( shadowView.origin, shadow.m_WorldToShadow, flashlightState );
  4827. }
  4828. DrawFrustum( shadowView.origin, shadow.m_WorldToShadow );
  4829. }
  4830. if ( bDebugFrustumBBox && !bSetup )
  4831. {
  4832. Vector vecExtentsMin, vecExtentsMax;
  4833. GetFrustumExtents( pActiveDepthShadows[j], vecExtentsMin, vecExtentsMax );
  4834. float flVisibleBBoxMinHeight = MIN( vecExtentsMax.z - 1.0f, C_EnvProjectedTexture::GetVisibleBBoxMinHeight() );
  4835. vecExtentsMin.z = MAX( vecExtentsMin.z, flVisibleBBoxMinHeight );
  4836. NDebugOverlay::Box( Vector( 0.0f, 0.0f, 0.0f ), vecExtentsMin, vecExtentsMax, 0, 0, 255, 100, 0.0f );
  4837. }
  4838. // Set depth bias factors specific to this flashlight
  4839. if( !bSetup )
  4840. {
  4841. CMatRenderContextPtr pRenderContext( materials );
  4842. pRenderContext->SetShadowDepthBiasFactors( flashlightState.m_flShadowSlopeScaleDepthBias, flashlightState.m_flShadowDepthBias );
  4843. // Render to the shadow depth texture with appropriate view
  4844. view->UpdateShadowDepthTexture( m_DummyColorTexture, shadowDepthTexture, shadowView );
  4845. }
  4846. else
  4847. {
  4848. // just build world/renderable lists
  4849. view->UpdateShadowDepthTexture( NULL, NULL, shadowView );
  4850. }
  4851. // Associate the shadow depth texture and stencil bit with the flashlight for use during scene rendering
  4852. if( !bSetup )
  4853. {
  4854. shadowmgr->SetFlashlightDepthTexture( shadow.m_ShadowHandle, shadowDepthTexture, 0 );
  4855. }
  4856. }
  4857. SetViewFlashlightState( nActiveDepthShadowCount, pActiveDepthShadows );
  4858. }
  4859. //-----------------------------------------------------------------------------
  4860. // Re-renders all shadow textures for shadow casters that lie in the leaf list
  4861. //-----------------------------------------------------------------------------
  4862. static void SetupBonesOnBaseAnimating( C_BaseAnimating *&pBaseAnimating )
  4863. {
  4864. pBaseAnimating->SetupBones( NULL, -1, -1, gpGlobals->curtime );
  4865. }
  4866. void CClientShadowMgr::ComputeShadowTextures( const CViewSetup &view, int leafCount, WorldListLeafData_t* pLeafList )
  4867. {
  4868. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  4869. int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  4870. VPROF_BUDGET( "CClientShadowMgr::ComputeShadowTextures", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  4871. if ( !m_RenderToTextureActive || (r_shadows.GetInt() == 0) || r_shadows_gamecontrol.GetInt() == 0 )
  4872. return;
  4873. MDLCACHE_CRITICAL_SECTION();
  4874. // First grab all shadow textures we may want to render
  4875. int nCount = s_VisibleShadowList.FindShadows( &view, leafCount, pLeafList );
  4876. if ( nCount == 0 )
  4877. return;
  4878. // FIXME: Add heuristics based on distance, etc. to futz with
  4879. // the shadow allocator + to select blobby shadows
  4880. CMatRenderContextPtr pRenderContext( materials );
  4881. PIXEVENT( pRenderContext, "Render-To-Texture Shadows" );
  4882. // Clear to white (color unused), black alpha
  4883. pRenderContext->ClearColor4ub( 255, 255, 255, 0 );
  4884. // No height clip mode please.
  4885. MaterialHeightClipMode_t oldHeightClipMode = pRenderContext->GetHeightClipMode();
  4886. pRenderContext->SetHeightClipMode( MATERIAL_HEIGHTCLIPMODE_DISABLE );
  4887. // No projection matrix (orthographic mode)
  4888. // FIXME: Make it work for projective shadows?
  4889. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  4890. pRenderContext->PushMatrix();
  4891. pRenderContext->LoadIdentity();
  4892. pRenderContext->Scale( 1, -1, 1 );
  4893. pRenderContext->Ortho( 0, 0, 1, 1, -9999, 0 );
  4894. pRenderContext->MatrixMode( MATERIAL_VIEW );
  4895. pRenderContext->PushMatrix();
  4896. pRenderContext->PushRenderTargetAndViewport( m_ShadowAllocator.GetTexture() );
  4897. if ( m_bRenderTargetNeedsClear )
  4898. {
  4899. // don't need to clear absent depth buffer
  4900. pRenderContext->ClearBuffers( true, false );
  4901. m_bRenderTargetNeedsClear = false;
  4902. }
  4903. int nMaxShadows = r_shadowmaxrendered.GetInt();
  4904. int nModelsRendered = 0;
  4905. int i;
  4906. for (i = 0; i < nCount; ++i)
  4907. {
  4908. const VisibleShadowInfo_t &info = s_VisibleShadowList.GetVisibleShadow(i);
  4909. if ( nModelsRendered < nMaxShadows )
  4910. {
  4911. if ( DrawRenderToTextureShadow( nSlot, info.m_hShadow, info.m_flArea ) )
  4912. {
  4913. ++nModelsRendered;
  4914. }
  4915. }
  4916. else
  4917. {
  4918. DrawRenderToTextureShadowLOD( nSlot, info.m_hShadow );
  4919. }
  4920. }
  4921. // Render to the backbuffer again
  4922. pRenderContext->PopRenderTargetAndViewport();
  4923. // Restore the matrices
  4924. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  4925. pRenderContext->PopMatrix();
  4926. pRenderContext->MatrixMode( MATERIAL_VIEW );
  4927. pRenderContext->PopMatrix();
  4928. pRenderContext->SetHeightClipMode( oldHeightClipMode );
  4929. pRenderContext->SetHeightClipMode( oldHeightClipMode );
  4930. // Restore the clear color
  4931. pRenderContext->ClearColor3ub( 0, 0, 0 );
  4932. }
  4933. //-------------------------------------------------------------------------------------------------------
  4934. // Lock down the usage of a shadow depth texture...must be unlocked for use on subsequent views / frames
  4935. //-------------------------------------------------------------------------------------------------------
  4936. bool CClientShadowMgr::LockShadowDepthTexture( CTextureReference *shadowDepthTexture, int nStartTexture )
  4937. {
  4938. for ( int i = nStartTexture; i < m_DepthTextureCache.Count(); i++ ) // Search for cached shadow depth texture
  4939. {
  4940. if ( m_DepthTextureCacheLocks[i] == false && m_DepthTextureCache[i].IsValid() ) // If a free one is found
  4941. {
  4942. *shadowDepthTexture = m_DepthTextureCache[i];
  4943. m_DepthTextureCacheLocks[i] = true;
  4944. return true;
  4945. }
  4946. }
  4947. return false; // Didn't find it...
  4948. }
  4949. bool ClientShadowMgrAcquireShadowDepthTexture( CTextureReference *pDummyColorTexture, CTextureReference *pShadowDepthTexture )
  4950. {
  4951. if ( pDummyColorTexture )
  4952. {
  4953. *pDummyColorTexture = s_ClientShadowMgr.m_DummyColorTexture;
  4954. }
  4955. if ( pShadowDepthTexture )
  4956. {
  4957. if ( s_ClientShadowMgr.m_DepthTextureCache.Count() && s_ClientShadowMgr.m_DepthTextureCache[0].IsValid() )
  4958. {
  4959. *pShadowDepthTexture = s_ClientShadowMgr.m_DepthTextureCache[0];
  4960. return true;
  4961. }
  4962. }
  4963. else
  4964. {
  4965. s_ClientShadowMgr.UnlockAllShadowDepthTextures();
  4966. }
  4967. return false;
  4968. }
  4969. //------------------------------------------------------------------
  4970. // Unlock shadow depth texture for use on subsequent views / frames
  4971. //------------------------------------------------------------------
  4972. void CClientShadowMgr::UnlockAllShadowDepthTextures()
  4973. {
  4974. for (int i=0; i< m_DepthTextureCache.Count(); i++ )
  4975. {
  4976. m_DepthTextureCacheLocks[i] = false;
  4977. }
  4978. shadowmgr->SetSinglePassFlashlightRenderState( SHADOW_HANDLE_INVALID );
  4979. shadowmgr->PopSinglePassFlashlightStateEnabled();
  4980. }
  4981. void CClientShadowMgr::SetFlashlightTarget( ClientShadowHandle_t shadowHandle, EHANDLE targetEntity )
  4982. {
  4983. Assert( m_Shadows.IsValidIndex( shadowHandle ) );
  4984. CClientShadowMgr::ClientShadow_t &shadow = m_Shadows[ shadowHandle ];
  4985. if( ( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) == 0 )
  4986. return;
  4987. // shadow.m_pTargetRenderable = pRenderable;
  4988. shadow.m_hTargetEntity = targetEntity;
  4989. }
  4990. void CClientShadowMgr::SetFlashlightLightWorld( ClientShadowHandle_t shadowHandle, bool bLightWorld )
  4991. {
  4992. Assert( m_Shadows.IsValidIndex( shadowHandle ) );
  4993. ClientShadow_t &shadow = m_Shadows[ shadowHandle ];
  4994. if( ( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) == 0 )
  4995. return;
  4996. if ( bLightWorld )
  4997. {
  4998. shadow.m_Flags |= SHADOW_FLAGS_LIGHT_WORLD;
  4999. }
  5000. else
  5001. {
  5002. shadow.m_Flags &= ~SHADOW_FLAGS_LIGHT_WORLD;
  5003. }
  5004. }
  5005. bool CClientShadowMgr::IsFlashlightTarget( ClientShadowHandle_t shadowHandle, IClientRenderable *pRenderable )
  5006. {
  5007. ClientShadow_t &shadow = m_Shadows[ shadowHandle ];
  5008. if( shadow.m_hTargetEntity->GetClientRenderable() == pRenderable )
  5009. return true;
  5010. C_BaseEntity *pChild = shadow.m_hTargetEntity->FirstMoveChild();
  5011. while( pChild )
  5012. {
  5013. if( pChild->GetClientRenderable()==pRenderable )
  5014. return true;
  5015. pChild = pChild->NextMovePeer();
  5016. }
  5017. return false;
  5018. }
  5019. void CClientShadowMgr::SetShadowFromWorldLightsEnabled( bool bEnable )
  5020. {
  5021. bool bIsShadowingFromWorldLights = IsShadowingFromWorldLights();
  5022. m_bShadowFromWorldLights = bEnable;
  5023. if ( bIsShadowingFromWorldLights != IsShadowingFromWorldLights() )
  5024. {
  5025. UpdateAllShadows();
  5026. }
  5027. }
  5028. void CClientShadowMgr::SuppressShadowFromWorldLights( bool bSuppress )
  5029. {
  5030. bool bIsShadowingFromWorldLights = IsShadowingFromWorldLights();
  5031. m_bSuppressShadowFromWorldLights = bSuppress;
  5032. if ( bIsShadowingFromWorldLights != IsShadowingFromWorldLights() )
  5033. {
  5034. UpdateAllShadows();
  5035. }
  5036. }
  5037. ///////////////////////////////////////////////////////////////////////
  5038. // Vertex and index data for cube with degenerate faces on each edge
  5039. ///////////////////////////////////////////////////////////////////////
  5040. ALIGN16 static const float pShadowBoundVerts[] =
  5041. {
  5042. // +X face
  5043. 1.0f, -1.0f, -1.0f, 1.0f,
  5044. 1.0f, 1.0f, -1.0f, 1.0f,
  5045. 1.0f, 1.0f, 1.0f, 1.0f,
  5046. 1.0f, -1.0f, 1.0f, 1.0f,
  5047. // +Y face
  5048. -1.0f, 1.0f, -1.0f, 1.0f,
  5049. -1.0f, 1.0f, 1.0f, 1.0f,
  5050. 1.0f, 1.0f, 1.0f, 1.0f,
  5051. 1.0f, 1.0f, -1.0f, 1.0f,
  5052. // -X face
  5053. -1.0f, -1.0f, 1.0f, 1.0f,
  5054. -1.0f, 1.0f, 1.0f, 1.0f,
  5055. -1.0f, 1.0f, -1.0f, 1.0f,
  5056. -1.0f, -1.0f, -1.0f, 1.0f,
  5057. // -Y face
  5058. -1.0f, -1.0f, -1.0f, 1.0f,
  5059. 1.0f, -1.0f, -1.0f, 1.0f,
  5060. 1.0f, -1.0f, 1.0f, 1.0f,
  5061. -1.0f, -1.0f, 1.0f, 1.0f,
  5062. // +Z face
  5063. -1.0f, -1.0f, 1.0f, 1.0f,
  5064. 1.0f, -1.0f, 1.0f, 1.0f,
  5065. 1.0f, 1.0f, 1.0f, 1.0f,
  5066. -1.0f, 1.0f, 1.0f, 1.0f,
  5067. // -Z face
  5068. 1.0f, -1.0f, -1.0f, 1.0f,
  5069. -1.0f, -1.0f, -1.0f, 1.0f,
  5070. -1.0f, 1.0f, -1.0f, 1.0f,
  5071. 1.0f, 1.0f, -1.0f, 1.0f
  5072. };
  5073. ALIGN16 static const float pShadowBoundNormals[] =
  5074. {
  5075. 1.0f, 0.0f, 0.0f, 0.0f,
  5076. 0.0f, 1.0f, 0.0f, 0.0f,
  5077. -1.0f, 0.0f, 0.0f, 0.0f,
  5078. 0.0f, -1.0f, 0.0f, 0.0f,
  5079. 0.0f, 0.0f, 1.0f, 0.0f,
  5080. 0.0f, 0.0f, -1.0f, 0.0f,
  5081. };
  5082. ALIGN16 static const unsigned short pShadowBoundIndices[] =
  5083. {
  5084. // box faces
  5085. 0, 2, 1, 0, 3, 2,
  5086. 4, 6, 5, 4, 7, 6,
  5087. 8, 10, 9, 8, 11, 10,
  5088. 12, 14, 13, 12, 15, 14,
  5089. 16, 18, 17, 16, 19, 18,
  5090. 20, 22, 21, 20, 23, 22,
  5091. // degenerate faces on edges
  5092. 2, 7, 1, 2, 6, 7,
  5093. 5, 10, 4, 5, 9, 10,
  5094. 8, 12, 11, 8, 15, 12,
  5095. 14, 0, 13, 14, 3, 0,
  5096. 17, 2, 3, 17, 18, 2,
  5097. 18, 5, 6, 18, 19, 5,
  5098. 8, 19, 16, 8, 9, 19,
  5099. 14, 16, 17, 14, 15, 16,
  5100. 0, 23, 20, 0, 1, 23,
  5101. 7, 22, 23, 7, 4, 22,
  5102. 11, 21, 22, 11, 22, 10,
  5103. 13, 21, 12, 13, 20, 21
  5104. };
  5105. // Adds a cube with degenerate edge quads to a mesh builder
  5106. void CClientShadowMgr::BuildCubeWithDegenerateEdgeQuads( CMeshBuilder& meshBuilder, const matrix3x4_t& objToWorld, const VMatrix& projToShadow, const CClientShadowMgr::ClientShadow_t& shadow )
  5107. {
  5108. static bool bSIMDDataInitialized = false;
  5109. static FourVectors srcPositions[6];
  5110. static FourVectors srcNormals[2];
  5111. if ( !bSIMDDataInitialized )
  5112. {
  5113. // convert vertex data into SIMD data
  5114. const float* RESTRICT pPos = pShadowBoundVerts;
  5115. const float* RESTRICT pNormal = pShadowBoundNormals;
  5116. for( int v = 0; v < 6; ++v )
  5117. {
  5118. srcPositions[v].LoadAndSwizzleAligned( pPos, pPos+4, pPos+8, pPos+12);
  5119. pPos += 16;
  5120. }
  5121. srcNormals[0].LoadAndSwizzleAligned( pNormal, pNormal+4, pNormal+8, pNormal+12);
  5122. pNormal += 16;
  5123. srcNormals[1].LoadAndSwizzleAligned( pNormal, pNormal+4, pNormal+4, pNormal+4);
  5124. bSIMDDataInitialized = true;
  5125. }
  5126. Vector fallOffParams;
  5127. ComputeFalloffInfo( shadow, &fallOffParams );
  5128. int nBaseVertIdx = meshBuilder.GetCurrentVertex();
  5129. float texCoord[4] = { shadow.m_TexCoordOffset.x, shadow.m_TexCoordOffset.y, shadow.m_TexCoordScale.x, shadow.m_TexCoordScale.y };
  5130. Vector shadowDir = shadow.m_ShadowDir * shadow.m_MaxDist;
  5131. if ( r_shadow_deferred_simd.GetBool() )
  5132. {
  5133. // FIXME: Something in here is buggy
  5134. FourVectors positions[6];
  5135. FourVectors normals[2];
  5136. positions[0] = srcPositions[0];
  5137. positions[1] = srcPositions[1];
  5138. positions[2] = srcPositions[2];
  5139. positions[3] = srcPositions[3];
  5140. positions[4] = srcPositions[4];
  5141. positions[5] = srcPositions[5];
  5142. positions[0].TransformBy( objToWorld );
  5143. positions[1].TransformBy( objToWorld );
  5144. positions[2].TransformBy( objToWorld );
  5145. positions[3].TransformBy( objToWorld );
  5146. positions[4].TransformBy( objToWorld );
  5147. positions[5].TransformBy( objToWorld );
  5148. //FourVectors::TransformManyBy( srcPositions, 6, objToWorld, positions ); // this doesn't work but the above does. What gives???
  5149. FourVectors::RotateManyBy( srcNormals, 2, objToWorld, normals );
  5150. normals[0].VectorNormalizeFast(); // optional, will throw asserts in debug if we don't normalize
  5151. normals[1].VectorNormalizeFast();
  5152. for( int v = 0; v < ARRAYSIZE( pShadowBoundVerts ) / 4; ++v )
  5153. {
  5154. meshBuilder.Position3fv( positions[v/4].Vec( v%4 ).Base() );
  5155. meshBuilder.Normal3fv( normals[v/16].Vec( (v/4)%4 ).Base() );
  5156. meshBuilder.TexCoord3fv( 0, shadowDir.Base() );
  5157. meshBuilder.TexCoord4fv( 1, texCoord );
  5158. meshBuilder.TexCoord4fv( 2, projToShadow[0] );
  5159. meshBuilder.TexCoord4fv( 3, projToShadow[1] );
  5160. meshBuilder.TexCoord4fv( 4, projToShadow[2] );
  5161. meshBuilder.TexCoord4fv( 5, projToShadow[3] );
  5162. meshBuilder.TexCoord3fv( 6, fallOffParams.Base() );
  5163. meshBuilder.AdvanceVertex();
  5164. }
  5165. }
  5166. else
  5167. {
  5168. const float* pPos = pShadowBoundVerts;
  5169. const float* pNormal = pShadowBoundNormals;
  5170. for( int v = 0; v < ARRAYSIZE( pShadowBoundVerts ) / 4; ++v )
  5171. {
  5172. Vector pos;
  5173. Vector normal;
  5174. VectorTransform( pPos, objToWorld, (float*)&pos );
  5175. VectorRotate( pNormal, objToWorld, (float*)&normal );
  5176. meshBuilder.Position3fv( pos.Base() );
  5177. meshBuilder.Normal3fv( normal.Base() );
  5178. meshBuilder.TexCoord3fv( 0, shadowDir.Base() );
  5179. meshBuilder.TexCoord4fv( 1, texCoord );
  5180. meshBuilder.TexCoord4fv( 2, projToShadow[0] );
  5181. meshBuilder.TexCoord4fv( 3, projToShadow[1] );
  5182. meshBuilder.TexCoord4fv( 4, projToShadow[2] );
  5183. meshBuilder.TexCoord4fv( 5, projToShadow[3] );
  5184. meshBuilder.TexCoord3fv( 6, fallOffParams.Base() );
  5185. meshBuilder.AdvanceVertex();
  5186. pPos += 4;
  5187. if ( v % 4 == 3)
  5188. pNormal += 4;
  5189. }
  5190. }
  5191. for( int i = 0; i < ARRAYSIZE( pShadowBoundIndices ) / 2; ++i )
  5192. {
  5193. // this causes alignment exception on 360?
  5194. //meshBuilder.FastIndex2( nBaseVertIdx + pShadowBoundIndices[2*i], nBaseVertIdx + pShadowBoundIndices[2*i+1] );
  5195. meshBuilder.FastIndex( nBaseVertIdx + pShadowBoundIndices[2*i] );
  5196. meshBuilder.FastIndex( nBaseVertIdx + pShadowBoundIndices[2*i+1] );
  5197. }
  5198. }
  5199. struct IntersectingShadowInfo_t
  5200. {
  5201. ClientShadowHandle_t h;
  5202. matrix3x4_t objToWorld;
  5203. };
  5204. // Sets up rendering info for deferred shadows
  5205. bool CClientShadowMgr::SetupDeferredShadow( const ClientShadow_t& shadow, const Vector& camPos, matrix3x4_t* pObjToWorldMat ) const
  5206. {
  5207. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity );
  5208. Vector mins;
  5209. Vector maxs;
  5210. pRenderable->GetShadowRenderBounds( mins, maxs, GetActualShadowCastType( pRenderable ) );
  5211. Vector center = mins + maxs;
  5212. center *= 0.5f;
  5213. Vector dims = maxs - mins;
  5214. dims *= 0.5f;
  5215. matrix3x4_t scaleAndOffset ( dims.x, 0.0f, 0.0f, center.x,
  5216. 0.0f, dims.y, 0.0f, center.y,
  5217. 0.0f, 0.0f, dims.z, center.z );
  5218. matrix3x4_t objToWorld;
  5219. AngleMatrix( pRenderable->GetRenderAngles(), pRenderable->GetRenderOrigin(), objToWorld );
  5220. matrix3x4_t worldToObj;
  5221. MatrixInvert( objToWorld, worldToObj );
  5222. MatrixMultiply( objToWorld, scaleAndOffset, objToWorld );
  5223. MatrixCopy( objToWorld, *pObjToWorldMat );
  5224. // test if camera is inside shadow volume
  5225. Vector shadowDirObjSpace;
  5226. Vector camPosObjSpace;
  5227. VectorRotate( shadow.m_ShadowDir, worldToObj, shadowDirObjSpace );
  5228. VectorTransform( camPos, worldToObj, camPosObjSpace );
  5229. BoxTraceInfo_t ti;
  5230. if ( IntersectRayWithBox( camPosObjSpace, -shadow.m_MaxDist*shadowDirObjSpace, mins, maxs, 0.0f, &ti ) )
  5231. {
  5232. return true;
  5233. }
  5234. return false;
  5235. }
  5236. void CClientShadowMgr::DownsampleDepthBuffer( IMatRenderContext* pRenderContext, const VMatrix& invViewProjMat )
  5237. {
  5238. int nScreenWidth, nScreenHeight, nDummy;
  5239. pRenderContext->GetViewport( nDummy, nDummy, nScreenWidth, nScreenHeight );
  5240. int nWidth = m_downSampledNormals->GetActualWidth();
  5241. int nHeight = m_downSampledNormals->GetActualHeight();
  5242. pRenderContext->PushRenderTargetAndViewport( m_downSampledNormals, 0, 0, nWidth, nHeight );
  5243. IMaterial* pMat = materials->FindMaterial( "dev/downsampledepth", TEXTURE_GROUP_OTHER );
  5244. // yes, this is stupid
  5245. IMaterialVar* pVar = pMat->FindVar( "$c0_x", NULL );
  5246. pVar->SetFloatValue( invViewProjMat[0][0] );
  5247. pVar = pMat->FindVar( "$c0_y", NULL );
  5248. pVar->SetFloatValue( invViewProjMat[0][1] );
  5249. pVar = pMat->FindVar( "$c0_z", NULL );
  5250. pVar->SetFloatValue( invViewProjMat[0][2] );
  5251. pVar = pMat->FindVar( "$c0_w", NULL );
  5252. pVar->SetFloatValue( invViewProjMat[0][3] );
  5253. pVar = pMat->FindVar( "$c1_x", NULL );
  5254. pVar->SetFloatValue( invViewProjMat[1][0] );
  5255. pVar = pMat->FindVar( "$c1_y", NULL );
  5256. pVar->SetFloatValue( invViewProjMat[1][1] );
  5257. pVar = pMat->FindVar( "$c1_z", NULL );
  5258. pVar->SetFloatValue( invViewProjMat[1][2] );
  5259. pVar = pMat->FindVar( "$c1_w", NULL );
  5260. pVar->SetFloatValue( invViewProjMat[1][3] );
  5261. pVar = pMat->FindVar( "$c2_x", NULL );
  5262. pVar->SetFloatValue( invViewProjMat[2][0] );
  5263. pVar = pMat->FindVar( "$c2_y", NULL );
  5264. pVar->SetFloatValue( invViewProjMat[2][1] );
  5265. pVar = pMat->FindVar( "$c2_z", NULL );
  5266. pVar->SetFloatValue( invViewProjMat[2][2] );
  5267. pVar = pMat->FindVar( "$c2_w", NULL );
  5268. pVar->SetFloatValue( invViewProjMat[2][3] );
  5269. pVar = pMat->FindVar( "$c3_x", NULL );
  5270. pVar->SetFloatValue( invViewProjMat[3][0] );
  5271. pVar = pMat->FindVar( "$c3_y", NULL );
  5272. pVar->SetFloatValue( invViewProjMat[3][1] );
  5273. pVar = pMat->FindVar( "$c3_z", NULL );
  5274. pVar->SetFloatValue( invViewProjMat[3][2] );
  5275. pVar = pMat->FindVar( "$c3_w", NULL );
  5276. pVar->SetFloatValue( invViewProjMat[3][3] );
  5277. pVar = pMat->FindVar( "$c4_x", NULL );
  5278. pVar->SetFloatValue( 1.0f / float( nScreenWidth ) );
  5279. pVar = pMat->FindVar( "$c4_y", NULL );
  5280. pVar->SetFloatValue( 1.0f / float( nScreenHeight ) );
  5281. pRenderContext->DrawScreenSpaceRectangle( pMat, 0, 0, nWidth, nHeight,
  5282. 0, 0, 2*nWidth-2, 2*nHeight-2,
  5283. 2*nWidth, 2*nHeight );
  5284. if ( IsGameConsole() )
  5285. {
  5286. pRenderContext->CopyRenderTargetToTextureEx( m_downSampledNormals, 0, NULL, NULL );
  5287. pRenderContext->CopyRenderTargetToTextureEx( m_downSampledDepth, -1, NULL, NULL );
  5288. }
  5289. pRenderContext->PopRenderTargetAndViewport();
  5290. }
  5291. void CClientShadowMgr::CompositeDeferredShadows( IMatRenderContext* pRenderContext )
  5292. {
  5293. int nWidth, nHeight, nDummy;
  5294. pRenderContext->GetViewport( nDummy, nDummy, nWidth, nHeight );
  5295. IMaterial* pMat = materials->FindMaterial( "dev/compositedeferredshadow", TEXTURE_GROUP_OTHER );
  5296. /*
  5297. IMaterialVar* pMatVar = pMat->FindVar( "$basetexture", NULL, false );
  5298. if ( pMatVar )
  5299. {
  5300. ITexture *pFullScreen = materials->FindTexture( "_rt_FullFrameFB1", TEXTURE_GROUP_RENDER_TARGET );
  5301. pMatVar->SetTextureValue( pFullScreen );
  5302. }
  5303. */
  5304. pRenderContext->DrawScreenSpaceRectangle( pMat, 0, 0, nWidth, nHeight,
  5305. 0, 0, 2*nWidth-2, 2*nHeight-2,
  5306. 2*nWidth, 2*nHeight );
  5307. }
  5308. void CClientShadowMgr::ComputeFalloffInfo( const ClientShadow_t& shadow, Vector* pShadowFalloffParams )
  5309. {
  5310. float flFalloffOffset = 0.7f * shadow.m_FalloffStart; // pull the offset in a little to hide the shadow darkness discontinuity
  5311. float flFalloffDist = shadow.m_MaxDist - flFalloffOffset;
  5312. float flOOZFalloffDist = ( flFalloffDist > 0.0f ) ? 1.0f / flFalloffDist : 1.0f;
  5313. // for use in the shader
  5314. pShadowFalloffParams->x = -flFalloffOffset * flOOZFalloffDist;
  5315. pShadowFalloffParams->y = flOOZFalloffDist;
  5316. pShadowFalloffParams->z = 1.0f/255.0f * shadow.m_FalloffBias;
  5317. }
  5318. void CClientShadowMgr::DrawDeferredShadows( const CViewSetup &view, int leafCount, WorldListLeafData_t* pLeafList )
  5319. {
  5320. VPROF_BUDGET( __FUNCTION__, VPROF_BUDGETGROUP_SHADOW_RENDERING );
  5321. if ( !IsGameConsole() )
  5322. {
  5323. return;
  5324. }
  5325. // We assume the visible shadow list was updated in ComputeShadowTextures. This is only correct if we're not rendering from multiple view points.
  5326. int nNumShadows = s_VisibleShadowList.GetVisibleShadowCount();
  5327. if ( nNumShadows == 0 )
  5328. {
  5329. return;
  5330. }
  5331. IntersectingShadowInfo_t* pInsideVolume = (IntersectingShadowInfo_t*)stackalloc( nNumShadows * sizeof(IntersectingShadowInfo_t) );
  5332. int nNumInsideVolumes = 0;
  5333. CMatRenderContextPtr pRenderContext( materials );
  5334. PIXEVENT( pRenderContext, "DEFERRED_SHADOWS" );
  5335. matrix3x4_t viewMatrix;
  5336. pRenderContext->GetMatrix( MATERIAL_VIEW, &viewMatrix );
  5337. VMatrix projMatrix;
  5338. pRenderContext->GetMatrix( MATERIAL_PROJECTION, &projMatrix );
  5339. VMatrix viewProjMatrix;
  5340. VMatrix invViewProjMatrix;
  5341. MatrixMultiply( projMatrix, VMatrix(viewMatrix), viewProjMatrix );
  5342. MatrixInverseGeneral( viewProjMatrix, invViewProjMatrix );
  5343. ShaderStencilState_t state;
  5344. state.m_bEnable = true;
  5345. state.m_nWriteMask = 0xFF;
  5346. state.m_nTestMask = 0x1 << 2;
  5347. state.m_nReferenceValue = 0x0;
  5348. state.m_CompareFunc = SHADER_STENCILFUNC_EQUAL;
  5349. state.m_PassOp = SHADER_STENCILOP_KEEP;
  5350. state.m_FailOp = SHADER_STENCILOP_KEEP;
  5351. state.m_ZFailOp = SHADER_STENCILOP_KEEP;
  5352. #if defined( _X360 )
  5353. state.m_bHiStencilEnable = true;
  5354. state.m_bHiStencilWriteEnable = false;
  5355. state.m_HiStencilCompareFunc = SHADER_HI_STENCILFUNC_EQUAL;
  5356. state.m_nHiStencilReferenceValue = 0;
  5357. #endif
  5358. #ifdef _X360
  5359. pRenderContext->PushVertexShaderGPRAllocation( 16 );
  5360. #endif
  5361. if ( r_shadow_deferred_downsample.GetBool() )
  5362. {
  5363. DownsampleDepthBuffer( pRenderContext, invViewProjMatrix );
  5364. int nWidth = m_downSampledNormals->GetActualWidth();
  5365. int nHeight = m_downSampledNormals->GetActualHeight();
  5366. pRenderContext->PushRenderTargetAndViewport( m_downSampledNormals, 0, 0, nWidth, nHeight );
  5367. }
  5368. else
  5369. {
  5370. pRenderContext->SetStencilState( state );
  5371. #if defined( _X360 )
  5372. pRenderContext->FlushHiStencil();
  5373. #endif
  5374. }
  5375. pRenderContext->MatrixMode( MATERIAL_MODEL );
  5376. pRenderContext->PushMatrix();
  5377. pRenderContext->LoadIdentity();
  5378. IMaterialVar* pTextureVar = m_RenderDeferredShadowMat->FindVar( "$basetexture", NULL, false );
  5379. if( pTextureVar )
  5380. {
  5381. pTextureVar->SetTextureValue( s_ClientShadowMgr.GetShadowTexture( CLIENTSHADOW_INVALID_HANDLE ) );
  5382. }
  5383. pTextureVar = m_RenderDeferredShadowMat->FindVar( "$depthtexture", NULL, false );
  5384. if( pTextureVar )
  5385. {
  5386. //pTextureVar->SetTextureValue( s_ClientShadowMgr.GetShadowTexture( CLIENTSHADOW_INVALID_HANDLE ) );
  5387. pTextureVar->SetTextureValue( GetFullFrameDepthTexture() );
  5388. }
  5389. IMaterialVar* pZFailVar = m_RenderDeferredShadowMat->FindVar( "$zfailenable", NULL, false );
  5390. if( pZFailVar )
  5391. {
  5392. pZFailVar->SetIntValue( 0 );
  5393. }
  5394. pRenderContext->Bind( m_RenderDeferredShadowMat );
  5395. Vector camPos;
  5396. pRenderContext->GetWorldSpaceCameraPosition( &camPos );
  5397. IMesh* pMesh = pRenderContext->GetDynamicMesh();
  5398. CMeshBuilder meshBuilder;
  5399. int nMaxVerts, nMaxIndices;
  5400. pRenderContext->GetMaxToRender( pMesh, false, &nMaxVerts, &nMaxIndices );
  5401. int nMaxShadowsPerBatch = MIN( nMaxVerts / ( ARRAYSIZE( pShadowBoundVerts ) / 4 ), nMaxIndices / ARRAYSIZE( pShadowBoundIndices ) );
  5402. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundVerts ) / 4, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundIndices ) );
  5403. int nNumShadowsBatched = 0;
  5404. // Z-Pass shadow volumes
  5405. for ( int i = 0; i < nNumShadows; ++i )
  5406. {
  5407. const VisibleShadowInfo_t& vsi = s_VisibleShadowList.GetVisibleShadow( i );
  5408. ClientShadow_t& shadow = m_Shadows[vsi.m_hShadow];
  5409. matrix3x4_t objToWorld;
  5410. if ( SetupDeferredShadow( shadow, camPos, &objToWorld ) )
  5411. {
  5412. pInsideVolume[nNumInsideVolumes].h = vsi.m_hShadow;
  5413. MatrixCopy( objToWorld, pInsideVolume[nNumInsideVolumes].objToWorld );
  5414. nNumInsideVolumes++;
  5415. continue;
  5416. }
  5417. VMatrix projToTextureMatrix;
  5418. MatrixMultiply( shadow.m_WorldToTexture, invViewProjMatrix, projToTextureMatrix );
  5419. // create extruded bounding geometry
  5420. BuildCubeWithDegenerateEdgeQuads( meshBuilder, objToWorld, projToTextureMatrix, shadow );
  5421. nNumShadowsBatched++;
  5422. if ( nNumShadowsBatched == nMaxShadowsPerBatch )
  5423. {
  5424. // flush
  5425. meshBuilder.End();
  5426. pMesh->Draw();
  5427. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundVerts ) / 4, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundIndices ) );
  5428. nNumShadowsBatched = 0;
  5429. }
  5430. }
  5431. // render
  5432. meshBuilder.End();
  5433. if ( nNumShadowsBatched > 0 )
  5434. {
  5435. pMesh->Draw();
  5436. nNumShadowsBatched = 0;
  5437. }
  5438. else
  5439. {
  5440. pMesh->MarkAsDrawn();
  5441. }
  5442. // draw deferred blobby shadow volumes
  5443. if ( s_VisibleShadowList.GetVisibleBlobbyShadowCount() > 0 )
  5444. {
  5445. pRenderContext->Bind( m_RenderDeferredSimpleShadowMat );
  5446. pTextureVar = m_RenderDeferredSimpleShadowMat->FindVar( "$depthtexture", NULL, false );
  5447. if( pTextureVar )
  5448. {
  5449. pTextureVar->SetTextureValue( GetFullFrameDepthTexture() );
  5450. }
  5451. int nNumShadows = s_VisibleShadowList.GetVisibleBlobbyShadowCount();
  5452. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundVerts ) / 4, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundIndices ) );
  5453. for ( int i = 0; i < nNumShadows; ++i )
  5454. {
  5455. const VisibleShadowInfo_t& vsi = s_VisibleShadowList.GetVisibleBlobbyShadow( i );
  5456. ClientShadow_t& shadow = m_Shadows[vsi.m_hShadow];
  5457. matrix3x4_t objToWorld;
  5458. if ( SetupDeferredShadow( shadow, camPos, &objToWorld ) )
  5459. {
  5460. //DevWarning( "Blobby shadow needs z-fail rendering. Skipped.\n" );
  5461. continue;
  5462. }
  5463. VMatrix projToTextureMatrix;
  5464. MatrixMultiply( shadow.m_WorldToTexture, invViewProjMatrix, projToTextureMatrix );
  5465. // create extruded bounding geometry
  5466. BuildCubeWithDegenerateEdgeQuads( meshBuilder, objToWorld, projToTextureMatrix, shadow );
  5467. nNumShadowsBatched++;
  5468. if ( nNumShadowsBatched == nMaxShadowsPerBatch )
  5469. {
  5470. // flush
  5471. meshBuilder.End();
  5472. pMesh->Draw();
  5473. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundVerts ) / 4, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundIndices ) );
  5474. nNumShadowsBatched = 0;
  5475. }
  5476. }
  5477. // render
  5478. meshBuilder.End();
  5479. if ( nNumShadowsBatched > 0 )
  5480. {
  5481. pMesh->Draw();
  5482. nNumShadowsBatched = 0;
  5483. }
  5484. else
  5485. {
  5486. pMesh->MarkAsDrawn();
  5487. }
  5488. }
  5489. // draw zfail volumes
  5490. if ( nNumInsideVolumes > 0 )
  5491. {
  5492. pRenderContext->CullMode( MATERIAL_CULLMODE_CW );
  5493. if( pZFailVar )
  5494. {
  5495. pZFailVar->SetIntValue( 1 );
  5496. }
  5497. pRenderContext->Bind( m_RenderDeferredShadowMat );
  5498. //IMesh* pMesh = pRenderContext->GetDynamicMesh();
  5499. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundVerts ) / 4, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundIndices ) );
  5500. for ( int i = 0; i < nNumInsideVolumes; ++i )
  5501. {
  5502. ClientShadow_t& shadow = m_Shadows[pInsideVolume[i].h];
  5503. VMatrix projToTextureMatrix;
  5504. MatrixMultiply( shadow.m_WorldToTexture, invViewProjMatrix, projToTextureMatrix );
  5505. // create extruded bounding geometry
  5506. BuildCubeWithDegenerateEdgeQuads( meshBuilder, pInsideVolume[i].objToWorld, projToTextureMatrix, shadow );
  5507. nNumShadowsBatched++;
  5508. if ( nNumShadowsBatched == nMaxShadowsPerBatch )
  5509. {
  5510. // flush
  5511. meshBuilder.End();
  5512. pMesh->Draw();
  5513. //pMesh = pRenderContext->GetDynamicMesh();
  5514. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundVerts ) / 4, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundIndices ) );
  5515. nNumShadowsBatched = 0;
  5516. }
  5517. }
  5518. meshBuilder.End();
  5519. if ( nNumShadowsBatched > 0 )
  5520. {
  5521. pMesh->Draw();
  5522. nNumShadowsBatched = 0;
  5523. }
  5524. else
  5525. {
  5526. pMesh->MarkAsDrawn();
  5527. }
  5528. }
  5529. pRenderContext->PopMatrix();
  5530. // reset culling
  5531. pRenderContext->CullMode( MATERIAL_CULLMODE_CCW );
  5532. if ( r_shadow_deferred_downsample.GetBool() )
  5533. {
  5534. pRenderContext->CopyRenderTargetToTextureEx( m_downSampledNormals, 0, NULL, NULL );
  5535. pRenderContext->PopRenderTargetAndViewport();
  5536. pRenderContext->SetStencilState( state );
  5537. CompositeDeferredShadows( pRenderContext );
  5538. }
  5539. ShaderStencilState_t stateDisable;
  5540. stateDisable.m_bEnable = false;
  5541. #if defined( _X360 )
  5542. stateDisable.m_bHiStencilEnable = false;
  5543. stateDisable.m_bHiStencilWriteEnable = false;
  5544. #endif
  5545. pRenderContext->SetStencilState( stateDisable );
  5546. #ifdef _X360
  5547. pRenderContext->PopVertexShaderGPRAllocation();
  5548. #endif
  5549. // NOTE: We could use geometry instancing for drawing the extruded bounding boxes
  5550. }
  5551. void DeferredShadowToggleCallback( IConVar*, const char *, float )
  5552. {
  5553. if ( !IsGameConsole() )
  5554. {
  5555. DevMsg( "Deferred shadow rendering only supported on the 360.\n" );
  5556. return;
  5557. }
  5558. s_ClientShadowMgr.UpdateAllShadows();
  5559. s_ClientShadowMgr.RemoveAllShadowDecals();
  5560. }
  5561. void DeferredShadowDownsampleToggleCallback( IConVar *var, const char *pOldValue, float flOldValue )
  5562. {
  5563. s_ClientShadowMgr.ShutdownDeferredShadows();
  5564. s_ClientShadowMgr.InitDeferredShadows();
  5565. }
  5566. void CClientShadowMgr::UpdateSplitscreenLocalPlayerShadowSkip()
  5567. {
  5568. // Don't draw the current splitscreen player's own shadow
  5569. if ( engine->IsSplitScreenActive() )
  5570. {
  5571. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  5572. C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer();
  5573. C_BasePlayer* pFirstPersonEnt = pPlayer;
  5574. if ( pPlayer )
  5575. {
  5576. if ( pPlayer->GetObserverMode() == OBS_MODE_IN_EYE )
  5577. {
  5578. pFirstPersonEnt = ToBasePlayer( pPlayer->GetObserverTarget() );
  5579. }
  5580. else if ( pPlayer->GetObserverMode() != OBS_MODE_NONE )
  5581. {
  5582. pFirstPersonEnt = NULL;
  5583. }
  5584. }
  5585. // pFirstPersonEnt NULL only if the player is spectating, but not first-person-spectating
  5586. if ( pFirstPersonEnt )
  5587. {
  5588. shadowmgr->SkipShadowForEntity( pFirstPersonEnt->entindex() );
  5589. }
  5590. else
  5591. {
  5592. shadowmgr->SkipShadowForEntity( INT_MIN ); // pick an entindex that is guaranteed not to be used by anything
  5593. }
  5594. }
  5595. else
  5596. {
  5597. shadowmgr->SkipShadowForEntity( INT_MIN ); // pick an entindex that is guaranteed not to be used by anything
  5598. }
  5599. }
  5600. //-----------------------------------------------------------------------------
  5601. // A material proxy that resets the base texture to use the rendered shadow
  5602. //-----------------------------------------------------------------------------
  5603. class CShadowProxy : public IMaterialProxy
  5604. {
  5605. public:
  5606. CShadowProxy();
  5607. virtual ~CShadowProxy();
  5608. virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
  5609. virtual void OnBind( void *pProxyData );
  5610. virtual void Release( void ) { delete this; }
  5611. virtual IMaterial *GetMaterial();
  5612. private:
  5613. IMaterialVar* m_BaseTextureVar;
  5614. IMaterialVar* m_MaxFalloffAmountVar;
  5615. };
  5616. CShadowProxy::CShadowProxy()
  5617. : m_BaseTextureVar( NULL ),
  5618. m_MaxFalloffAmountVar( NULL )
  5619. {
  5620. }
  5621. CShadowProxy::~CShadowProxy()
  5622. {
  5623. }
  5624. bool CShadowProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
  5625. {
  5626. bool foundVar;
  5627. m_BaseTextureVar = pMaterial->FindVar( "$basetexture", &foundVar, false );
  5628. if ( !foundVar )
  5629. return false;
  5630. m_MaxFalloffAmountVar = pMaterial->FindVar( "$maxfalloffamount", &foundVar, false );
  5631. return foundVar;
  5632. }
  5633. void CShadowProxy::OnBind( void *pProxyData )
  5634. {
  5635. unsigned short clientShadowHandle = ( unsigned short )(intp)pProxyData&0xffff;
  5636. ITexture* pTex = s_ClientShadowMgr.GetShadowTexture( clientShadowHandle );
  5637. m_BaseTextureVar->SetTextureValue( pTex );
  5638. m_MaxFalloffAmountVar->SetFloatValue( MAX_FALLOFF_AMOUNT );
  5639. }
  5640. IMaterial *CShadowProxy::GetMaterial()
  5641. {
  5642. return m_BaseTextureVar->GetOwningMaterial();
  5643. }
  5644. EXPOSE_MATERIAL_PROXY( CShadowProxy, Shadow );
  5645. //-----------------------------------------------------------------------------
  5646. // A material proxy that resets the base texture to use the rendered shadow
  5647. //-----------------------------------------------------------------------------
  5648. class CShadowModelProxy : public IMaterialProxy
  5649. {
  5650. public:
  5651. CShadowModelProxy();
  5652. virtual ~CShadowModelProxy();
  5653. virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
  5654. virtual void OnBind( void *pProxyData );
  5655. virtual void Release( void ) { delete this; }
  5656. virtual IMaterial *GetMaterial();
  5657. private:
  5658. IMaterialVar* m_BaseTextureVar;
  5659. IMaterialVar* m_BaseTextureOffsetVar;
  5660. IMaterialVar* m_BaseTextureScaleVar;
  5661. IMaterialVar* m_BaseTextureMatrixVar;
  5662. IMaterialVar* m_FalloffOffsetVar;
  5663. IMaterialVar* m_FalloffDistanceVar;
  5664. IMaterialVar* m_FalloffAmountVar;
  5665. };
  5666. CShadowModelProxy::CShadowModelProxy()
  5667. {
  5668. m_BaseTextureVar = NULL;
  5669. m_BaseTextureOffsetVar = NULL;
  5670. m_BaseTextureScaleVar = NULL;
  5671. m_BaseTextureMatrixVar = NULL;
  5672. m_FalloffOffsetVar = NULL;
  5673. m_FalloffDistanceVar = NULL;
  5674. m_FalloffAmountVar = NULL;
  5675. }
  5676. CShadowModelProxy::~CShadowModelProxy()
  5677. {
  5678. }
  5679. bool CShadowModelProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
  5680. {
  5681. bool foundVar;
  5682. m_BaseTextureVar = pMaterial->FindVar( "$basetexture", &foundVar, false );
  5683. if (!foundVar)
  5684. return false;
  5685. m_BaseTextureOffsetVar = pMaterial->FindVar( "$basetextureoffset", &foundVar, false );
  5686. if (!foundVar)
  5687. return false;
  5688. m_BaseTextureScaleVar = pMaterial->FindVar( "$basetexturescale", &foundVar, false );
  5689. if (!foundVar)
  5690. return false;
  5691. m_BaseTextureMatrixVar = pMaterial->FindVar( "$basetexturetransform", &foundVar, false );
  5692. if (!foundVar)
  5693. return false;
  5694. m_FalloffOffsetVar = pMaterial->FindVar( "$falloffoffset", &foundVar, false );
  5695. if (!foundVar)
  5696. return false;
  5697. m_FalloffDistanceVar = pMaterial->FindVar( "$falloffdistance", &foundVar, false );
  5698. if (!foundVar)
  5699. return false;
  5700. m_FalloffAmountVar = pMaterial->FindVar( "$falloffamount", &foundVar, false );
  5701. return foundVar;
  5702. }
  5703. void CShadowModelProxy::OnBind( void *pProxyData )
  5704. {
  5705. unsigned short clientShadowHandle = ( unsigned short )((intp)pProxyData&0xffff);
  5706. ITexture* pTex = s_ClientShadowMgr.GetShadowTexture( clientShadowHandle );
  5707. m_BaseTextureVar->SetTextureValue( pTex );
  5708. const ShadowInfo_t& info = s_ClientShadowMgr.GetShadowInfo( clientShadowHandle );
  5709. m_BaseTextureMatrixVar->SetMatrixValue( info.m_WorldToShadow );
  5710. m_BaseTextureOffsetVar->SetVecValue( info.m_TexOrigin.Base(), 2 );
  5711. m_BaseTextureScaleVar->SetVecValue( info.m_TexSize.Base(), 2 );
  5712. m_FalloffOffsetVar->SetFloatValue( info.m_FalloffOffset );
  5713. m_FalloffDistanceVar->SetFloatValue( info.m_MaxDist );
  5714. m_FalloffAmountVar->SetFloatValue( info.m_FalloffAmount );
  5715. }
  5716. IMaterial *CShadowModelProxy::GetMaterial()
  5717. {
  5718. return m_BaseTextureVar->GetOwningMaterial();
  5719. }
  5720. EXPOSE_MATERIAL_PROXY( CShadowModelProxy, ShadowModel );