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

4335 lines
146 KiB

  1. //========= Copyright 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. #include "cbase.h"
  57. #include "engine/ishadowmgr.h"
  58. #include "model_types.h"
  59. #include "bitmap/imageformat.h"
  60. #include "materialsystem/imaterialproxy.h"
  61. #include "materialsystem/imaterialvar.h"
  62. #include "materialsystem/imaterial.h"
  63. #include "materialsystem/imesh.h"
  64. #include "materialsystem/itexture.h"
  65. #include "bsptreedata.h"
  66. #include "utlmultilist.h"
  67. #include "collisionutils.h"
  68. #include "iviewrender.h"
  69. #include "ivrenderview.h"
  70. #include "tier0/vprof.h"
  71. #include "engine/ivmodelinfo.h"
  72. #include "view_shared.h"
  73. #include "engine/ivdebugoverlay.h"
  74. #include "engine/IStaticPropMgr.h"
  75. #include "datacache/imdlcache.h"
  76. #include "viewrender.h"
  77. #include "tier0/icommandline.h"
  78. #include "vstdlib/jobthread.h"
  79. #include "toolframework_client.h"
  80. #include "bonetoworldarray.h"
  81. #include "cmodel.h"
  82. // memdbgon must be the last include file in a .cpp file!!!
  83. #include "tier0/memdbgon.h"
  84. static ConVar r_flashlightdrawfrustum( "r_flashlightdrawfrustum", "0" );
  85. static ConVar r_flashlightmodels( "r_flashlightmodels", "1" );
  86. static ConVar r_shadowrendertotexture( "r_shadowrendertotexture", "0" );
  87. static ConVar r_flashlight_version2( "r_flashlight_version2", "0", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY );
  88. ConVar r_flashlightdepthtexture( "r_flashlightdepthtexture", "1", FCVAR_ALLOWED_IN_COMPETITIVE );
  89. #if defined( _X360 )
  90. ConVar r_flashlightdepthres( "r_flashlightdepthres", "512" );
  91. #else
  92. ConVar r_flashlightdepthres( "r_flashlightdepthres", "1024" );
  93. #endif
  94. ConVar r_threaded_client_shadow_manager( "r_threaded_client_shadow_manager", "0" );
  95. #ifdef _WIN32
  96. #pragma warning( disable: 4701 )
  97. #endif
  98. // forward declarations
  99. void ToolFramework_RecordMaterialParams( IMaterial *pMaterial );
  100. //-----------------------------------------------------------------------------
  101. // A texture allocator used to batch textures together
  102. // At the moment, the implementation simply allocates blocks of max 256x256
  103. // and each block stores an array of uniformly-sized textures
  104. //-----------------------------------------------------------------------------
  105. typedef unsigned short TextureHandle_t;
  106. enum
  107. {
  108. INVALID_TEXTURE_HANDLE = (TextureHandle_t)~0
  109. };
  110. class CTextureAllocator
  111. {
  112. public:
  113. // Initialize the allocator with something that knows how to refresh the bits
  114. void Init();
  115. void Shutdown();
  116. // Resets the allocator
  117. void Reset();
  118. // Deallocates everything
  119. void DeallocateAllTextures();
  120. // Allocate, deallocate texture
  121. TextureHandle_t AllocateTexture( int w, int h );
  122. void DeallocateTexture( TextureHandle_t h );
  123. // Mark texture as being used... (return true if re-render is needed)
  124. bool UseTexture( TextureHandle_t h, bool bWillRedraw, float flArea );
  125. bool HasValidTexture( TextureHandle_t h );
  126. // Advance frame...
  127. void AdvanceFrame();
  128. // Get at the location of the texture
  129. void GetTextureRect(TextureHandle_t handle, int& x, int& y, int& w, int& h );
  130. // Get at the texture it's a part of
  131. ITexture *GetTexture();
  132. // Get at the total texture size.
  133. void GetTotalTextureSize( int& w, int& h );
  134. void DebugPrintCache( void );
  135. private:
  136. typedef unsigned short FragmentHandle_t;
  137. enum
  138. {
  139. INVALID_FRAGMENT_HANDLE = (FragmentHandle_t)~0,
  140. TEXTURE_PAGE_SIZE = 1024,
  141. MAX_TEXTURE_POWER = 8,
  142. #if !defined( _X360 )
  143. MIN_TEXTURE_POWER = 4,
  144. #else
  145. MIN_TEXTURE_POWER = 5, // per resolve requirements to ensure 32x32 aligned offsets
  146. #endif
  147. MAX_TEXTURE_SIZE = (1 << MAX_TEXTURE_POWER),
  148. MIN_TEXTURE_SIZE = (1 << MIN_TEXTURE_POWER),
  149. BLOCK_SIZE = MAX_TEXTURE_SIZE,
  150. BLOCKS_PER_ROW = (TEXTURE_PAGE_SIZE / MAX_TEXTURE_SIZE),
  151. BLOCK_COUNT = (BLOCKS_PER_ROW * BLOCKS_PER_ROW),
  152. };
  153. struct TextureInfo_t
  154. {
  155. FragmentHandle_t m_Fragment;
  156. unsigned short m_Size;
  157. unsigned short m_Power;
  158. };
  159. struct FragmentInfo_t
  160. {
  161. unsigned short m_Block;
  162. unsigned short m_Index;
  163. TextureHandle_t m_Texture;
  164. // Makes sure we don't overflow
  165. unsigned int m_FrameUsed;
  166. };
  167. struct BlockInfo_t
  168. {
  169. unsigned short m_FragmentPower;
  170. };
  171. struct Cache_t
  172. {
  173. unsigned short m_List;
  174. };
  175. // Adds a block worth of fragments to the LRU
  176. void AddBlockToLRU( int block );
  177. // Unlink fragment from cache
  178. void UnlinkFragmentFromCache( Cache_t& cache, FragmentHandle_t fragment );
  179. // Mark something as being used (MRU)..
  180. void MarkUsed( FragmentHandle_t fragment );
  181. // Mark something as being unused (LRU)..
  182. void MarkUnused( FragmentHandle_t fragment );
  183. // Disconnect texture from fragment
  184. void DisconnectTextureFromFragment( FragmentHandle_t f );
  185. // Returns the size of a particular fragment
  186. int GetFragmentPower( FragmentHandle_t f ) const;
  187. // Stores the actual texture we're writing into
  188. CTextureReference m_TexturePage;
  189. CUtlLinkedList< TextureInfo_t, TextureHandle_t > m_Textures;
  190. CUtlMultiList< FragmentInfo_t, FragmentHandle_t > m_Fragments;
  191. Cache_t m_Cache[MAX_TEXTURE_POWER+1];
  192. BlockInfo_t m_Blocks[BLOCK_COUNT];
  193. unsigned int m_CurrentFrame;
  194. };
  195. //-----------------------------------------------------------------------------
  196. // Allocate/deallocate the texture page
  197. //-----------------------------------------------------------------------------
  198. void CTextureAllocator::Init()
  199. {
  200. for ( int i = 0; i <= MAX_TEXTURE_POWER; ++i )
  201. {
  202. m_Cache[i].m_List = m_Fragments.InvalidIndex();
  203. }
  204. #if !defined( _X360 )
  205. // don't need depth buffer for shadows
  206. m_TexturePage.InitRenderTarget( TEXTURE_PAGE_SIZE, TEXTURE_PAGE_SIZE, RT_SIZE_NO_CHANGE, IMAGE_FORMAT_ARGB8888, MATERIAL_RT_DEPTH_NONE, false, "_rt_Shadows" );
  207. #else
  208. // unfortunate explicit management required for this render target
  209. // 32bpp edram is only largest shadow fragment, but resolved to actual shadow atlas
  210. // because full-res 1024x1024 shadow buffer is too large for EDRAM
  211. m_TexturePage.InitRenderTargetTexture( TEXTURE_PAGE_SIZE, TEXTURE_PAGE_SIZE, RT_SIZE_NO_CHANGE, IMAGE_FORMAT_ARGB8888, MATERIAL_RT_DEPTH_NONE, false, "_rt_Shadows" );
  212. // edram footprint is only 256x256x4 = 256K
  213. m_TexturePage.InitRenderTargetSurface( MAX_TEXTURE_SIZE, MAX_TEXTURE_SIZE, IMAGE_FORMAT_ARGB8888, false );
  214. // due to texture/surface size mismatch, ensure texture page is entirely cleared translucent
  215. // otherwise border artifacts at edge of shadows due to pixel shader averaging of unwanted bits
  216. m_TexturePage->ClearTexture( 0, 0, 0, 0 );
  217. #endif
  218. }
  219. void CTextureAllocator::Shutdown()
  220. {
  221. m_TexturePage.Shutdown();
  222. }
  223. //-----------------------------------------------------------------------------
  224. // Initialize the allocator with something that knows how to refresh the bits
  225. //-----------------------------------------------------------------------------
  226. void CTextureAllocator::Reset()
  227. {
  228. DeallocateAllTextures();
  229. m_Textures.EnsureCapacity(256);
  230. m_Fragments.EnsureCapacity(256);
  231. // Set up the block sizes....
  232. // FIXME: Improve heuristic?!?
  233. #if !defined( _X360 )
  234. m_Blocks[0].m_FragmentPower = MAX_TEXTURE_POWER-4; // 128 cells at ExE resolution
  235. #else
  236. m_Blocks[0].m_FragmentPower = MAX_TEXTURE_POWER-3; // 64 cells at DxD resolution
  237. #endif
  238. m_Blocks[1].m_FragmentPower = MAX_TEXTURE_POWER-3; // 64 cells at DxD resolution
  239. m_Blocks[2].m_FragmentPower = MAX_TEXTURE_POWER-2; // 32 cells at CxC resolution
  240. m_Blocks[3].m_FragmentPower = MAX_TEXTURE_POWER-2;
  241. m_Blocks[4].m_FragmentPower = MAX_TEXTURE_POWER-1; // 24 cells at BxB resolution
  242. m_Blocks[5].m_FragmentPower = MAX_TEXTURE_POWER-1;
  243. m_Blocks[6].m_FragmentPower = MAX_TEXTURE_POWER-1;
  244. m_Blocks[7].m_FragmentPower = MAX_TEXTURE_POWER-1;
  245. m_Blocks[8].m_FragmentPower = MAX_TEXTURE_POWER-1;
  246. m_Blocks[9].m_FragmentPower = MAX_TEXTURE_POWER-1;
  247. m_Blocks[10].m_FragmentPower = MAX_TEXTURE_POWER; // 6 cells at AxA resolution
  248. m_Blocks[11].m_FragmentPower = MAX_TEXTURE_POWER;
  249. m_Blocks[12].m_FragmentPower = MAX_TEXTURE_POWER;
  250. m_Blocks[13].m_FragmentPower = MAX_TEXTURE_POWER;
  251. m_Blocks[14].m_FragmentPower = MAX_TEXTURE_POWER;
  252. m_Blocks[15].m_FragmentPower = MAX_TEXTURE_POWER;
  253. // Initialize the LRU
  254. int i;
  255. for ( i = 0; i <= MAX_TEXTURE_POWER; ++i )
  256. {
  257. m_Cache[i].m_List = m_Fragments.CreateList();
  258. }
  259. // Now that the block sizes are allocated, create LRUs for the various block sizes
  260. for ( i = 0; i < BLOCK_COUNT; ++i)
  261. {
  262. // Initialize LRU
  263. AddBlockToLRU( i );
  264. }
  265. m_CurrentFrame = 0;
  266. }
  267. void CTextureAllocator::DeallocateAllTextures()
  268. {
  269. m_Textures.Purge();
  270. m_Fragments.Purge();
  271. for ( int i = 0; i <= MAX_TEXTURE_POWER; ++i )
  272. {
  273. m_Cache[i].m_List = m_Fragments.InvalidIndex();
  274. }
  275. }
  276. //-----------------------------------------------------------------------------
  277. // Dump the state of the cache to debug out
  278. //-----------------------------------------------------------------------------
  279. void CTextureAllocator::DebugPrintCache( void )
  280. {
  281. // For each fragment
  282. int nNumFragments = m_Fragments.TotalCount();
  283. int nNumInvalidFragments = 0;
  284. Warning("Fragments (%d):\n===============\n", nNumFragments);
  285. for ( int f = 0; f < nNumFragments; f++ )
  286. {
  287. if ( ( m_Fragments[f].m_FrameUsed != 0 ) && ( m_Fragments[f].m_Texture != INVALID_TEXTURE_HANDLE ) )
  288. 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 );
  289. else
  290. nNumInvalidFragments++;
  291. }
  292. Warning("Invalid Fragments: %d\n", nNumInvalidFragments);
  293. // for ( int c = 0; c <= MAX_TEXTURE_POWER; ++c )
  294. // {
  295. // Warning("Cache Index (%d)\n", m_Cache[c].m_List);
  296. // }
  297. }
  298. //-----------------------------------------------------------------------------
  299. // Adds a block worth of fragments to the LRU
  300. //-----------------------------------------------------------------------------
  301. void CTextureAllocator::AddBlockToLRU( int block )
  302. {
  303. int power = m_Blocks[block].m_FragmentPower;
  304. int size = (1 << power);
  305. // Compute the number of fragments in this block
  306. int fragmentCount = MAX_TEXTURE_SIZE / size;
  307. fragmentCount *= fragmentCount;
  308. // For each fragment, indicate which block it's a part of (and the index)
  309. // and then stick in at the top of the LRU
  310. while (--fragmentCount >= 0 )
  311. {
  312. FragmentHandle_t f = m_Fragments.Alloc( );
  313. m_Fragments[f].m_Block = block;
  314. m_Fragments[f].m_Index = fragmentCount;
  315. m_Fragments[f].m_Texture = INVALID_TEXTURE_HANDLE;
  316. m_Fragments[f].m_FrameUsed = 0xFFFFFFFF;
  317. m_Fragments.LinkToHead( m_Cache[power].m_List, f );
  318. }
  319. }
  320. //-----------------------------------------------------------------------------
  321. // Unlink fragment from cache
  322. //-----------------------------------------------------------------------------
  323. void CTextureAllocator::UnlinkFragmentFromCache( Cache_t& cache, FragmentHandle_t fragment )
  324. {
  325. m_Fragments.Unlink( cache.m_List, fragment);
  326. }
  327. //-----------------------------------------------------------------------------
  328. // Mark something as being used (MRU)..
  329. //-----------------------------------------------------------------------------
  330. void CTextureAllocator::MarkUsed( FragmentHandle_t fragment )
  331. {
  332. int block = m_Fragments[fragment].m_Block;
  333. int power = m_Blocks[block].m_FragmentPower;
  334. // Hook it at the end of the LRU
  335. Cache_t& cache = m_Cache[power];
  336. m_Fragments.LinkToTail( cache.m_List, fragment );
  337. m_Fragments[fragment].m_FrameUsed = m_CurrentFrame;
  338. }
  339. //-----------------------------------------------------------------------------
  340. // Mark something as being unused (LRU)..
  341. //-----------------------------------------------------------------------------
  342. void CTextureAllocator::MarkUnused( FragmentHandle_t fragment )
  343. {
  344. int block = m_Fragments[fragment].m_Block;
  345. int power = m_Blocks[block].m_FragmentPower;
  346. // Hook it at the end of the LRU
  347. Cache_t& cache = m_Cache[power];
  348. m_Fragments.LinkToHead( cache.m_List, fragment );
  349. }
  350. //-----------------------------------------------------------------------------
  351. // Allocate, deallocate texture
  352. //-----------------------------------------------------------------------------
  353. TextureHandle_t CTextureAllocator::AllocateTexture( int w, int h )
  354. {
  355. // Implementational detail for now
  356. Assert( w == h );
  357. // Clamp texture size
  358. if (w < MIN_TEXTURE_SIZE)
  359. w = MIN_TEXTURE_SIZE;
  360. else if (w > MAX_TEXTURE_SIZE)
  361. w = MAX_TEXTURE_SIZE;
  362. TextureHandle_t handle = m_Textures.AddToTail();
  363. m_Textures[handle].m_Fragment = INVALID_FRAGMENT_HANDLE;
  364. m_Textures[handle].m_Size = w;
  365. // Find the power of two
  366. int power = 0;
  367. int size = 1;
  368. while(size < w)
  369. {
  370. size <<= 1;
  371. ++power;
  372. }
  373. Assert( size == w );
  374. m_Textures[handle].m_Power = power;
  375. return handle;
  376. }
  377. void CTextureAllocator::DeallocateTexture( TextureHandle_t h )
  378. {
  379. // Warning("Beginning of DeallocateTexture\n");
  380. // DebugPrintCache();
  381. if (m_Textures[h].m_Fragment != INVALID_FRAGMENT_HANDLE)
  382. {
  383. MarkUnused(m_Textures[h].m_Fragment);
  384. m_Fragments[m_Textures[h].m_Fragment].m_FrameUsed = 0xFFFFFFFF; // non-zero frame
  385. DisconnectTextureFromFragment( m_Textures[h].m_Fragment );
  386. }
  387. m_Textures.Remove(h);
  388. // Warning("End of DeallocateTexture\n");
  389. // DebugPrintCache();
  390. }
  391. //-----------------------------------------------------------------------------
  392. // Disconnect texture from fragment
  393. //-----------------------------------------------------------------------------
  394. void CTextureAllocator::DisconnectTextureFromFragment( FragmentHandle_t f )
  395. {
  396. // Warning( "Beginning of DisconnectTextureFromFragment\n" );
  397. // DebugPrintCache();
  398. FragmentInfo_t& info = m_Fragments[f];
  399. if (info.m_Texture != INVALID_TEXTURE_HANDLE)
  400. {
  401. m_Textures[info.m_Texture].m_Fragment = INVALID_FRAGMENT_HANDLE;
  402. info.m_Texture = INVALID_TEXTURE_HANDLE;
  403. }
  404. // Warning( "End of DisconnectTextureFromFragment\n" );
  405. // DebugPrintCache();
  406. }
  407. //-----------------------------------------------------------------------------
  408. // Do we have a valid texture assigned?
  409. //-----------------------------------------------------------------------------
  410. bool CTextureAllocator::HasValidTexture( TextureHandle_t h )
  411. {
  412. TextureInfo_t& info = m_Textures[h];
  413. FragmentHandle_t currentFragment = info.m_Fragment;
  414. return (currentFragment != INVALID_FRAGMENT_HANDLE);
  415. }
  416. //-----------------------------------------------------------------------------
  417. // Mark texture as being used...
  418. //-----------------------------------------------------------------------------
  419. bool CTextureAllocator::UseTexture( TextureHandle_t h, bool bWillRedraw, float flArea )
  420. {
  421. // Warning( "Top of UseTexture\n" );
  422. // DebugPrintCache();
  423. TextureInfo_t& info = m_Textures[h];
  424. // spin up to the best fragment size
  425. int nDesiredPower = MIN_TEXTURE_POWER;
  426. int nDesiredWidth = MIN_TEXTURE_SIZE;
  427. while ( (nDesiredWidth * nDesiredWidth) < flArea )
  428. {
  429. if ( nDesiredPower >= info.m_Power )
  430. {
  431. nDesiredPower = info.m_Power;
  432. break;
  433. }
  434. ++nDesiredPower;
  435. nDesiredWidth <<= 1;
  436. }
  437. // If we've got a valid fragment for this texture, no worries!
  438. int nCurrentPower = -1;
  439. FragmentHandle_t currentFragment = info.m_Fragment;
  440. if (currentFragment != INVALID_FRAGMENT_HANDLE)
  441. {
  442. // If the current fragment is at or near the desired power, we're done
  443. nCurrentPower = GetFragmentPower(info.m_Fragment);
  444. Assert( nCurrentPower <= info.m_Power );
  445. bool bShouldKeepTexture = (!bWillRedraw) && (nDesiredPower < 8) && (nDesiredPower - nCurrentPower <= 1);
  446. if ((nCurrentPower == nDesiredPower) || bShouldKeepTexture)
  447. {
  448. // Move to the back of the LRU
  449. MarkUsed( currentFragment );
  450. return false;
  451. }
  452. }
  453. // Warning( "\n\nUseTexture B\n" );
  454. // DebugPrintCache();
  455. // Grab the LRU fragment from the appropriate cache
  456. // If that fragment is connected to a texture, disconnect it.
  457. int power = nDesiredPower;
  458. FragmentHandle_t f = INVALID_FRAGMENT_HANDLE;
  459. bool done = false;
  460. while (!done && power >= 0)
  461. {
  462. f = m_Fragments.Head( m_Cache[power].m_List );
  463. // This represents an overflow condition (used too many textures of
  464. // the same size in a single frame). It that happens, just use a texture
  465. // of lower res.
  466. if ( (f != m_Fragments.InvalidIndex()) && (m_Fragments[f].m_FrameUsed != m_CurrentFrame) )
  467. {
  468. done = true;
  469. }
  470. else
  471. {
  472. --power;
  473. }
  474. }
  475. // Warning( "\n\nUseTexture C\n" );
  476. // DebugPrintCache();
  477. // Ok, lets see if we're better off than we were...
  478. if (currentFragment != INVALID_FRAGMENT_HANDLE)
  479. {
  480. if (power <= nCurrentPower)
  481. {
  482. // Oops... we're not. Let's leave well enough alone
  483. // Move to the back of the LRU
  484. MarkUsed( currentFragment );
  485. return false;
  486. }
  487. else
  488. {
  489. // Clear out the old fragment
  490. DisconnectTextureFromFragment(currentFragment);
  491. }
  492. }
  493. if ( f == INVALID_FRAGMENT_HANDLE )
  494. {
  495. return false;
  496. }
  497. // Disconnect existing texture from this fragment (if necessary)
  498. DisconnectTextureFromFragment(f);
  499. // Connnect new texture to this fragment
  500. info.m_Fragment = f;
  501. m_Fragments[f].m_Texture = h;
  502. // Move to the back of the LRU
  503. MarkUsed( f );
  504. // Indicate we need a redraw
  505. return true;
  506. }
  507. //-----------------------------------------------------------------------------
  508. // Returns the size of a particular fragment
  509. //-----------------------------------------------------------------------------
  510. int CTextureAllocator::GetFragmentPower( FragmentHandle_t f ) const
  511. {
  512. return m_Blocks[m_Fragments[f].m_Block].m_FragmentPower;
  513. }
  514. //-----------------------------------------------------------------------------
  515. // Advance frame...
  516. //-----------------------------------------------------------------------------
  517. void CTextureAllocator::AdvanceFrame()
  518. {
  519. // Be sure that this is called as infrequently as possible (i.e. once per frame,
  520. // NOT once per view) to prevent cache thrash when rendering multiple views in a single frame
  521. m_CurrentFrame++;
  522. }
  523. //-----------------------------------------------------------------------------
  524. // Prepare to render into texture...
  525. //-----------------------------------------------------------------------------
  526. ITexture* CTextureAllocator::GetTexture()
  527. {
  528. return m_TexturePage;
  529. }
  530. //-----------------------------------------------------------------------------
  531. // Get at the total texture size.
  532. //-----------------------------------------------------------------------------
  533. void CTextureAllocator::GetTotalTextureSize( int& w, int& h )
  534. {
  535. w = h = TEXTURE_PAGE_SIZE;
  536. }
  537. //-----------------------------------------------------------------------------
  538. // Returns the rectangle the texture lives in..
  539. //-----------------------------------------------------------------------------
  540. void CTextureAllocator::GetTextureRect(TextureHandle_t handle, int& x, int& y, int& w, int& h )
  541. {
  542. TextureInfo_t& info = m_Textures[handle];
  543. Assert( info.m_Fragment != INVALID_FRAGMENT_HANDLE );
  544. // Compute the position of the fragment in the page
  545. FragmentInfo_t& fragment = m_Fragments[info.m_Fragment];
  546. int blockY = fragment.m_Block / BLOCKS_PER_ROW;
  547. int blockX = fragment.m_Block - blockY * BLOCKS_PER_ROW;
  548. int fragmentSize = (1 << m_Blocks[fragment.m_Block].m_FragmentPower);
  549. int fragmentsPerRow = BLOCK_SIZE / fragmentSize;
  550. int fragmentY = fragment.m_Index / fragmentsPerRow;
  551. int fragmentX = fragment.m_Index - fragmentY * fragmentsPerRow;
  552. x = blockX * BLOCK_SIZE + fragmentX * fragmentSize;
  553. y = blockY * BLOCK_SIZE + fragmentY * fragmentSize;
  554. w = fragmentSize;
  555. h = fragmentSize;
  556. }
  557. //-----------------------------------------------------------------------------
  558. // Defines how big of a shadow texture we should be making per caster...
  559. //-----------------------------------------------------------------------------
  560. #define TEXEL_SIZE_PER_CASTER_SIZE 2.0f
  561. #define MAX_FALLOFF_AMOUNT 240
  562. #define MAX_CLIP_PLANE_COUNT 4
  563. #define SHADOW_CULL_TOLERANCE 0.5f
  564. static ConVar r_shadows( "r_shadows", "1" ); // hook into engine's cvars..
  565. static ConVar r_shadowmaxrendered("r_shadowmaxrendered", "32");
  566. static ConVar r_shadows_gamecontrol( "r_shadows_gamecontrol", "-1", FCVAR_CHEAT ); // hook into engine's cvars..
  567. //-----------------------------------------------------------------------------
  568. // The class responsible for dealing with shadows on the client side
  569. // Oh, and let's take a moment and notice how happy Robin and John must be
  570. // owing to the lack of space between this lovely comment and the class name =)
  571. //-----------------------------------------------------------------------------
  572. class CClientShadowMgr : public IClientShadowMgr
  573. {
  574. public:
  575. CClientShadowMgr();
  576. virtual char const *Name() { return "CCLientShadowMgr"; }
  577. // Inherited from IClientShadowMgr
  578. virtual bool Init();
  579. virtual void PostInit() {}
  580. virtual void Shutdown();
  581. virtual void LevelInitPreEntity();
  582. virtual void LevelInitPostEntity() {}
  583. virtual void LevelShutdownPreEntity() {}
  584. virtual void LevelShutdownPostEntity();
  585. virtual bool IsPerFrame() { return true; }
  586. virtual void PreRender();
  587. virtual void Update( float frametime ) { }
  588. virtual void PostRender() {}
  589. virtual void OnSave() {}
  590. virtual void OnRestore() {}
  591. virtual void SafeRemoveIfDesired() {}
  592. virtual ClientShadowHandle_t CreateShadow( ClientEntityHandle_t entity, int flags );
  593. virtual void DestroyShadow( ClientShadowHandle_t handle );
  594. // Create flashlight (projected texture light source)
  595. virtual ClientShadowHandle_t CreateFlashlight( const FlashlightState_t &lightState );
  596. virtual void UpdateFlashlightState( ClientShadowHandle_t shadowHandle, const FlashlightState_t &lightState );
  597. virtual void DestroyFlashlight( ClientShadowHandle_t shadowHandle );
  598. // Update a shadow
  599. virtual void UpdateProjectedTexture( ClientShadowHandle_t handle, bool force );
  600. void ComputeBoundingSphere( IClientRenderable* pRenderable, Vector& origin, float& radius );
  601. virtual void AddToDirtyShadowList( ClientShadowHandle_t handle, bool bForce );
  602. virtual void AddToDirtyShadowList( IClientRenderable *pRenderable, bool force );
  603. // Marks the render-to-texture shadow as needing to be re-rendered
  604. virtual void MarkRenderToTextureShadowDirty( ClientShadowHandle_t handle );
  605. // deals with shadows being added to shadow receivers
  606. void AddShadowToReceiver( ClientShadowHandle_t handle,
  607. IClientRenderable* pRenderable, ShadowReceiver_t type );
  608. // deals with shadows being added to shadow receivers
  609. void RemoveAllShadowsFromReceiver( IClientRenderable* pRenderable, ShadowReceiver_t type );
  610. // Re-renders all shadow textures for shadow casters that lie in the leaf list
  611. void ComputeShadowTextures( const CViewSetup &view, int leafCount, LeafIndex_t* pLeafList );
  612. // Kicks off rendering into shadow depth maps (if any)
  613. void ComputeShadowDepthTextures( const CViewSetup &view );
  614. // Frees shadow depth textures for use in subsequent view/frame
  615. void FreeShadowDepthTextures();
  616. // Returns the shadow texture
  617. ITexture* GetShadowTexture( unsigned short h );
  618. // Returns shadow information
  619. const ShadowInfo_t& GetShadowInfo( ClientShadowHandle_t h );
  620. // Renders the shadow texture to screen...
  621. void RenderShadowTexture( int w, int h );
  622. // Sets the shadow direction
  623. virtual void SetShadowDirection( const Vector& dir );
  624. const Vector &GetShadowDirection() const;
  625. // Sets the shadow color
  626. virtual void SetShadowColor( unsigned char r, unsigned char g, unsigned char b );
  627. void GetShadowColor( unsigned char *r, unsigned char *g, unsigned char *b ) const;
  628. // Sets the shadow distance
  629. virtual void SetShadowDistance( float flMaxDistance );
  630. float GetShadowDistance( ) const;
  631. // Sets the screen area at which blobby shadows are always used
  632. virtual void SetShadowBlobbyCutoffArea( float flMinArea );
  633. float GetBlobbyCutoffArea( ) const;
  634. // Set the darkness falloff bias
  635. virtual void SetFalloffBias( ClientShadowHandle_t handle, unsigned char ucBias );
  636. void RestoreRenderState();
  637. // Computes a rough bounding box encompassing the volume of the shadow
  638. void ComputeShadowBBox( IClientRenderable *pRenderable, const Vector &vecAbsCenter, float flRadius, Vector *pAbsMins, Vector *pAbsMaxs );
  639. bool WillParentRenderBlobbyShadow( IClientRenderable *pRenderable );
  640. // Are we the child of a shadow with render-to-texture?
  641. bool ShouldUseParentShadow( IClientRenderable *pRenderable );
  642. void SetShadowsDisabled( bool bDisabled )
  643. {
  644. r_shadows_gamecontrol.SetValue( bDisabled != 1 );
  645. }
  646. private:
  647. enum
  648. {
  649. SHADOW_FLAGS_TEXTURE_DIRTY = (CLIENT_SHADOW_FLAGS_LAST_FLAG << 1),
  650. SHADOW_FLAGS_BRUSH_MODEL = (CLIENT_SHADOW_FLAGS_LAST_FLAG << 2),
  651. SHADOW_FLAGS_USING_LOD_SHADOW = (CLIENT_SHADOW_FLAGS_LAST_FLAG << 3),
  652. SHADOW_FLAGS_LIGHT_WORLD = (CLIENT_SHADOW_FLAGS_LAST_FLAG << 4),
  653. };
  654. struct ClientShadow_t
  655. {
  656. ClientEntityHandle_t m_Entity;
  657. ShadowHandle_t m_ShadowHandle;
  658. ClientLeafShadowHandle_t m_ClientLeafShadowHandle;
  659. unsigned short m_Flags;
  660. VMatrix m_WorldToShadow;
  661. Vector2D m_WorldSize;
  662. Vector m_LastOrigin;
  663. QAngle m_LastAngles;
  664. TextureHandle_t m_ShadowTexture;
  665. CTextureReference m_ShadowDepthTexture;
  666. int m_nRenderFrame;
  667. EHANDLE m_hTargetEntity;
  668. };
  669. private:
  670. // Shadow update functions
  671. void UpdateStudioShadow( IClientRenderable *pRenderable, ClientShadowHandle_t handle );
  672. void UpdateBrushShadow( IClientRenderable *pRenderable, ClientShadowHandle_t handle );
  673. void UpdateShadow( ClientShadowHandle_t handle, bool force );
  674. // Gets the entity whose shadow this shadow will render into
  675. IClientRenderable *GetParentShadowEntity( ClientShadowHandle_t handle );
  676. // Adds the child bounds to the bounding box
  677. void AddChildBounds( matrix3x4_t &matWorldToBBox, IClientRenderable* pParent, Vector &vecMins, Vector &vecMaxs );
  678. // Compute a bounds for the entity + children
  679. void ComputeHierarchicalBounds( IClientRenderable *pRenderable, Vector &vecMins, Vector &vecMaxs );
  680. // Builds matrices transforming from world space to shadow space
  681. void BuildGeneralWorldToShadowMatrix( VMatrix& matWorldToShadow,
  682. const Vector& origin, const Vector& dir, const Vector& xvec, const Vector& yvec );
  683. void BuildWorldToShadowMatrix( VMatrix& matWorldToShadow, const Vector& origin, const Quaternion& quatOrientation );
  684. void BuildPerspectiveWorldToFlashlightMatrix( VMatrix& matWorldToShadow, const FlashlightState_t &flashlightState );
  685. // Update a shadow
  686. void UpdateProjectedTextureInternal( ClientShadowHandle_t handle, bool force );
  687. // Compute the shadow origin and attenuation start distance
  688. float ComputeLocalShadowOrigin( IClientRenderable* pRenderable,
  689. const Vector& mins, const Vector& maxs, const Vector& localShadowDir, float backupFactor, Vector& origin );
  690. // Remove a shadow from the dirty list
  691. void RemoveShadowFromDirtyList( ClientShadowHandle_t handle );
  692. // NOTE: this will ONLY return SHADOWS_NONE, SHADOWS_SIMPLE, or SHADOW_RENDER_TO_TEXTURE.
  693. ShadowType_t GetActualShadowCastType( ClientShadowHandle_t handle ) const;
  694. ShadowType_t GetActualShadowCastType( IClientRenderable *pRenderable ) const;
  695. // Builds a simple blobby shadow
  696. void BuildOrthoShadow( IClientRenderable* pRenderable, ClientShadowHandle_t handle, const Vector& mins, const Vector& maxs);
  697. // Builds a more complex shadow...
  698. void BuildRenderToTextureShadow( IClientRenderable* pRenderable,
  699. ClientShadowHandle_t handle, const Vector& mins, const Vector& maxs );
  700. // Build a projected-texture flashlight
  701. void BuildFlashlight( ClientShadowHandle_t handle );
  702. // Does all the lovely stuff we need to do to have render-to-texture shadows
  703. void SetupRenderToTextureShadow( ClientShadowHandle_t h );
  704. void CleanUpRenderToTextureShadow( ClientShadowHandle_t h );
  705. // Compute the extra shadow planes
  706. void ComputeExtraClipPlanes( IClientRenderable* pRenderable,
  707. ClientShadowHandle_t handle, const Vector* vec,
  708. const Vector& mins, const Vector& maxs, const Vector& localShadowDir );
  709. // Set extra clip planes related to shadows...
  710. void ClearExtraClipPlanes( ClientShadowHandle_t h );
  711. void AddExtraClipPlane( ClientShadowHandle_t h, const Vector& normal, float dist );
  712. // Cull if the origin is on the wrong side of a shadow clip plane....
  713. bool CullReceiver( ClientShadowHandle_t handle, IClientRenderable* pRenderable, IClientRenderable* pSourceRenderable );
  714. bool ComputeSeparatingPlane( IClientRenderable* pRend1, IClientRenderable* pRend2, cplane_t* pPlane );
  715. // Causes all shadows to be re-updated
  716. void UpdateAllShadows();
  717. // One of these gets called with every shadow that potentially will need to re-render
  718. bool DrawRenderToTextureShadow( unsigned short clientShadowHandle, float flArea );
  719. void DrawRenderToTextureShadowLOD( unsigned short clientShadowHandle );
  720. // Draws all children shadows into our own
  721. bool DrawShadowHierarchy( IClientRenderable *pRenderable, const ClientShadow_t &shadow, bool bChild = false );
  722. // Setup stage for threading
  723. bool BuildSetupListForRenderToTextureShadow( unsigned short clientShadowHandle, float flArea );
  724. bool BuildSetupShadowHierarchy( IClientRenderable *pRenderable, const ClientShadow_t &shadow, bool bChild = false );
  725. // Computes + sets the render-to-texture texcoords
  726. void SetRenderToTextureShadowTexCoords( ShadowHandle_t handle, int x, int y, int w, int h );
  727. // Visualization....
  728. void DrawRenderToTextureDebugInfo( IClientRenderable* pRenderable, const Vector& mins, const Vector& maxs );
  729. // Advance frame
  730. void AdvanceFrame();
  731. // Returns renderable-specific shadow info
  732. float GetShadowDistance( IClientRenderable *pRenderable ) const;
  733. const Vector &GetShadowDirection( IClientRenderable *pRenderable ) const;
  734. // Initialize, shutdown render-to-texture shadows
  735. void InitDepthTextureShadows();
  736. void ShutdownDepthTextureShadows();
  737. // Initialize, shutdown render-to-texture shadows
  738. void InitRenderToTextureShadows();
  739. void ShutdownRenderToTextureShadows();
  740. static bool ShadowHandleCompareFunc( const ClientShadowHandle_t& lhs, const ClientShadowHandle_t& rhs )
  741. {
  742. return lhs < rhs;
  743. }
  744. ClientShadowHandle_t CreateProjectedTexture( ClientEntityHandle_t entity, int flags );
  745. // Lock down the usage of a shadow depth texture...must be unlocked use on subsequent views / frames
  746. bool LockShadowDepthTexture( CTextureReference *shadowDepthTexture );
  747. void UnlockAllShadowDepthTextures();
  748. // Set and clear flashlight target renderable
  749. void SetFlashlightTarget( ClientShadowHandle_t shadowHandle, EHANDLE targetEntity );
  750. // Set flashlight light world flag
  751. void SetFlashlightLightWorld( ClientShadowHandle_t shadowHandle, bool bLightWorld );
  752. bool IsFlashlightTarget( ClientShadowHandle_t shadowHandle, IClientRenderable *pRenderable );
  753. // Builds a list of active shadows requiring shadow depth renders
  754. int BuildActiveShadowDepthList( const CViewSetup &viewSetup, int nMaxDepthShadows, ClientShadowHandle_t *pActiveDepthShadows );
  755. // Sets the view's active flashlight render state
  756. void SetViewFlashlightState( int nActiveFlashlightCount, ClientShadowHandle_t* pActiveFlashlights );
  757. private:
  758. Vector m_SimpleShadowDir;
  759. color32 m_AmbientLightColor;
  760. CMaterialReference m_SimpleShadow;
  761. CMaterialReference m_RenderShadow;
  762. CMaterialReference m_RenderModelShadow;
  763. CTextureReference m_DummyColorTexture;
  764. CUtlLinkedList< ClientShadow_t, ClientShadowHandle_t > m_Shadows;
  765. CTextureAllocator m_ShadowAllocator;
  766. bool m_RenderToTextureActive;
  767. bool m_bRenderTargetNeedsClear;
  768. bool m_bUpdatingDirtyShadows;
  769. bool m_bThreaded;
  770. float m_flShadowCastDist;
  771. float m_flMinShadowArea;
  772. CUtlRBTree< ClientShadowHandle_t, unsigned short > m_DirtyShadows;
  773. CUtlVector< ClientShadowHandle_t > m_TransparentShadows;
  774. // These members maintain current state of depth texturing (size and global active state)
  775. // If either changes in a frame, PreRender() will catch it and do the appropriate allocation, deallocation or reallocation
  776. bool m_bDepthTextureActive;
  777. int m_nDepthTextureResolution; // Assume square (height == width)
  778. CUtlVector< CTextureReference > m_DepthTextureCache;
  779. CUtlVector< bool > m_DepthTextureCacheLocks;
  780. int m_nMaxDepthTextureShadows;
  781. friend class CVisibleShadowList;
  782. friend class CVisibleShadowFrustumList;
  783. };
  784. //-----------------------------------------------------------------------------
  785. // Singleton
  786. //-----------------------------------------------------------------------------
  787. static CClientShadowMgr s_ClientShadowMgr;
  788. IClientShadowMgr* g_pClientShadowMgr = &s_ClientShadowMgr;
  789. //-----------------------------------------------------------------------------
  790. // Builds a list of potential shadows that lie within our PVS + view frustum
  791. //-----------------------------------------------------------------------------
  792. struct VisibleShadowInfo_t
  793. {
  794. ClientShadowHandle_t m_hShadow;
  795. float m_flArea;
  796. Vector m_vecAbsCenter;
  797. };
  798. class CVisibleShadowList : public IClientLeafShadowEnum
  799. {
  800. public:
  801. CVisibleShadowList();
  802. int FindShadows( const CViewSetup *pView, int nLeafCount, LeafIndex_t *pLeafList );
  803. int GetVisibleShadowCount() const;
  804. const VisibleShadowInfo_t &GetVisibleShadow( int i ) const;
  805. private:
  806. void EnumShadow( unsigned short clientShadowHandle );
  807. float ComputeScreenArea( const Vector &vecCenter, float r ) const;
  808. void PrioritySort();
  809. CUtlVector<VisibleShadowInfo_t> m_ShadowsInView;
  810. CUtlVector<int> m_PriorityIndex;
  811. };
  812. //-----------------------------------------------------------------------------
  813. // Singleton instances of shadow and shadow frustum lists
  814. //-----------------------------------------------------------------------------
  815. static CVisibleShadowList s_VisibleShadowList;
  816. //-----------------------------------------------------------------------------
  817. //
  818. //-----------------------------------------------------------------------------
  819. static CUtlVector<C_BaseAnimating *> s_NPCShadowBoneSetups;
  820. static CUtlVector<C_BaseAnimating *> s_NonNPCShadowBoneSetups;
  821. //-----------------------------------------------------------------------------
  822. // CVisibleShadowList - Constructor and Accessors
  823. //-----------------------------------------------------------------------------
  824. CVisibleShadowList::CVisibleShadowList() : m_ShadowsInView( 0, 64 ), m_PriorityIndex( 0, 64 )
  825. {
  826. }
  827. int CVisibleShadowList::GetVisibleShadowCount() const
  828. {
  829. return m_ShadowsInView.Count();
  830. }
  831. const VisibleShadowInfo_t &CVisibleShadowList::GetVisibleShadow( int i ) const
  832. {
  833. return m_ShadowsInView[m_PriorityIndex[i]];
  834. }
  835. //-----------------------------------------------------------------------------
  836. // CVisibleShadowList - Computes approximate screen area of the shadow
  837. //-----------------------------------------------------------------------------
  838. float CVisibleShadowList::ComputeScreenArea( const Vector &vecCenter, float r ) const
  839. {
  840. CMatRenderContextPtr pRenderContext( materials );
  841. float flScreenDiameter = pRenderContext->ComputePixelDiameterOfSphere( vecCenter, r );
  842. return flScreenDiameter * flScreenDiameter;
  843. }
  844. //-----------------------------------------------------------------------------
  845. // CVisibleShadowList - Visits every shadow in the list of leaves
  846. //-----------------------------------------------------------------------------
  847. void CVisibleShadowList::EnumShadow( unsigned short clientShadowHandle )
  848. {
  849. CClientShadowMgr::ClientShadow_t& shadow = s_ClientShadowMgr.m_Shadows[clientShadowHandle];
  850. // Don't bother if we rendered it this frame, no matter which view it was rendered for
  851. if ( shadow.m_nRenderFrame == gpGlobals->framecount )
  852. return;
  853. // We don't need to bother with it if it's not render-to-texture
  854. if ( s_ClientShadowMgr.GetActualShadowCastType( clientShadowHandle ) != SHADOWS_RENDER_TO_TEXTURE )
  855. return;
  856. // Don't bother with it if the shadow is totally transparent
  857. const ShadowInfo_t &shadowInfo = shadowmgr->GetInfo( shadow.m_ShadowHandle );
  858. if ( shadowInfo.m_FalloffBias == 255 )
  859. return;
  860. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity );
  861. Assert( pRenderable );
  862. // Don't bother with children of hierarchy; they will be drawn with their parents
  863. if ( s_ClientShadowMgr.ShouldUseParentShadow( pRenderable ) || s_ClientShadowMgr.WillParentRenderBlobbyShadow( pRenderable ) )
  864. return;
  865. // Compute a sphere surrounding the shadow
  866. // FIXME: This doesn't account for children of hierarchy... too bad!
  867. Vector vecAbsCenter;
  868. float flRadius;
  869. s_ClientShadowMgr.ComputeBoundingSphere( pRenderable, vecAbsCenter, flRadius );
  870. // Compute a box surrounding the shadow
  871. Vector vecAbsMins, vecAbsMaxs;
  872. s_ClientShadowMgr.ComputeShadowBBox( pRenderable, vecAbsCenter, flRadius, &vecAbsMins, &vecAbsMaxs );
  873. // FIXME: Add distance check here?
  874. // Make sure it's in the frustum. If it isn't it's not interesting
  875. if (engine->CullBox( vecAbsMins, vecAbsMaxs ))
  876. return;
  877. int i = m_ShadowsInView.AddToTail( );
  878. VisibleShadowInfo_t &info = m_ShadowsInView[i];
  879. info.m_hShadow = clientShadowHandle;
  880. m_ShadowsInView[i].m_flArea = ComputeScreenArea( vecAbsCenter, flRadius );
  881. // Har, har. When water is rendering (or any multipass technique),
  882. // we may well initially render from a viewpoint which doesn't include this shadow.
  883. // That doesn't mean we shouldn't check it again though. Sucks that we need to compute
  884. // the sphere + bbox multiply times though.
  885. shadow.m_nRenderFrame = gpGlobals->framecount;
  886. }
  887. //-----------------------------------------------------------------------------
  888. // CVisibleShadowList - Sort based on screen area/priority
  889. //-----------------------------------------------------------------------------
  890. void CVisibleShadowList::PrioritySort()
  891. {
  892. int nCount = m_ShadowsInView.Count();
  893. m_PriorityIndex.EnsureCapacity( nCount );
  894. m_PriorityIndex.RemoveAll();
  895. int i, j;
  896. for ( i = 0; i < nCount; ++i )
  897. {
  898. m_PriorityIndex.AddToTail(i);
  899. }
  900. for ( i = 0; i < nCount - 1; ++i )
  901. {
  902. int nLargestInd = i;
  903. float flLargestArea = m_ShadowsInView[m_PriorityIndex[i]].m_flArea;
  904. for ( j = i + 1; j < nCount; ++j )
  905. {
  906. int nIndex = m_PriorityIndex[j];
  907. if ( flLargestArea < m_ShadowsInView[nIndex].m_flArea )
  908. {
  909. nLargestInd = j;
  910. flLargestArea = m_ShadowsInView[nIndex].m_flArea;
  911. }
  912. }
  913. ::V_swap( m_PriorityIndex[i], m_PriorityIndex[nLargestInd] );
  914. }
  915. }
  916. //-----------------------------------------------------------------------------
  917. // CVisibleShadowList - Main entry point for finding shadows in the leaf list
  918. //-----------------------------------------------------------------------------
  919. int CVisibleShadowList::FindShadows( const CViewSetup *pView, int nLeafCount, LeafIndex_t *pLeafList )
  920. {
  921. VPROF_BUDGET( "CVisibleShadowList::FindShadows", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  922. m_ShadowsInView.RemoveAll();
  923. ClientLeafSystem()->EnumerateShadowsInLeaves( nLeafCount, pLeafList, this );
  924. int nCount = m_ShadowsInView.Count();
  925. if (nCount != 0)
  926. {
  927. // Sort based on screen area/priority
  928. PrioritySort();
  929. }
  930. return nCount;
  931. }
  932. //-----------------------------------------------------------------------------
  933. // Constructor
  934. //-----------------------------------------------------------------------------
  935. CClientShadowMgr::CClientShadowMgr() :
  936. m_DirtyShadows( 0, 0, ShadowHandleCompareFunc ),
  937. m_RenderToTextureActive( false ),
  938. m_bDepthTextureActive( false )
  939. {
  940. m_nDepthTextureResolution = r_flashlightdepthres.GetInt();
  941. m_bThreaded = false;
  942. }
  943. //-----------------------------------------------------------------------------
  944. // Changes the shadow direction...
  945. //-----------------------------------------------------------------------------
  946. CON_COMMAND_F( r_shadowdir, "Set shadow direction", FCVAR_CHEAT )
  947. {
  948. if ( args.ArgC() == 1 )
  949. {
  950. Vector dir = s_ClientShadowMgr.GetShadowDirection();
  951. Msg( "%.2f %.2f %.2f\n", dir.x, dir.y, dir.z );
  952. return;
  953. }
  954. if ( args.ArgC() == 4 )
  955. {
  956. Vector dir;
  957. dir.x = atof( args[1] );
  958. dir.y = atof( args[2] );
  959. dir.z = atof( args[3] );
  960. s_ClientShadowMgr.SetShadowDirection(dir);
  961. }
  962. }
  963. CON_COMMAND_F( r_shadowangles, "Set shadow angles", FCVAR_CHEAT )
  964. {
  965. if (args.ArgC() == 1)
  966. {
  967. Vector dir = s_ClientShadowMgr.GetShadowDirection();
  968. QAngle angles;
  969. VectorAngles( dir, angles );
  970. Msg( "%.2f %.2f %.2f\n", angles.x, angles.y, angles.z );
  971. return;
  972. }
  973. if (args.ArgC() == 4)
  974. {
  975. Vector dir;
  976. QAngle angles;
  977. angles.x = atof( args[1] );
  978. angles.y = atof( args[2] );
  979. angles.z = atof( args[3] );
  980. AngleVectors( angles, &dir );
  981. s_ClientShadowMgr.SetShadowDirection(dir);
  982. }
  983. }
  984. CON_COMMAND_F( r_shadowcolor, "Set shadow color", FCVAR_CHEAT )
  985. {
  986. if (args.ArgC() == 1)
  987. {
  988. unsigned char r, g, b;
  989. s_ClientShadowMgr.GetShadowColor( &r, &g, &b );
  990. Msg( "Shadow color %d %d %d\n", r, g, b );
  991. return;
  992. }
  993. if (args.ArgC() == 4)
  994. {
  995. int r = atoi( args[1] );
  996. int g = atoi( args[2] );
  997. int b = atoi( args[3] );
  998. s_ClientShadowMgr.SetShadowColor(r, g, b);
  999. }
  1000. }
  1001. CON_COMMAND_F( r_shadowdist, "Set shadow distance", FCVAR_CHEAT )
  1002. {
  1003. if (args.ArgC() == 1)
  1004. {
  1005. float flDist = s_ClientShadowMgr.GetShadowDistance( );
  1006. Msg( "Shadow distance %.2f\n", flDist );
  1007. return;
  1008. }
  1009. if (args.ArgC() == 2)
  1010. {
  1011. float flDistance = atof( args[1] );
  1012. s_ClientShadowMgr.SetShadowDistance( flDistance );
  1013. }
  1014. }
  1015. CON_COMMAND_F( r_shadowblobbycutoff, "some shadow stuff", FCVAR_CHEAT )
  1016. {
  1017. if (args.ArgC() == 1)
  1018. {
  1019. float flArea = s_ClientShadowMgr.GetBlobbyCutoffArea( );
  1020. Msg( "Cutoff area %.2f\n", flArea );
  1021. return;
  1022. }
  1023. if (args.ArgC() == 2)
  1024. {
  1025. float flArea = atof( args[1] );
  1026. s_ClientShadowMgr.SetShadowBlobbyCutoffArea( flArea );
  1027. }
  1028. }
  1029. static void ShadowRestoreFunc( int nChangeFlags )
  1030. {
  1031. s_ClientShadowMgr.RestoreRenderState();
  1032. }
  1033. //-----------------------------------------------------------------------------
  1034. // Initialization, shutdown
  1035. //-----------------------------------------------------------------------------
  1036. bool CClientShadowMgr::Init()
  1037. {
  1038. m_bRenderTargetNeedsClear = false;
  1039. m_SimpleShadow.Init( "decals/simpleshadow", TEXTURE_GROUP_DECAL );
  1040. Vector dir( 0.1, 0.1, -1 );
  1041. SetShadowDirection(dir);
  1042. SetShadowDistance( 50 );
  1043. SetShadowBlobbyCutoffArea( 0.005 );
  1044. bool bTools = CommandLine()->CheckParm( "-tools" ) != NULL;
  1045. m_nMaxDepthTextureShadows = bTools ? 4 : 1; // Just one shadow depth texture in games, more in tools
  1046. bool bLowEnd = ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 );
  1047. if ( !bLowEnd && r_shadowrendertotexture.GetBool() )
  1048. {
  1049. InitRenderToTextureShadows();
  1050. }
  1051. // If someone turned shadow depth mapping on but we can't do it, force it off
  1052. if ( r_flashlightdepthtexture.GetBool() && !materials->SupportsShadowDepthTextures() )
  1053. {
  1054. r_flashlightdepthtexture.SetValue( 0 );
  1055. ShutdownDepthTextureShadows();
  1056. }
  1057. if ( !bLowEnd && r_flashlightdepthtexture.GetBool() )
  1058. {
  1059. InitDepthTextureShadows();
  1060. }
  1061. materials->AddRestoreFunc( ShadowRestoreFunc );
  1062. return true;
  1063. }
  1064. void CClientShadowMgr::Shutdown()
  1065. {
  1066. m_SimpleShadow.Shutdown();
  1067. m_Shadows.RemoveAll();
  1068. ShutdownRenderToTextureShadows();
  1069. ShutdownDepthTextureShadows();
  1070. materials->RemoveRestoreFunc( ShadowRestoreFunc );
  1071. }
  1072. //-----------------------------------------------------------------------------
  1073. // Initialize, shutdown depth-texture shadows
  1074. //-----------------------------------------------------------------------------
  1075. void CClientShadowMgr::InitDepthTextureShadows()
  1076. {
  1077. VPROF_BUDGET( "CClientShadowMgr::InitDepthTextureShadows", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  1078. if( !m_bDepthTextureActive )
  1079. {
  1080. m_bDepthTextureActive = true;
  1081. ImageFormat dstFormat = materials->GetShadowDepthTextureFormat(); // Vendor-dependent depth texture format
  1082. #if !defined( _X360 )
  1083. ImageFormat nullFormat = materials->GetNullTextureFormat(); // Vendor-dependent null texture format (takes as little memory as possible)
  1084. #endif
  1085. materials->BeginRenderTargetAllocation();
  1086. #if defined( _X360 )
  1087. // For the 360, we'll be rendering depth directly into the dummy depth and Resolve()ing to the depth texture.
  1088. // only need the dummy surface, don't care about color results
  1089. m_DummyColorTexture.InitRenderTargetTexture( r_flashlightdepthres.GetInt(), r_flashlightdepthres.GetInt(), RT_SIZE_OFFSCREEN, IMAGE_FORMAT_BGR565, MATERIAL_RT_DEPTH_SHARED, false, "_rt_ShadowDummy" );
  1090. m_DummyColorTexture.InitRenderTargetSurface( r_flashlightdepthres.GetInt(), r_flashlightdepthres.GetInt(), IMAGE_FORMAT_BGR565, true );
  1091. #else
  1092. m_DummyColorTexture.InitRenderTarget( r_flashlightdepthres.GetInt(), r_flashlightdepthres.GetInt(), RT_SIZE_OFFSCREEN, nullFormat, MATERIAL_RT_DEPTH_NONE, false, "_rt_ShadowDummy" );
  1093. #endif
  1094. // Create some number of depth-stencil textures
  1095. m_DepthTextureCache.Purge();
  1096. m_DepthTextureCacheLocks.Purge();
  1097. for( int i=0; i < m_nMaxDepthTextureShadows; i++ )
  1098. {
  1099. CTextureReference depthTex; // Depth-stencil surface
  1100. bool bFalse = false;
  1101. char strRTName[64];
  1102. Q_snprintf( strRTName, ARRAYSIZE( strRTName ), "_rt_ShadowDepthTexture_%d", i );
  1103. #if defined( _X360 )
  1104. // create a render target to use as a resolve target to get the shared depth buffer
  1105. // surface is effectively never used
  1106. depthTex.InitRenderTargetTexture( m_nDepthTextureResolution, m_nDepthTextureResolution, RT_SIZE_OFFSCREEN, dstFormat, MATERIAL_RT_DEPTH_NONE, false, strRTName );
  1107. depthTex.InitRenderTargetSurface( 1, 1, dstFormat, false );
  1108. #else
  1109. depthTex.InitRenderTarget( m_nDepthTextureResolution, m_nDepthTextureResolution, RT_SIZE_OFFSCREEN, dstFormat, MATERIAL_RT_DEPTH_NONE, false, strRTName );
  1110. #endif
  1111. if ( i == 0 )
  1112. {
  1113. // Shadow may be resized during allocation (due to resolution constraints etc)
  1114. m_nDepthTextureResolution = depthTex->GetActualWidth();
  1115. r_flashlightdepthres.SetValue( m_nDepthTextureResolution );
  1116. }
  1117. m_DepthTextureCache.AddToTail( depthTex );
  1118. m_DepthTextureCacheLocks.AddToTail( bFalse );
  1119. }
  1120. materials->EndRenderTargetAllocation();
  1121. }
  1122. }
  1123. void CClientShadowMgr::ShutdownDepthTextureShadows()
  1124. {
  1125. if( m_bDepthTextureActive )
  1126. {
  1127. // Shut down the dummy texture
  1128. m_DummyColorTexture.Shutdown();
  1129. while( m_DepthTextureCache.Count() )
  1130. {
  1131. m_DepthTextureCache[ m_DepthTextureCache.Count()-1 ].Shutdown();
  1132. m_DepthTextureCacheLocks.Remove( m_DepthTextureCache.Count()-1 );
  1133. m_DepthTextureCache.Remove( m_DepthTextureCache.Count()-1 );
  1134. }
  1135. m_bDepthTextureActive = false;
  1136. }
  1137. }
  1138. //-----------------------------------------------------------------------------
  1139. // Initialize, shutdown render-to-texture shadows
  1140. //-----------------------------------------------------------------------------
  1141. void CClientShadowMgr::InitRenderToTextureShadows()
  1142. {
  1143. if ( !m_RenderToTextureActive )
  1144. {
  1145. m_RenderToTextureActive = true;
  1146. m_RenderShadow.Init( "decals/rendershadow", TEXTURE_GROUP_DECAL );
  1147. m_RenderModelShadow.Init( "decals/rendermodelshadow", TEXTURE_GROUP_DECAL );
  1148. m_ShadowAllocator.Init();
  1149. m_ShadowAllocator.Reset();
  1150. m_bRenderTargetNeedsClear = true;
  1151. float fr = (float)m_AmbientLightColor.r / 255.0f;
  1152. float fg = (float)m_AmbientLightColor.g / 255.0f;
  1153. float fb = (float)m_AmbientLightColor.b / 255.0f;
  1154. m_RenderShadow->ColorModulate( fr, fg, fb );
  1155. m_RenderModelShadow->ColorModulate( fr, fg, fb );
  1156. // Iterate over all existing textures and allocate shadow textures
  1157. for (ClientShadowHandle_t i = m_Shadows.Head(); i != m_Shadows.InvalidIndex(); i = m_Shadows.Next(i) )
  1158. {
  1159. ClientShadow_t& shadow = m_Shadows[i];
  1160. if ( shadow.m_Flags & SHADOW_FLAGS_USE_RENDER_TO_TEXTURE )
  1161. {
  1162. SetupRenderToTextureShadow( i );
  1163. MarkRenderToTextureShadowDirty( i );
  1164. // Switch the material to use render-to-texture shadows
  1165. shadowmgr->SetShadowMaterial( shadow.m_ShadowHandle, m_RenderShadow, m_RenderModelShadow, (void*)(uintp)i );
  1166. }
  1167. }
  1168. }
  1169. }
  1170. void CClientShadowMgr::ShutdownRenderToTextureShadows()
  1171. {
  1172. if (m_RenderToTextureActive)
  1173. {
  1174. // Iterate over all existing textures and deallocate shadow textures
  1175. for (ClientShadowHandle_t i = m_Shadows.Head(); i != m_Shadows.InvalidIndex(); i = m_Shadows.Next(i) )
  1176. {
  1177. CleanUpRenderToTextureShadow( i );
  1178. // Switch the material to use blobby shadows
  1179. ClientShadow_t& shadow = m_Shadows[i];
  1180. shadowmgr->SetShadowMaterial( shadow.m_ShadowHandle, m_SimpleShadow, m_SimpleShadow, (void*)CLIENTSHADOW_INVALID_HANDLE );
  1181. shadowmgr->SetShadowTexCoord( shadow.m_ShadowHandle, 0, 0, 1, 1 );
  1182. ClearExtraClipPlanes( i );
  1183. }
  1184. m_RenderShadow.Shutdown();
  1185. m_RenderModelShadow.Shutdown();
  1186. m_ShadowAllocator.DeallocateAllTextures();
  1187. m_ShadowAllocator.Shutdown();
  1188. // Cause the render target to go away
  1189. materials->UncacheUnusedMaterials();
  1190. m_RenderToTextureActive = false;
  1191. }
  1192. }
  1193. //-----------------------------------------------------------------------------
  1194. // Sets the shadow color
  1195. //-----------------------------------------------------------------------------
  1196. void CClientShadowMgr::SetShadowColor( unsigned char r, unsigned char g, unsigned char b )
  1197. {
  1198. float fr = (float)r / 255.0f;
  1199. float fg = (float)g / 255.0f;
  1200. float fb = (float)b / 255.0f;
  1201. // Hook the shadow color into the shadow materials
  1202. m_SimpleShadow->ColorModulate( fr, fg, fb );
  1203. if (m_RenderToTextureActive)
  1204. {
  1205. m_RenderShadow->ColorModulate( fr, fg, fb );
  1206. m_RenderModelShadow->ColorModulate( fr, fg, fb );
  1207. }
  1208. m_AmbientLightColor.r = r;
  1209. m_AmbientLightColor.g = g;
  1210. m_AmbientLightColor.b = b;
  1211. }
  1212. void CClientShadowMgr::GetShadowColor( unsigned char *r, unsigned char *g, unsigned char *b ) const
  1213. {
  1214. *r = m_AmbientLightColor.r;
  1215. *g = m_AmbientLightColor.g;
  1216. *b = m_AmbientLightColor.b;
  1217. }
  1218. //-----------------------------------------------------------------------------
  1219. // Level init... get the shadow color
  1220. //-----------------------------------------------------------------------------
  1221. void CClientShadowMgr::LevelInitPreEntity()
  1222. {
  1223. m_bUpdatingDirtyShadows = false;
  1224. Vector ambientColor;
  1225. engine->GetAmbientLightColor( ambientColor );
  1226. ambientColor *= 3;
  1227. ambientColor += Vector( 0.3f, 0.3f, 0.3f );
  1228. unsigned char r = ambientColor[0] > 1.0 ? 255 : 255 * ambientColor[0];
  1229. unsigned char g = ambientColor[1] > 1.0 ? 255 : 255 * ambientColor[1];
  1230. unsigned char b = ambientColor[2] > 1.0 ? 255 : 255 * ambientColor[2];
  1231. SetShadowColor(r, g, b);
  1232. // Set up the texture allocator
  1233. if ( m_RenderToTextureActive )
  1234. {
  1235. m_ShadowAllocator.Reset();
  1236. m_bRenderTargetNeedsClear = true;
  1237. }
  1238. }
  1239. //-----------------------------------------------------------------------------
  1240. // Clean up all shadows
  1241. //-----------------------------------------------------------------------------
  1242. void CClientShadowMgr::LevelShutdownPostEntity()
  1243. {
  1244. // All shadows *should* have been cleaned up when the entities went away
  1245. // but, just in case....
  1246. Assert( m_Shadows.Count() == 0 );
  1247. ClientShadowHandle_t h = m_Shadows.Head();
  1248. while (h != CLIENTSHADOW_INVALID_HANDLE)
  1249. {
  1250. ClientShadowHandle_t next = m_Shadows.Next(h);
  1251. DestroyShadow( h );
  1252. h = next;
  1253. }
  1254. // Deallocate all textures
  1255. if (m_RenderToTextureActive)
  1256. {
  1257. m_ShadowAllocator.DeallocateAllTextures();
  1258. }
  1259. r_shadows_gamecontrol.SetValue( -1 );
  1260. }
  1261. //-----------------------------------------------------------------------------
  1262. // Deals with alt-tab
  1263. //-----------------------------------------------------------------------------
  1264. void CClientShadowMgr::RestoreRenderState()
  1265. {
  1266. // Mark all shadows dirty; they need to regenerate their state
  1267. ClientShadowHandle_t h;
  1268. for ( h = m_Shadows.Head(); h != m_Shadows.InvalidIndex(); h = m_Shadows.Next(h) )
  1269. {
  1270. m_Shadows[h].m_Flags |= SHADOW_FLAGS_TEXTURE_DIRTY;
  1271. }
  1272. SetShadowColor( m_AmbientLightColor.r, m_AmbientLightColor.g, m_AmbientLightColor.b );
  1273. m_bRenderTargetNeedsClear = true;
  1274. }
  1275. //-----------------------------------------------------------------------------
  1276. // Does all the lovely stuff we need to do to have render-to-texture shadows
  1277. //-----------------------------------------------------------------------------
  1278. void CClientShadowMgr::SetupRenderToTextureShadow( ClientShadowHandle_t h )
  1279. {
  1280. // First, compute how much texture memory we want to use.
  1281. ClientShadow_t& shadow = m_Shadows[h];
  1282. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity );
  1283. if ( !pRenderable )
  1284. return;
  1285. Vector mins, maxs;
  1286. pRenderable->GetShadowRenderBounds( mins, maxs, GetActualShadowCastType( h ) );
  1287. // Compute the maximum dimension
  1288. Vector size;
  1289. VectorSubtract( maxs, mins, size );
  1290. float maxSize = MAX( size.x, size.y );
  1291. maxSize = MAX( maxSize, size.z );
  1292. // Figure out the texture size
  1293. // For now, we're going to assume a fixed number of shadow texels
  1294. // per shadow-caster size; add in some extra space at the boundary.
  1295. int texelCount = TEXEL_SIZE_PER_CASTER_SIZE * maxSize;
  1296. // Pick the first power of 2 larger...
  1297. int textureSize = 1;
  1298. while (textureSize < texelCount)
  1299. {
  1300. textureSize <<= 1;
  1301. }
  1302. shadow.m_ShadowTexture = m_ShadowAllocator.AllocateTexture( textureSize, textureSize );
  1303. }
  1304. void CClientShadowMgr::CleanUpRenderToTextureShadow( ClientShadowHandle_t h )
  1305. {
  1306. ClientShadow_t& shadow = m_Shadows[h];
  1307. if (m_RenderToTextureActive && (shadow.m_Flags & SHADOW_FLAGS_USE_RENDER_TO_TEXTURE))
  1308. {
  1309. m_ShadowAllocator.DeallocateTexture( shadow.m_ShadowTexture );
  1310. shadow.m_ShadowTexture = INVALID_TEXTURE_HANDLE;
  1311. }
  1312. }
  1313. //-----------------------------------------------------------------------------
  1314. // Causes all shadows to be re-updated
  1315. //-----------------------------------------------------------------------------
  1316. void CClientShadowMgr::UpdateAllShadows()
  1317. {
  1318. for ( ClientShadowHandle_t i = m_Shadows.Head(); i != m_Shadows.InvalidIndex(); i = m_Shadows.Next(i) )
  1319. {
  1320. ClientShadow_t& shadow = m_Shadows[i];
  1321. // Don't bother with flashlights
  1322. if ( ( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) != 0 )
  1323. continue;
  1324. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity );
  1325. if ( !pRenderable )
  1326. continue;
  1327. Assert( pRenderable->GetShadowHandle() == i );
  1328. AddToDirtyShadowList( pRenderable, true );
  1329. }
  1330. }
  1331. //-----------------------------------------------------------------------------
  1332. // Sets the shadow direction
  1333. //-----------------------------------------------------------------------------
  1334. void CClientShadowMgr::SetShadowDirection( const Vector& dir )
  1335. {
  1336. VectorCopy( dir, m_SimpleShadowDir );
  1337. VectorNormalize( m_SimpleShadowDir );
  1338. if ( m_RenderToTextureActive )
  1339. {
  1340. UpdateAllShadows();
  1341. }
  1342. }
  1343. const Vector &CClientShadowMgr::GetShadowDirection() const
  1344. {
  1345. // This will cause blobby shadows to always project straight down
  1346. static Vector s_vecDown( 0, 0, -1 );
  1347. if ( !m_RenderToTextureActive )
  1348. return s_vecDown;
  1349. return m_SimpleShadowDir;
  1350. }
  1351. //-----------------------------------------------------------------------------
  1352. // Gets shadow information for a particular renderable
  1353. //-----------------------------------------------------------------------------
  1354. float CClientShadowMgr::GetShadowDistance( IClientRenderable *pRenderable ) const
  1355. {
  1356. float flDist = m_flShadowCastDist;
  1357. // Allow the renderable to override the default
  1358. pRenderable->GetShadowCastDistance( &flDist, GetActualShadowCastType( pRenderable ) );
  1359. return flDist;
  1360. }
  1361. const Vector &CClientShadowMgr::GetShadowDirection( IClientRenderable *pRenderable ) const
  1362. {
  1363. Vector &vecResult = AllocTempVector();
  1364. vecResult = GetShadowDirection();
  1365. // Allow the renderable to override the default
  1366. pRenderable->GetShadowCastDirection( &vecResult, GetActualShadowCastType( pRenderable ) );
  1367. return vecResult;
  1368. }
  1369. //-----------------------------------------------------------------------------
  1370. // Sets the shadow distance
  1371. //-----------------------------------------------------------------------------
  1372. void CClientShadowMgr::SetShadowDistance( float flMaxDistance )
  1373. {
  1374. m_flShadowCastDist = flMaxDistance;
  1375. UpdateAllShadows();
  1376. }
  1377. float CClientShadowMgr::GetShadowDistance( ) const
  1378. {
  1379. return m_flShadowCastDist;
  1380. }
  1381. //-----------------------------------------------------------------------------
  1382. // Sets the screen area at which blobby shadows are always used
  1383. //-----------------------------------------------------------------------------
  1384. void CClientShadowMgr::SetShadowBlobbyCutoffArea( float flMinArea )
  1385. {
  1386. m_flMinShadowArea = flMinArea;
  1387. }
  1388. float CClientShadowMgr::GetBlobbyCutoffArea( ) const
  1389. {
  1390. return m_flMinShadowArea;
  1391. }
  1392. //-----------------------------------------------------------------------------
  1393. // Purpose:
  1394. //-----------------------------------------------------------------------------
  1395. void CClientShadowMgr::SetFalloffBias( ClientShadowHandle_t handle, unsigned char ucBias )
  1396. {
  1397. shadowmgr->SetFalloffBias( m_Shadows[handle].m_ShadowHandle, ucBias );
  1398. }
  1399. //-----------------------------------------------------------------------------
  1400. // Returns the shadow texture
  1401. //-----------------------------------------------------------------------------
  1402. ITexture* CClientShadowMgr::GetShadowTexture( unsigned short h )
  1403. {
  1404. return m_ShadowAllocator.GetTexture();
  1405. }
  1406. //-----------------------------------------------------------------------------
  1407. // Returns information needed by the model proxy
  1408. //-----------------------------------------------------------------------------
  1409. const ShadowInfo_t& CClientShadowMgr::GetShadowInfo( ClientShadowHandle_t h )
  1410. {
  1411. return shadowmgr->GetInfo( m_Shadows[h].m_ShadowHandle );
  1412. }
  1413. //-----------------------------------------------------------------------------
  1414. // Renders the shadow texture to screen...
  1415. //-----------------------------------------------------------------------------
  1416. void CClientShadowMgr::RenderShadowTexture( int w, int h )
  1417. {
  1418. if (m_RenderToTextureActive)
  1419. {
  1420. CMatRenderContextPtr pRenderContext( materials );
  1421. pRenderContext->Bind( m_RenderShadow );
  1422. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  1423. CMeshBuilder meshBuilder;
  1424. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  1425. meshBuilder.Position3f( 0.0f, 0.0f, 0.0f );
  1426. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  1427. meshBuilder.Color4ub( 0, 0, 0, 0 );
  1428. meshBuilder.AdvanceVertex();
  1429. meshBuilder.Position3f( w, 0.0f, 0.0f );
  1430. meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
  1431. meshBuilder.Color4ub( 0, 0, 0, 0 );
  1432. meshBuilder.AdvanceVertex();
  1433. meshBuilder.Position3f( w, h, 0.0f );
  1434. meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
  1435. meshBuilder.Color4ub( 0, 0, 0, 0 );
  1436. meshBuilder.AdvanceVertex();
  1437. meshBuilder.Position3f( 0.0f, h, 0.0f );
  1438. meshBuilder.TexCoord2f( 0, 0.0f, 1.0f );
  1439. meshBuilder.Color4ub( 0, 0, 0, 0 );
  1440. meshBuilder.AdvanceVertex();
  1441. meshBuilder.End();
  1442. pMesh->Draw();
  1443. }
  1444. }
  1445. //-----------------------------------------------------------------------------
  1446. // Create/destroy a shadow
  1447. //-----------------------------------------------------------------------------
  1448. ClientShadowHandle_t CClientShadowMgr::CreateProjectedTexture( ClientEntityHandle_t entity, int flags )
  1449. {
  1450. // We need to know if it's a brush model for shadows
  1451. if( !( flags & SHADOW_FLAGS_FLASHLIGHT ) )
  1452. {
  1453. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( entity );
  1454. if ( !pRenderable )
  1455. return m_Shadows.InvalidIndex();
  1456. int modelType = modelinfo->GetModelType( pRenderable->GetModel() );
  1457. if (modelType == mod_brush)
  1458. {
  1459. flags |= SHADOW_FLAGS_BRUSH_MODEL;
  1460. }
  1461. }
  1462. ClientShadowHandle_t h = m_Shadows.AddToTail();
  1463. ClientShadow_t& shadow = m_Shadows[h];
  1464. shadow.m_Entity = entity;
  1465. shadow.m_ClientLeafShadowHandle = ClientLeafSystem()->AddShadow( h, flags );
  1466. shadow.m_Flags = flags;
  1467. shadow.m_nRenderFrame = -1;
  1468. shadow.m_LastOrigin.Init( FLT_MAX, FLT_MAX, FLT_MAX );
  1469. shadow.m_LastAngles.Init( FLT_MAX, FLT_MAX, FLT_MAX );
  1470. Assert( ( ( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) == 0 ) !=
  1471. ( ( shadow.m_Flags & SHADOW_FLAGS_SHADOW ) == 0 ) );
  1472. // Set up the flags....
  1473. IMaterial* pShadowMaterial = m_SimpleShadow;
  1474. IMaterial* pShadowModelMaterial = m_SimpleShadow;
  1475. void* pShadowProxyData = (void*)CLIENTSHADOW_INVALID_HANDLE;
  1476. if ( m_RenderToTextureActive && (flags & SHADOW_FLAGS_USE_RENDER_TO_TEXTURE) )
  1477. {
  1478. SetupRenderToTextureShadow(h);
  1479. pShadowMaterial = m_RenderShadow;
  1480. pShadowModelMaterial = m_RenderModelShadow;
  1481. pShadowProxyData = (void*)(uintp)h;
  1482. }
  1483. if( flags & SHADOW_FLAGS_USE_DEPTH_TEXTURE )
  1484. {
  1485. pShadowMaterial = m_RenderShadow;
  1486. pShadowModelMaterial = m_RenderModelShadow;
  1487. pShadowProxyData = (void*)(uintp)h;
  1488. }
  1489. int createShadowFlags;
  1490. if( flags & SHADOW_FLAGS_FLASHLIGHT )
  1491. {
  1492. // don't use SHADOW_CACHE_VERTS with projective lightsources since we expect that they will change every frame.
  1493. // FIXME: might want to make it cache optionally if it's an entity light that is static.
  1494. createShadowFlags = SHADOW_FLASHLIGHT;
  1495. }
  1496. else
  1497. {
  1498. createShadowFlags = SHADOW_CACHE_VERTS;
  1499. }
  1500. shadow.m_ShadowHandle = shadowmgr->CreateShadowEx( pShadowMaterial, pShadowModelMaterial, pShadowProxyData, createShadowFlags );
  1501. return h;
  1502. }
  1503. ClientShadowHandle_t CClientShadowMgr::CreateFlashlight( const FlashlightState_t &lightState )
  1504. {
  1505. // We don't really need a model entity handle for a projective light source, so use an invalid one.
  1506. static ClientEntityHandle_t invalidHandle = INVALID_CLIENTENTITY_HANDLE;
  1507. int shadowFlags = SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_LIGHT_WORLD;
  1508. if( lightState.m_bEnableShadows && r_flashlightdepthtexture.GetBool() )
  1509. {
  1510. shadowFlags |= SHADOW_FLAGS_USE_DEPTH_TEXTURE;
  1511. }
  1512. ClientShadowHandle_t shadowHandle = CreateProjectedTexture( invalidHandle, shadowFlags );
  1513. UpdateFlashlightState( shadowHandle, lightState );
  1514. UpdateProjectedTexture( shadowHandle, true );
  1515. return shadowHandle;
  1516. }
  1517. ClientShadowHandle_t CClientShadowMgr::CreateShadow( ClientEntityHandle_t entity, int flags )
  1518. {
  1519. // We don't really need a model entity handle for a projective light source, so use an invalid one.
  1520. flags &= ~SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK;
  1521. flags |= SHADOW_FLAGS_SHADOW | SHADOW_FLAGS_TEXTURE_DIRTY;
  1522. ClientShadowHandle_t shadowHandle = CreateProjectedTexture( entity, flags );
  1523. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( entity );
  1524. if ( pRenderable )
  1525. {
  1526. Assert( !pRenderable->IsShadowDirty( ) );
  1527. pRenderable->MarkShadowDirty( true );
  1528. }
  1529. // NOTE: We *have* to call the version that takes a shadow handle
  1530. // even if we have an entity because this entity hasn't set its shadow handle yet
  1531. AddToDirtyShadowList( shadowHandle, true );
  1532. return shadowHandle;
  1533. }
  1534. //-----------------------------------------------------------------------------
  1535. // Updates the flashlight direction and re-computes surfaces it should lie on
  1536. //-----------------------------------------------------------------------------
  1537. void CClientShadowMgr::UpdateFlashlightState( ClientShadowHandle_t shadowHandle, const FlashlightState_t &flashlightState )
  1538. {
  1539. VPROF_BUDGET( "CClientShadowMgr::UpdateFlashlightState", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  1540. BuildPerspectiveWorldToFlashlightMatrix( m_Shadows[shadowHandle].m_WorldToShadow, flashlightState );
  1541. shadowmgr->UpdateFlashlightState( m_Shadows[shadowHandle].m_ShadowHandle, flashlightState );
  1542. }
  1543. void CClientShadowMgr::DestroyFlashlight( ClientShadowHandle_t shadowHandle )
  1544. {
  1545. DestroyShadow( shadowHandle );
  1546. }
  1547. //-----------------------------------------------------------------------------
  1548. // Remove a shadow from the dirty list
  1549. //-----------------------------------------------------------------------------
  1550. void CClientShadowMgr::RemoveShadowFromDirtyList( ClientShadowHandle_t handle )
  1551. {
  1552. int idx = m_DirtyShadows.Find( handle );
  1553. if ( idx != m_DirtyShadows.InvalidIndex() )
  1554. {
  1555. // Clean up the shadow update bit.
  1556. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( m_Shadows[handle].m_Entity );
  1557. if ( pRenderable )
  1558. {
  1559. pRenderable->MarkShadowDirty( false );
  1560. }
  1561. m_DirtyShadows.RemoveAt( idx );
  1562. }
  1563. }
  1564. //-----------------------------------------------------------------------------
  1565. // Remove a shadow
  1566. //-----------------------------------------------------------------------------
  1567. void CClientShadowMgr::DestroyShadow( ClientShadowHandle_t handle )
  1568. {
  1569. Assert( m_Shadows.IsValidIndex(handle) );
  1570. RemoveShadowFromDirtyList( handle );
  1571. shadowmgr->DestroyShadow( m_Shadows[handle].m_ShadowHandle );
  1572. ClientLeafSystem()->RemoveShadow( m_Shadows[handle].m_ClientLeafShadowHandle );
  1573. CleanUpRenderToTextureShadow( handle );
  1574. m_Shadows.Remove(handle);
  1575. }
  1576. //-----------------------------------------------------------------------------
  1577. // Build the worldtotexture matrix
  1578. //-----------------------------------------------------------------------------
  1579. void CClientShadowMgr::BuildGeneralWorldToShadowMatrix( VMatrix& matWorldToShadow,
  1580. const Vector& origin, const Vector& dir, const Vector& xvec, const Vector& yvec )
  1581. {
  1582. // We're assuming here that xvec + yvec aren't necessary perpendicular
  1583. // The shadow->world matrix is pretty simple:
  1584. // Just stick the origin in the translation component
  1585. // and the vectors in the columns...
  1586. matWorldToShadow.SetBasisVectors( xvec, yvec, dir );
  1587. matWorldToShadow.SetTranslation( origin );
  1588. matWorldToShadow[3][0] = matWorldToShadow[3][1] = matWorldToShadow[3][2] = 0.0f;
  1589. matWorldToShadow[3][3] = 1.0f;
  1590. // Now do a general inverse to get matWorldToShadow
  1591. MatrixInverseGeneral( matWorldToShadow, matWorldToShadow );
  1592. }
  1593. void CClientShadowMgr::BuildWorldToShadowMatrix( VMatrix& matWorldToShadow, const Vector& origin, const Quaternion& quatOrientation )
  1594. {
  1595. // The shadow->world matrix is pretty simple:
  1596. // Just stick the origin in the translation component
  1597. // and the vectors in the columns...
  1598. // The inverse of this transposes the rotational component
  1599. // and the translational component = - (rotation transpose) * origin
  1600. matrix3x4_t matOrientation;
  1601. QuaternionMatrix( quatOrientation, matOrientation ); // Convert quat to matrix3x4
  1602. PositionMatrix( vec3_origin, matOrientation ); // Zero out translation elements
  1603. VMatrix matBasis( matOrientation ); // Convert matrix3x4 to VMatrix
  1604. Vector vForward, vLeft, vUp;
  1605. matBasis.GetBasisVectors( vForward, vLeft, vUp );
  1606. matBasis.SetForward( vLeft ); // Bizarre vector flip inherited from earlier code, WTF?
  1607. matBasis.SetLeft( vUp );
  1608. matBasis.SetUp( vForward );
  1609. matWorldToShadow = matBasis.Transpose(); // Transpose
  1610. Vector translation;
  1611. Vector3DMultiply( matWorldToShadow, origin, translation );
  1612. translation *= -1.0f;
  1613. matWorldToShadow.SetTranslation( translation );
  1614. // The the bottom row.
  1615. matWorldToShadow[3][0] = matWorldToShadow[3][1] = matWorldToShadow[3][2] = 0.0f;
  1616. matWorldToShadow[3][3] = 1.0f;
  1617. }
  1618. void CClientShadowMgr::BuildPerspectiveWorldToFlashlightMatrix( VMatrix& matWorldToShadow, const FlashlightState_t &flashlightState )
  1619. {
  1620. VPROF_BUDGET( "CClientShadowMgr::BuildPerspectiveWorldToFlashlightMatrix", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  1621. // Buildworld to shadow matrix, then perspective projection and concatenate
  1622. VMatrix matWorldToShadowView, matPerspective;
  1623. BuildWorldToShadowMatrix( matWorldToShadowView, flashlightState.m_vecLightOrigin,
  1624. flashlightState.m_quatOrientation );
  1625. MatrixBuildPerspective( matPerspective, flashlightState.m_fHorizontalFOVDegrees,
  1626. flashlightState.m_fVerticalFOVDegrees,
  1627. flashlightState.m_NearZ, flashlightState.m_FarZ );
  1628. MatrixMultiply( matPerspective, matWorldToShadowView, matWorldToShadow );
  1629. }
  1630. //-----------------------------------------------------------------------------
  1631. // Compute the shadow origin and attenuation start distance
  1632. //-----------------------------------------------------------------------------
  1633. float CClientShadowMgr::ComputeLocalShadowOrigin( IClientRenderable* pRenderable,
  1634. const Vector& mins, const Vector& maxs, const Vector& localShadowDir, float backupFactor, Vector& origin )
  1635. {
  1636. // Compute the centroid of the object...
  1637. Vector vecCentroid;
  1638. VectorAdd( mins, maxs, vecCentroid );
  1639. vecCentroid *= 0.5f;
  1640. Vector vecSize;
  1641. VectorSubtract( maxs, mins, vecSize );
  1642. float flRadius = vecSize.Length() * 0.5f;
  1643. // NOTE: The *origin* of the shadow cast is a point on a line passing through
  1644. // the centroid of the caster. The direction of this line is the shadow cast direction,
  1645. // and the point on that line corresponds to the endpoint of the box that is
  1646. // furthest *back* along the shadow direction
  1647. // For the first point at which the shadow could possibly start falling off,
  1648. // we need to use the point at which the ray described above leaves the
  1649. // bounding sphere surrounding the entity. This is necessary because otherwise,
  1650. // tall, thin objects would have their shadows appear + disappear as then spun about their origin
  1651. // Figure out the corner corresponding to the min + max projection
  1652. // along the shadow direction
  1653. // We're basically finding the point on the cube that has the largest and smallest
  1654. // dot product with the local shadow dir. Then we're taking the dot product
  1655. // of that with the localShadowDir. lastly, we're subtracting out the
  1656. // centroid projection to give us a distance along the localShadowDir to
  1657. // the front and back of the cube along the direction of the ray.
  1658. float centroidProjection = DotProduct( vecCentroid, localShadowDir );
  1659. float minDist = -centroidProjection;
  1660. for (int i = 0; i < 3; ++i)
  1661. {
  1662. if ( localShadowDir[i] > 0.0f )
  1663. {
  1664. minDist += localShadowDir[i] * mins[i];
  1665. }
  1666. else
  1667. {
  1668. minDist += localShadowDir[i] * maxs[i];
  1669. }
  1670. }
  1671. minDist *= backupFactor;
  1672. VectorMA( vecCentroid, minDist, localShadowDir, origin );
  1673. return flRadius - minDist;
  1674. }
  1675. //-----------------------------------------------------------------------------
  1676. // Sorts the components of a vector
  1677. //-----------------------------------------------------------------------------
  1678. static inline void SortAbsVectorComponents( const Vector& src, int* pVecIdx )
  1679. {
  1680. Vector absVec( fabs(src[0]), fabs(src[1]), fabs(src[2]) );
  1681. int maxIdx = (absVec[0] > absVec[1]) ? 0 : 1;
  1682. if (absVec[2] > absVec[maxIdx])
  1683. {
  1684. maxIdx = 2;
  1685. }
  1686. // always choose something right-handed....
  1687. switch( maxIdx )
  1688. {
  1689. case 0:
  1690. pVecIdx[0] = 1;
  1691. pVecIdx[1] = 2;
  1692. pVecIdx[2] = 0;
  1693. break;
  1694. case 1:
  1695. pVecIdx[0] = 2;
  1696. pVecIdx[1] = 0;
  1697. pVecIdx[2] = 1;
  1698. break;
  1699. case 2:
  1700. pVecIdx[0] = 0;
  1701. pVecIdx[1] = 1;
  1702. pVecIdx[2] = 2;
  1703. break;
  1704. }
  1705. }
  1706. //-----------------------------------------------------------------------------
  1707. // Build the worldtotexture matrix
  1708. //-----------------------------------------------------------------------------
  1709. static void BuildWorldToTextureMatrix( const VMatrix& matWorldToShadow,
  1710. const Vector2D& size, VMatrix& matWorldToTexture )
  1711. {
  1712. // Build a matrix that maps from shadow space to (u,v) coordinates
  1713. VMatrix shadowToUnit;
  1714. MatrixBuildScale( shadowToUnit, 1.0f / size.x, 1.0f / size.y, 1.0f );
  1715. shadowToUnit[0][3] = shadowToUnit[1][3] = 0.5f;
  1716. // Store off the world to (u,v) transformation
  1717. MatrixMultiply( shadowToUnit, matWorldToShadow, matWorldToTexture );
  1718. }
  1719. static void BuildOrthoWorldToShadowMatrix( VMatrix& worldToShadow,
  1720. const Vector& origin, const Vector& dir, const Vector& xvec, const Vector& yvec )
  1721. {
  1722. // This version is faster and assumes dir, xvec, yvec are perpendicular
  1723. AssertFloatEquals( DotProduct( dir, xvec ), 0.0f, 1e-3 );
  1724. AssertFloatEquals( DotProduct( dir, yvec ), 0.0f, 1e-3 );
  1725. AssertFloatEquals( DotProduct( xvec, yvec ), 0.0f, 1e-3 );
  1726. // The shadow->world matrix is pretty simple:
  1727. // Just stick the origin in the translation component
  1728. // and the vectors in the columns...
  1729. // The inverse of this transposes the rotational component
  1730. // and the translational component = - (rotation transpose) * origin
  1731. worldToShadow.SetBasisVectors( xvec, yvec, dir );
  1732. MatrixTranspose( worldToShadow, worldToShadow );
  1733. Vector translation;
  1734. Vector3DMultiply( worldToShadow, origin, translation );
  1735. translation *= -1.0f;
  1736. worldToShadow.SetTranslation( translation );
  1737. // The the bottom row.
  1738. worldToShadow[3][0] = worldToShadow[3][1] = worldToShadow[3][2] = 0.0f;
  1739. worldToShadow[3][3] = 1.0f;
  1740. }
  1741. //-----------------------------------------------------------------------------
  1742. // Set extra clip planes related to shadows...
  1743. //-----------------------------------------------------------------------------
  1744. void CClientShadowMgr::ClearExtraClipPlanes( ClientShadowHandle_t h )
  1745. {
  1746. shadowmgr->ClearExtraClipPlanes( m_Shadows[h].m_ShadowHandle );
  1747. }
  1748. void CClientShadowMgr::AddExtraClipPlane( ClientShadowHandle_t h, const Vector& normal, float dist )
  1749. {
  1750. shadowmgr->AddExtraClipPlane( m_Shadows[h].m_ShadowHandle, normal, dist );
  1751. }
  1752. //-----------------------------------------------------------------------------
  1753. // Compute the extra shadow planes
  1754. //-----------------------------------------------------------------------------
  1755. void CClientShadowMgr::ComputeExtraClipPlanes( IClientRenderable* pRenderable,
  1756. ClientShadowHandle_t handle, const Vector* vec,
  1757. const Vector& mins, const Vector& maxs, const Vector& localShadowDir )
  1758. {
  1759. // Compute the world-space position of the corner of the bounding box
  1760. // that's got the highest dotproduct with the local shadow dir...
  1761. Vector origin = pRenderable->GetRenderOrigin( );
  1762. float dir[3];
  1763. int i;
  1764. for ( i = 0; i < 3; ++i )
  1765. {
  1766. if (localShadowDir[i] < 0.0f)
  1767. {
  1768. VectorMA( origin, maxs[i], vec[i], origin );
  1769. dir[i] = 1;
  1770. }
  1771. else
  1772. {
  1773. VectorMA( origin, mins[i], vec[i], origin );
  1774. dir[i] = -1;
  1775. }
  1776. }
  1777. // Now that we have it, create 3 planes...
  1778. Vector normal;
  1779. ClearExtraClipPlanes(handle);
  1780. for ( i = 0; i < 3; ++i )
  1781. {
  1782. VectorMultiply( vec[i], dir[i], normal );
  1783. float dist = DotProduct( normal, origin );
  1784. AddExtraClipPlane( handle, normal, dist );
  1785. }
  1786. ClientShadow_t& shadow = m_Shadows[handle];
  1787. C_BaseEntity *pEntity = ClientEntityList().GetBaseEntityFromHandle( shadow.m_Entity );
  1788. if ( pEntity && pEntity->m_bEnableRenderingClipPlane )
  1789. {
  1790. normal[ 0 ] = -pEntity->m_fRenderingClipPlane[ 0 ];
  1791. normal[ 1 ] = -pEntity->m_fRenderingClipPlane[ 1 ];
  1792. normal[ 2 ] = -pEntity->m_fRenderingClipPlane[ 2 ];
  1793. AddExtraClipPlane( handle, normal, -pEntity->m_fRenderingClipPlane[ 3 ] - 0.5f );
  1794. }
  1795. }
  1796. inline ShadowType_t CClientShadowMgr::GetActualShadowCastType( ClientShadowHandle_t handle ) const
  1797. {
  1798. if ( handle == CLIENTSHADOW_INVALID_HANDLE )
  1799. {
  1800. return SHADOWS_NONE;
  1801. }
  1802. if ( m_Shadows[handle].m_Flags & SHADOW_FLAGS_USE_RENDER_TO_TEXTURE )
  1803. {
  1804. return ( m_RenderToTextureActive ? SHADOWS_RENDER_TO_TEXTURE : SHADOWS_SIMPLE );
  1805. }
  1806. else if( m_Shadows[handle].m_Flags & SHADOW_FLAGS_USE_DEPTH_TEXTURE )
  1807. {
  1808. return SHADOWS_RENDER_TO_DEPTH_TEXTURE;
  1809. }
  1810. else
  1811. {
  1812. return SHADOWS_SIMPLE;
  1813. }
  1814. }
  1815. inline ShadowType_t CClientShadowMgr::GetActualShadowCastType( IClientRenderable *pEnt ) const
  1816. {
  1817. return GetActualShadowCastType( pEnt->GetShadowHandle() );
  1818. }
  1819. //-----------------------------------------------------------------------------
  1820. // Adds a shadow to all leaves along a ray
  1821. //-----------------------------------------------------------------------------
  1822. class CShadowLeafEnum : public ISpatialLeafEnumerator
  1823. {
  1824. public:
  1825. bool EnumerateLeaf( int leaf, int context )
  1826. {
  1827. m_LeafList.AddToTail( leaf );
  1828. return true;
  1829. }
  1830. CUtlVectorFixedGrowable< int, 512 > m_LeafList;
  1831. };
  1832. //-----------------------------------------------------------------------------
  1833. // Builds a list of leaves inside the shadow volume
  1834. //-----------------------------------------------------------------------------
  1835. static void BuildShadowLeafList( CShadowLeafEnum *pEnum, const Vector& origin,
  1836. const Vector& dir, const Vector2D& size, float maxDist )
  1837. {
  1838. Ray_t ray;
  1839. VectorCopy( origin, ray.m_Start );
  1840. VectorMultiply( dir, maxDist, ray.m_Delta );
  1841. ray.m_StartOffset.Init( 0, 0, 0 );
  1842. float flRadius = sqrt( size.x * size.x + size.y * size.y ) * 0.5f;
  1843. ray.m_Extents.Init( flRadius, flRadius, flRadius );
  1844. ray.m_IsRay = false;
  1845. ray.m_IsSwept = true;
  1846. ISpatialQuery* pQuery = engine->GetBSPTreeQuery();
  1847. pQuery->EnumerateLeavesAlongRay( ray, pEnum, 0 );
  1848. }
  1849. //-----------------------------------------------------------------------------
  1850. // Builds a simple blobby shadow
  1851. //-----------------------------------------------------------------------------
  1852. void CClientShadowMgr::BuildOrthoShadow( IClientRenderable* pRenderable,
  1853. ClientShadowHandle_t handle, const Vector& mins, const Vector& maxs)
  1854. {
  1855. // Get the object's basis
  1856. Vector vec[3];
  1857. AngleVectors( pRenderable->GetRenderAngles(), &vec[0], &vec[1], &vec[2] );
  1858. vec[1] *= -1.0f;
  1859. Vector vecShadowDir = GetShadowDirection( pRenderable );
  1860. // Project the shadow casting direction into the space of the object
  1861. Vector localShadowDir;
  1862. localShadowDir[0] = DotProduct( vec[0], vecShadowDir );
  1863. localShadowDir[1] = DotProduct( vec[1], vecShadowDir );
  1864. localShadowDir[2] = DotProduct( vec[2], vecShadowDir );
  1865. // Figure out which vector has the largest component perpendicular
  1866. // to the shadow handle...
  1867. // Sort by how perpendicular it is
  1868. int vecIdx[3];
  1869. SortAbsVectorComponents( localShadowDir, vecIdx );
  1870. // Here's our shadow basis vectors; namely the ones that are
  1871. // most perpendicular to the shadow casting direction
  1872. Vector xvec = vec[vecIdx[0]];
  1873. Vector yvec = vec[vecIdx[1]];
  1874. // Project them into a plane perpendicular to the shadow direction
  1875. xvec -= vecShadowDir * DotProduct( vecShadowDir, xvec );
  1876. yvec -= vecShadowDir * DotProduct( vecShadowDir, yvec );
  1877. VectorNormalize( xvec );
  1878. VectorNormalize( yvec );
  1879. // Compute the box size
  1880. Vector boxSize;
  1881. VectorSubtract( maxs, mins, boxSize );
  1882. // We project the two longest sides into the vectors perpendicular
  1883. // to the projection direction, then add in the projection of the perp direction
  1884. Vector2D size( boxSize[vecIdx[0]], boxSize[vecIdx[1]] );
  1885. size.x *= fabs( DotProduct( vec[vecIdx[0]], xvec ) );
  1886. size.y *= fabs( DotProduct( vec[vecIdx[1]], yvec ) );
  1887. // Add the third component into x and y
  1888. size.x += boxSize[vecIdx[2]] * fabs( DotProduct( vec[vecIdx[2]], xvec ) );
  1889. size.y += boxSize[vecIdx[2]] * fabs( DotProduct( vec[vecIdx[2]], yvec ) );
  1890. // Bloat a bit, since the shadow wants to extend outside the model a bit
  1891. size.x += 10.0f;
  1892. size.y += 10.0f;
  1893. // Clamp the minimum size
  1894. Vector2DMax( size, Vector2D(10.0f, 10.0f), size );
  1895. // Place the origin at the point with min dot product with shadow dir
  1896. Vector org;
  1897. float falloffStart = ComputeLocalShadowOrigin( pRenderable, mins, maxs, localShadowDir, 2.0f, org );
  1898. // Transform the local origin into world coordinates
  1899. Vector worldOrigin = pRenderable->GetRenderOrigin( );
  1900. VectorMA( worldOrigin, org.x, vec[0], worldOrigin );
  1901. VectorMA( worldOrigin, org.y, vec[1], worldOrigin );
  1902. VectorMA( worldOrigin, org.z, vec[2], worldOrigin );
  1903. // FUNKY: A trick to reduce annoying texelization artifacts!?
  1904. float dx = 1.0f / TEXEL_SIZE_PER_CASTER_SIZE;
  1905. worldOrigin.x = (int)(worldOrigin.x / dx) * dx;
  1906. worldOrigin.y = (int)(worldOrigin.y / dx) * dx;
  1907. worldOrigin.z = (int)(worldOrigin.z / dx) * dx;
  1908. // NOTE: We gotta use the general matrix because xvec and yvec aren't perp
  1909. VMatrix matWorldToShadow, matWorldToTexture;
  1910. BuildGeneralWorldToShadowMatrix( m_Shadows[handle].m_WorldToShadow, worldOrigin, vecShadowDir, xvec, yvec );
  1911. BuildWorldToTextureMatrix( m_Shadows[handle].m_WorldToShadow, size, matWorldToTexture );
  1912. Vector2DCopy( size, m_Shadows[handle].m_WorldSize );
  1913. // Compute the falloff attenuation
  1914. // Area computation isn't exact since xvec is not perp to yvec, but close enough
  1915. // float shadowArea = size.x * size.y;
  1916. // The entity may be overriding our shadow cast distance
  1917. float flShadowCastDistance = GetShadowDistance( pRenderable );
  1918. float maxHeight = flShadowCastDistance + falloffStart; //3.0f * sqrt( shadowArea );
  1919. CShadowLeafEnum leafList;
  1920. BuildShadowLeafList( &leafList, worldOrigin, vecShadowDir, size, maxHeight );
  1921. int nCount = leafList.m_LeafList.Count();
  1922. const int *pLeafList = leafList.m_LeafList.Base();
  1923. shadowmgr->ProjectShadow( m_Shadows[handle].m_ShadowHandle, worldOrigin,
  1924. vecShadowDir, matWorldToTexture, size, nCount, pLeafList, maxHeight, falloffStart, MAX_FALLOFF_AMOUNT, pRenderable->GetRenderOrigin() );
  1925. // Compute extra clip planes to prevent poke-thru
  1926. // FIXME!!!!!!!!!!!!!! Removing this for now since it seems to mess up the blobby shadows.
  1927. // ComputeExtraClipPlanes( pEnt, handle, vec, mins, maxs, localShadowDir );
  1928. // Add the shadow to the client leaf system so it correctly marks
  1929. // leafs as being affected by a particular shadow
  1930. ClientLeafSystem()->ProjectShadow( m_Shadows[handle].m_ClientLeafShadowHandle, nCount, pLeafList );
  1931. }
  1932. //-----------------------------------------------------------------------------
  1933. // Visualization....
  1934. //-----------------------------------------------------------------------------
  1935. void CClientShadowMgr::DrawRenderToTextureDebugInfo( IClientRenderable* pRenderable, const Vector& mins, const Vector& maxs )
  1936. {
  1937. if ( !debugoverlay )
  1938. return;
  1939. // Get the object's basis
  1940. Vector vec[3];
  1941. AngleVectors( pRenderable->GetRenderAngles(), &vec[0], &vec[1], &vec[2] );
  1942. vec[1] *= -1.0f;
  1943. Vector vecSize;
  1944. VectorSubtract( maxs, mins, vecSize );
  1945. Vector vecOrigin = pRenderable->GetRenderOrigin();
  1946. Vector start, end, end2;
  1947. VectorMA( vecOrigin, mins.x, vec[0], start );
  1948. VectorMA( start, mins.y, vec[1], start );
  1949. VectorMA( start, mins.z, vec[2], start );
  1950. VectorMA( start, vecSize.x, vec[0], end );
  1951. VectorMA( end, vecSize.z, vec[2], end2 );
  1952. debugoverlay->AddLineOverlay( start, end, 255, 0, 0, true, 0.01 );
  1953. debugoverlay->AddLineOverlay( end2, end, 255, 0, 0, true, 0.01 );
  1954. VectorMA( start, vecSize.y, vec[1], end );
  1955. VectorMA( end, vecSize.z, vec[2], end2 );
  1956. debugoverlay->AddLineOverlay( start, end, 255, 0, 0, true, 0.01 );
  1957. debugoverlay->AddLineOverlay( end2, end, 255, 0, 0, true, 0.01 );
  1958. VectorMA( start, vecSize.z, vec[2], end );
  1959. debugoverlay->AddLineOverlay( start, end, 255, 0, 0, true, 0.01 );
  1960. start = end;
  1961. VectorMA( start, vecSize.x, vec[0], end );
  1962. debugoverlay->AddLineOverlay( start, end, 255, 0, 0, true, 0.01 );
  1963. VectorMA( start, vecSize.y, vec[1], end );
  1964. debugoverlay->AddLineOverlay( start, end, 255, 0, 0, true, 0.01 );
  1965. VectorMA( end, vecSize.x, vec[0], start );
  1966. VectorMA( start, -vecSize.x, vec[0], end );
  1967. debugoverlay->AddLineOverlay( start, end, 255, 0, 0, true, 0.01 );
  1968. VectorMA( start, -vecSize.y, vec[1], end );
  1969. debugoverlay->AddLineOverlay( start, end, 255, 0, 0, true, 0.01 );
  1970. VectorMA( start, -vecSize.z, vec[2], end );
  1971. debugoverlay->AddLineOverlay( start, end, 255, 0, 0, true, 0.01 );
  1972. start = end;
  1973. VectorMA( start, -vecSize.x, vec[0], end );
  1974. debugoverlay->AddLineOverlay( start, end, 255, 0, 0, true, 0.01 );
  1975. VectorMA( start, -vecSize.y, vec[1], end );
  1976. debugoverlay->AddLineOverlay( start, end, 255, 0, 0, true, 0.01 );
  1977. C_BaseEntity *pEnt = pRenderable->GetIClientUnknown()->GetBaseEntity();
  1978. if ( pEnt )
  1979. {
  1980. debugoverlay->AddTextOverlay( vecOrigin, 0, "%d", pEnt->entindex() );
  1981. }
  1982. else
  1983. {
  1984. debugoverlay->AddTextOverlay( vecOrigin, 0, "%X", (size_t)pRenderable );
  1985. }
  1986. }
  1987. extern ConVar cl_drawshadowtexture;
  1988. extern ConVar cl_shadowtextureoverlaysize;
  1989. //-----------------------------------------------------------------------------
  1990. // Builds a more complex shadow...
  1991. //-----------------------------------------------------------------------------
  1992. void CClientShadowMgr::BuildRenderToTextureShadow( IClientRenderable* pRenderable,
  1993. ClientShadowHandle_t handle, const Vector& mins, const Vector& maxs)
  1994. {
  1995. if ( cl_drawshadowtexture.GetInt() )
  1996. {
  1997. // Red wireframe bounding box around objects whose RTT shadows are being updated that frame
  1998. DrawRenderToTextureDebugInfo( pRenderable, mins, maxs );
  1999. }
  2000. // Get the object's basis
  2001. Vector vec[3];
  2002. AngleVectors( pRenderable->GetRenderAngles(), &vec[0], &vec[1], &vec[2] );
  2003. vec[1] *= -1.0f;
  2004. Vector vecShadowDir = GetShadowDirection( pRenderable );
  2005. // Debugging aid
  2006. // const model_t *pModel = pRenderable->GetModel();
  2007. // const char *pDebugName = modelinfo->GetModelName( pModel );
  2008. // Project the shadow casting direction into the space of the object
  2009. Vector localShadowDir;
  2010. localShadowDir[0] = DotProduct( vec[0], vecShadowDir );
  2011. localShadowDir[1] = DotProduct( vec[1], vecShadowDir );
  2012. localShadowDir[2] = DotProduct( vec[2], vecShadowDir );
  2013. // Compute the box size
  2014. Vector boxSize;
  2015. VectorSubtract( maxs, mins, boxSize );
  2016. Vector yvec;
  2017. float fProjMax = 0.0f;
  2018. for( int i = 0; i != 3; ++i )
  2019. {
  2020. Vector test = vec[i] - ( vecShadowDir * DotProduct( vecShadowDir, vec[i] ) );
  2021. test *= boxSize[i]; //doing after the projection to simplify projection math
  2022. float fLengthSqr = test.LengthSqr();
  2023. if( fLengthSqr > fProjMax )
  2024. {
  2025. fProjMax = fLengthSqr;
  2026. yvec = test;
  2027. }
  2028. }
  2029. VectorNormalize( yvec );
  2030. // Compute the x vector
  2031. Vector xvec;
  2032. CrossProduct( yvec, vecShadowDir, xvec );
  2033. // We project the two longest sides into the vectors perpendicular
  2034. // to the projection direction, then add in the projection of the perp direction
  2035. Vector2D size;
  2036. size.x = boxSize.x * fabs( DotProduct( vec[0], xvec ) ) +
  2037. boxSize.y * fabs( DotProduct( vec[1], xvec ) ) +
  2038. boxSize.z * fabs( DotProduct( vec[2], xvec ) );
  2039. size.y = boxSize.x * fabs( DotProduct( vec[0], yvec ) ) +
  2040. boxSize.y * fabs( DotProduct( vec[1], yvec ) ) +
  2041. boxSize.z * fabs( DotProduct( vec[2], yvec ) );
  2042. size.x += 2.0f * TEXEL_SIZE_PER_CASTER_SIZE;
  2043. size.y += 2.0f * TEXEL_SIZE_PER_CASTER_SIZE;
  2044. // Place the origin at the point with min dot product with shadow dir
  2045. Vector org;
  2046. float falloffStart = ComputeLocalShadowOrigin( pRenderable, mins, maxs, localShadowDir, 1.0f, org );
  2047. // Transform the local origin into world coordinates
  2048. Vector worldOrigin = pRenderable->GetRenderOrigin( );
  2049. VectorMA( worldOrigin, org.x, vec[0], worldOrigin );
  2050. VectorMA( worldOrigin, org.y, vec[1], worldOrigin );
  2051. VectorMA( worldOrigin, org.z, vec[2], worldOrigin );
  2052. VMatrix matWorldToTexture;
  2053. BuildOrthoWorldToShadowMatrix( m_Shadows[handle].m_WorldToShadow, worldOrigin, vecShadowDir, xvec, yvec );
  2054. BuildWorldToTextureMatrix( m_Shadows[handle].m_WorldToShadow, size, matWorldToTexture );
  2055. Vector2DCopy( size, m_Shadows[handle].m_WorldSize );
  2056. // Compute the falloff attenuation
  2057. // Area computation isn't exact since xvec is not perp to yvec, but close enough
  2058. // Extra factor of 4 in the maxHeight due to the size being half as big
  2059. // float shadowArea = size.x * size.y;
  2060. // The entity may be overriding our shadow cast distance
  2061. float flShadowCastDistance = GetShadowDistance( pRenderable );
  2062. float maxHeight = flShadowCastDistance + falloffStart; //3.0f * sqrt( shadowArea );
  2063. CShadowLeafEnum leafList;
  2064. BuildShadowLeafList( &leafList, worldOrigin, vecShadowDir, size, maxHeight );
  2065. int nCount = leafList.m_LeafList.Count();
  2066. const int *pLeafList = leafList.m_LeafList.Base();
  2067. shadowmgr->ProjectShadow( m_Shadows[handle].m_ShadowHandle, worldOrigin,
  2068. vecShadowDir, matWorldToTexture, size, nCount, pLeafList, maxHeight, falloffStart, MAX_FALLOFF_AMOUNT, pRenderable->GetRenderOrigin() );
  2069. // Compute extra clip planes to prevent poke-thru
  2070. ComputeExtraClipPlanes( pRenderable, handle, vec, mins, maxs, localShadowDir );
  2071. // Add the shadow to the client leaf system so it correctly marks
  2072. // leafs as being affected by a particular shadow
  2073. ClientLeafSystem()->ProjectShadow( m_Shadows[handle].m_ClientLeafShadowHandle, nCount, pLeafList );
  2074. }
  2075. static void LineDrawHelper( const Vector &startShadowSpace, const Vector &endShadowSpace,
  2076. const VMatrix &shadowToWorld, unsigned char r = 255, unsigned char g = 255,
  2077. unsigned char b = 255 )
  2078. {
  2079. Vector startWorldSpace, endWorldSpace;
  2080. Vector3DMultiplyPositionProjective( shadowToWorld, startShadowSpace, startWorldSpace );
  2081. Vector3DMultiplyPositionProjective( shadowToWorld, endShadowSpace, endWorldSpace );
  2082. if ( debugoverlay )
  2083. {
  2084. debugoverlay->AddLineOverlay( startWorldSpace + Vector( 0.0f, 0.0f, 1.0f ),
  2085. endWorldSpace + Vector( 0.0f, 0.0f, 1.0f ), r, g, b, false, -1 );
  2086. }
  2087. }
  2088. static void DebugDrawFrustum( const Vector &vOrigin, const VMatrix &matWorldToFlashlight )
  2089. {
  2090. VMatrix flashlightToWorld;
  2091. MatrixInverseGeneral( matWorldToFlashlight, flashlightToWorld );
  2092. // Draw boundaries of frustum
  2093. LineDrawHelper( Vector( 0.0f, 0.0f, 0.0f ), Vector( 0.0f, 0.0f, 1.0f ), flashlightToWorld, 255, 255, 255 );
  2094. LineDrawHelper( Vector( 0.0f, 0.0f, 1.0f ), Vector( 0.0f, 1.0f, 1.0f ), flashlightToWorld, 255, 255, 255 );
  2095. LineDrawHelper( Vector( 0.0f, 1.0f, 1.0f ), Vector( 0.0f, 1.0f, 0.0f ), flashlightToWorld, 255, 255, 255 );
  2096. LineDrawHelper( Vector( 0.0f, 1.0f, 0.0f ), Vector( 0.0f, 0.0f, 0.0f ), flashlightToWorld, 255, 255, 255 );
  2097. LineDrawHelper( Vector( 1.0f, 0.0f, 0.0f ), Vector( 1.0f, 0.0f, 1.0f ), flashlightToWorld, 255, 255, 255 );
  2098. LineDrawHelper( Vector( 1.0f, 0.0f, 1.0f ), Vector( 1.0f, 1.0f, 1.0f ), flashlightToWorld, 255, 255, 255 );
  2099. LineDrawHelper( Vector( 1.0f, 1.0f, 1.0f ), Vector( 1.0f, 1.0f, 0.0f ), flashlightToWorld, 255, 255, 255 );
  2100. LineDrawHelper( Vector( 1.0f, 1.0f, 0.0f ), Vector( 1.0f, 0.0f, 0.0f ), flashlightToWorld, 255, 255, 255 );
  2101. LineDrawHelper( Vector( 0.0f, 0.0f, 0.0f ), Vector( 1.0f, 0.0f, 0.0f ), flashlightToWorld, 255, 255, 255 );
  2102. LineDrawHelper( Vector( 0.0f, 0.0f, 1.0f ), Vector( 1.0f, 0.0f, 1.0f ), flashlightToWorld, 255, 255, 255 );
  2103. LineDrawHelper( Vector( 0.0f, 1.0f, 1.0f ), Vector( 1.0f, 1.0f, 1.0f ), flashlightToWorld, 255, 255, 255 );
  2104. LineDrawHelper( Vector( 0.0f, 1.0f, 0.0f ), Vector( 1.0f, 1.0f, 0.0f ), flashlightToWorld, 255, 255, 255 );
  2105. // Draw RGB triad at front plane
  2106. LineDrawHelper( Vector( 0.5f, 0.5f, 0.0f ), Vector( 1.0f, 0.5f, 0.0f ), flashlightToWorld, 255, 0, 0 );
  2107. LineDrawHelper( Vector( 0.5f, 0.5f, 0.0f ), Vector( 0.5f, 1.0f, 0.0f ), flashlightToWorld, 0, 255, 0 );
  2108. LineDrawHelper( Vector( 0.5f, 0.5f, 0.0f ), Vector( 0.5f, 0.5f, 0.35f ), flashlightToWorld, 0, 0, 255 );
  2109. }
  2110. //-----------------------------------------------------------------------------
  2111. // Builds a list of leaves inside the flashlight volume
  2112. //-----------------------------------------------------------------------------
  2113. static void BuildFlashlightLeafList( CShadowLeafEnum *pEnum, const VMatrix &worldToShadow )
  2114. {
  2115. // Use an AABB around the frustum to enumerate leaves.
  2116. Vector mins, maxs;
  2117. CalculateAABBFromProjectionMatrix( worldToShadow, &mins, &maxs );
  2118. ISpatialQuery* pQuery = engine->GetBSPTreeQuery();
  2119. pQuery->EnumerateLeavesInBox( mins, maxs, pEnum, 0 );
  2120. }
  2121. void CClientShadowMgr::BuildFlashlight( ClientShadowHandle_t handle )
  2122. {
  2123. // For the 360, we just draw flashlights with the main geometry
  2124. // and bypass the entire shadow casting system.
  2125. ClientShadow_t &shadow = m_Shadows[handle];
  2126. if ( IsX360() || r_flashlight_version2.GetInt() )
  2127. {
  2128. // This will update the matrices, but not do work to add the flashlight to surfaces
  2129. shadowmgr->ProjectFlashlight( shadow.m_ShadowHandle, shadow.m_WorldToShadow, 0, NULL );
  2130. return;
  2131. }
  2132. VPROF_BUDGET( "CClientShadowMgr::BuildFlashlight", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  2133. bool bLightModels = r_flashlightmodels.GetBool();
  2134. bool bLightSpecificEntity = shadow.m_hTargetEntity.Get() != NULL;
  2135. bool bLightWorld = ( shadow.m_Flags & SHADOW_FLAGS_LIGHT_WORLD ) != 0;
  2136. int nCount = 0;
  2137. const int *pLeafList = 0;
  2138. CShadowLeafEnum leafList;
  2139. if ( bLightWorld || ( bLightModels && !bLightSpecificEntity ) )
  2140. {
  2141. BuildFlashlightLeafList( &leafList, shadow.m_WorldToShadow );
  2142. nCount = leafList.m_LeafList.Count();
  2143. pLeafList = leafList.m_LeafList.Base();
  2144. }
  2145. if( bLightWorld )
  2146. {
  2147. shadowmgr->ProjectFlashlight( shadow.m_ShadowHandle, shadow.m_WorldToShadow, nCount, pLeafList );
  2148. }
  2149. else
  2150. {
  2151. // This should clear all models and surfaces from this shadow
  2152. shadowmgr->EnableShadow( shadow.m_ShadowHandle, false );
  2153. shadowmgr->EnableShadow( shadow.m_ShadowHandle, true );
  2154. }
  2155. if ( !bLightModels )
  2156. return;
  2157. if ( !bLightSpecificEntity )
  2158. {
  2159. // Add the shadow to the client leaf system so it correctly marks
  2160. // leafs as being affected by a particular shadow
  2161. ClientLeafSystem()->ProjectFlashlight( shadow.m_ClientLeafShadowHandle, nCount, pLeafList );
  2162. return;
  2163. }
  2164. // We know what we are focused on, so just add the shadow directly to that receiver
  2165. Assert( shadow.m_hTargetEntity->GetModel() );
  2166. C_BaseEntity *pChild = shadow.m_hTargetEntity->FirstMoveChild();
  2167. while( pChild )
  2168. {
  2169. int modelType = modelinfo->GetModelType( pChild->GetModel() );
  2170. if (modelType == mod_brush)
  2171. {
  2172. AddShadowToReceiver( handle, pChild, SHADOW_RECEIVER_BRUSH_MODEL );
  2173. }
  2174. else if ( modelType == mod_studio )
  2175. {
  2176. AddShadowToReceiver( handle, pChild, SHADOW_RECEIVER_STUDIO_MODEL );
  2177. }
  2178. pChild = pChild->NextMovePeer();
  2179. }
  2180. int modelType = modelinfo->GetModelType( shadow.m_hTargetEntity->GetModel() );
  2181. if (modelType == mod_brush)
  2182. {
  2183. AddShadowToReceiver( handle, shadow.m_hTargetEntity, SHADOW_RECEIVER_BRUSH_MODEL );
  2184. }
  2185. else if ( modelType == mod_studio )
  2186. {
  2187. AddShadowToReceiver( handle, shadow.m_hTargetEntity, SHADOW_RECEIVER_STUDIO_MODEL );
  2188. }
  2189. }
  2190. //-----------------------------------------------------------------------------
  2191. // Adds the child bounds to the bounding box
  2192. //-----------------------------------------------------------------------------
  2193. void CClientShadowMgr::AddChildBounds( matrix3x4_t &matWorldToBBox, IClientRenderable* pParent, Vector &vecMins, Vector &vecMaxs )
  2194. {
  2195. Vector vecChildMins, vecChildMaxs;
  2196. Vector vecNewChildMins, vecNewChildMaxs;
  2197. matrix3x4_t childToBBox;
  2198. IClientRenderable *pChild = pParent->FirstShadowChild();
  2199. while( pChild )
  2200. {
  2201. // Transform the child bbox into the space of the main bbox
  2202. // FIXME: Optimize this?
  2203. if ( GetActualShadowCastType( pChild ) != SHADOWS_NONE)
  2204. {
  2205. pChild->GetShadowRenderBounds( vecChildMins, vecChildMaxs, SHADOWS_RENDER_TO_TEXTURE );
  2206. ConcatTransforms( matWorldToBBox, pChild->RenderableToWorldTransform(), childToBBox );
  2207. TransformAABB( childToBBox, vecChildMins, vecChildMaxs, vecNewChildMins, vecNewChildMaxs );
  2208. VectorMin( vecMins, vecNewChildMins, vecMins );
  2209. VectorMax( vecMaxs, vecNewChildMaxs, vecMaxs );
  2210. }
  2211. AddChildBounds( matWorldToBBox, pChild, vecMins, vecMaxs );
  2212. pChild = pChild->NextShadowPeer();
  2213. }
  2214. }
  2215. //-----------------------------------------------------------------------------
  2216. // Compute a bounds for the entity + children
  2217. //-----------------------------------------------------------------------------
  2218. void CClientShadowMgr::ComputeHierarchicalBounds( IClientRenderable *pRenderable, Vector &vecMins, Vector &vecMaxs )
  2219. {
  2220. ShadowType_t shadowType = GetActualShadowCastType( pRenderable );
  2221. pRenderable->GetShadowRenderBounds( vecMins, vecMaxs, shadowType );
  2222. // We could use a good solution for this in the regular PC build, since
  2223. // it causes lots of extra bone setups for entities you can't see.
  2224. if ( IsPC() )
  2225. {
  2226. IClientRenderable *pChild = pRenderable->FirstShadowChild();
  2227. // Don't recurse down the tree when we hit a blobby shadow
  2228. if ( pChild && shadowType != SHADOWS_SIMPLE )
  2229. {
  2230. matrix3x4_t matWorldToBBox;
  2231. MatrixInvert( pRenderable->RenderableToWorldTransform(), matWorldToBBox );
  2232. AddChildBounds( matWorldToBBox, pRenderable, vecMins, vecMaxs );
  2233. }
  2234. }
  2235. }
  2236. //-----------------------------------------------------------------------------
  2237. // Shadow update functions
  2238. //-----------------------------------------------------------------------------
  2239. void CClientShadowMgr::UpdateStudioShadow( IClientRenderable *pRenderable, ClientShadowHandle_t handle )
  2240. {
  2241. if( !( m_Shadows[handle].m_Flags & SHADOW_FLAGS_FLASHLIGHT ) )
  2242. {
  2243. Vector mins, maxs;
  2244. ComputeHierarchicalBounds( pRenderable, mins, maxs );
  2245. ShadowType_t shadowType = GetActualShadowCastType( handle );
  2246. if ( shadowType != SHADOWS_RENDER_TO_TEXTURE )
  2247. {
  2248. BuildOrthoShadow( pRenderable, handle, mins, maxs );
  2249. }
  2250. else
  2251. {
  2252. BuildRenderToTextureShadow( pRenderable, handle, mins, maxs );
  2253. }
  2254. }
  2255. else
  2256. {
  2257. BuildFlashlight( handle );
  2258. }
  2259. }
  2260. void CClientShadowMgr::UpdateBrushShadow( IClientRenderable *pRenderable, ClientShadowHandle_t handle )
  2261. {
  2262. if( !( m_Shadows[handle].m_Flags & SHADOW_FLAGS_FLASHLIGHT ) )
  2263. {
  2264. // Compute the bounding box in the space of the shadow...
  2265. Vector mins, maxs;
  2266. ComputeHierarchicalBounds( pRenderable, mins, maxs );
  2267. ShadowType_t shadowType = GetActualShadowCastType( handle );
  2268. if ( shadowType != SHADOWS_RENDER_TO_TEXTURE )
  2269. {
  2270. BuildOrthoShadow( pRenderable, handle, mins, maxs );
  2271. }
  2272. else
  2273. {
  2274. BuildRenderToTextureShadow( pRenderable, handle, mins, maxs );
  2275. }
  2276. }
  2277. else
  2278. {
  2279. VPROF_BUDGET( "CClientShadowMgr::UpdateBrushShadow", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  2280. BuildFlashlight( handle );
  2281. }
  2282. }
  2283. #ifdef _DEBUG
  2284. static bool s_bBreak = false;
  2285. void ShadowBreak_f()
  2286. {
  2287. s_bBreak = true;
  2288. }
  2289. static ConCommand r_shadowbreak("r_shadowbreak", ShadowBreak_f);
  2290. #endif // _DEBUG
  2291. bool CClientShadowMgr::WillParentRenderBlobbyShadow( IClientRenderable *pRenderable )
  2292. {
  2293. if ( !pRenderable )
  2294. return false;
  2295. IClientRenderable *pShadowParent = pRenderable->GetShadowParent();
  2296. if ( !pShadowParent )
  2297. return false;
  2298. // If there's *no* shadow casting type, then we want to see if we can render into its parent
  2299. ShadowType_t shadowType = GetActualShadowCastType( pShadowParent );
  2300. if ( shadowType == SHADOWS_NONE )
  2301. return WillParentRenderBlobbyShadow( pShadowParent );
  2302. return shadowType == SHADOWS_SIMPLE;
  2303. }
  2304. //-----------------------------------------------------------------------------
  2305. // Are we the child of a shadow with render-to-texture?
  2306. //-----------------------------------------------------------------------------
  2307. bool CClientShadowMgr::ShouldUseParentShadow( IClientRenderable *pRenderable )
  2308. {
  2309. if ( !pRenderable )
  2310. return false;
  2311. IClientRenderable *pShadowParent = pRenderable->GetShadowParent();
  2312. if ( !pShadowParent )
  2313. return false;
  2314. // Can't render into the parent if the parent is blobby
  2315. ShadowType_t shadowType = GetActualShadowCastType( pShadowParent );
  2316. if ( shadowType == SHADOWS_SIMPLE )
  2317. return false;
  2318. // If there's *no* shadow casting type, then we want to see if we can render into its parent
  2319. if ( shadowType == SHADOWS_NONE )
  2320. return ShouldUseParentShadow( pShadowParent );
  2321. // Here, the parent uses a render-to-texture shadow
  2322. return true;
  2323. }
  2324. //-----------------------------------------------------------------------------
  2325. // Before we render any view, make sure all shadows are re-projected vs world
  2326. //-----------------------------------------------------------------------------
  2327. void CClientShadowMgr::PreRender()
  2328. {
  2329. VPROF_BUDGET( "CClientShadowMgr::PreRender", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  2330. MDLCACHE_CRITICAL_SECTION();
  2331. //
  2332. // -- Shadow Depth Textures -----------------------
  2333. //
  2334. {
  2335. // VPROF scope
  2336. VPROF_BUDGET( "CClientShadowMgr::PreRender", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  2337. // If someone turned shadow depth mapping on but we can't do it, force it off
  2338. if ( r_flashlightdepthtexture.GetBool() && !materials->SupportsShadowDepthTextures() )
  2339. {
  2340. r_flashlightdepthtexture.SetValue( 0 );
  2341. ShutdownDepthTextureShadows();
  2342. }
  2343. bool bDepthTextureActive = r_flashlightdepthtexture.GetBool();
  2344. int nDepthTextureResolution = r_flashlightdepthres.GetInt();
  2345. // If shadow depth texture size or enable/disable changed, do appropriate deallocation/(re)allocation
  2346. if ( ( bDepthTextureActive != m_bDepthTextureActive ) || ( nDepthTextureResolution != m_nDepthTextureResolution ) )
  2347. {
  2348. // If shadow depth texturing remains on, but resolution changed, shut down and reinitialize depth textures
  2349. if ( ( bDepthTextureActive == true ) && ( m_bDepthTextureActive == true ) &&
  2350. ( nDepthTextureResolution != m_nDepthTextureResolution ) )
  2351. {
  2352. ShutdownDepthTextureShadows();
  2353. InitDepthTextureShadows();
  2354. }
  2355. else
  2356. {
  2357. if ( m_bDepthTextureActive && !bDepthTextureActive ) // Turning off shadow depth texturing
  2358. {
  2359. ShutdownDepthTextureShadows();
  2360. }
  2361. else if ( bDepthTextureActive && !m_bDepthTextureActive) // Turning on shadow depth mapping
  2362. {
  2363. InitDepthTextureShadows();
  2364. }
  2365. }
  2366. }
  2367. }
  2368. //
  2369. // -- Render to Texture Shadows -----------------------
  2370. //
  2371. bool bRenderToTextureActive = r_shadowrendertotexture.GetBool();
  2372. if ( bRenderToTextureActive != m_RenderToTextureActive )
  2373. {
  2374. if ( m_RenderToTextureActive )
  2375. {
  2376. ShutdownRenderToTextureShadows();
  2377. }
  2378. else
  2379. {
  2380. InitRenderToTextureShadows();
  2381. }
  2382. UpdateAllShadows();
  2383. return;
  2384. }
  2385. m_bUpdatingDirtyShadows = true;
  2386. unsigned short i = m_DirtyShadows.FirstInorder();
  2387. while ( i != m_DirtyShadows.InvalidIndex() )
  2388. {
  2389. ClientShadowHandle_t& handle = m_DirtyShadows[ i ];
  2390. Assert( m_Shadows.IsValidIndex( handle ) );
  2391. UpdateProjectedTextureInternal( handle, false );
  2392. i = m_DirtyShadows.NextInorder(i);
  2393. }
  2394. m_DirtyShadows.RemoveAll();
  2395. // Transparent shadows must remain dirty, since they were not re-projected
  2396. int nCount = m_TransparentShadows.Count();
  2397. for ( i = 0; i < nCount; ++i )
  2398. {
  2399. m_DirtyShadows.Insert( m_TransparentShadows[i] );
  2400. }
  2401. m_TransparentShadows.RemoveAll();
  2402. m_bUpdatingDirtyShadows = false;
  2403. }
  2404. //-----------------------------------------------------------------------------
  2405. // Gets the entity whose shadow this shadow will render into
  2406. //-----------------------------------------------------------------------------
  2407. IClientRenderable *CClientShadowMgr::GetParentShadowEntity( ClientShadowHandle_t handle )
  2408. {
  2409. ClientShadow_t& shadow = m_Shadows[handle];
  2410. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity );
  2411. if ( pRenderable )
  2412. {
  2413. if ( ShouldUseParentShadow( pRenderable ) )
  2414. {
  2415. IClientRenderable *pParent = pRenderable->GetShadowParent();
  2416. while ( GetActualShadowCastType( pParent ) == SHADOWS_NONE )
  2417. {
  2418. pParent = pParent->GetShadowParent();
  2419. Assert( pParent );
  2420. }
  2421. return pParent;
  2422. }
  2423. }
  2424. return NULL;
  2425. }
  2426. //-----------------------------------------------------------------------------
  2427. // Marks a shadow as needing re-projection
  2428. //-----------------------------------------------------------------------------
  2429. void CClientShadowMgr::AddToDirtyShadowList( ClientShadowHandle_t handle, bool bForce )
  2430. {
  2431. // Don't add to the dirty shadow list while we're iterating over it
  2432. // The only way this can happen is if a child is being rendered into a parent
  2433. // shadow, and we don't need it to be added to the dirty list in that case.
  2434. if ( m_bUpdatingDirtyShadows )
  2435. return;
  2436. if ( handle == CLIENTSHADOW_INVALID_HANDLE )
  2437. return;
  2438. Assert( m_DirtyShadows.Find( handle ) == m_DirtyShadows.InvalidIndex() );
  2439. m_DirtyShadows.Insert( handle );
  2440. // This pretty much guarantees we'll recompute the shadow
  2441. if ( bForce )
  2442. {
  2443. m_Shadows[handle].m_LastAngles.Init( FLT_MAX, FLT_MAX, FLT_MAX );
  2444. }
  2445. // If we use our parent shadow, then it's dirty too...
  2446. IClientRenderable *pParent = GetParentShadowEntity( handle );
  2447. if ( pParent )
  2448. {
  2449. AddToDirtyShadowList( pParent, bForce );
  2450. }
  2451. }
  2452. //-----------------------------------------------------------------------------
  2453. // Marks a shadow as needing re-projection
  2454. //-----------------------------------------------------------------------------
  2455. void CClientShadowMgr::AddToDirtyShadowList( IClientRenderable *pRenderable, bool bForce )
  2456. {
  2457. // Don't add to the dirty shadow list while we're iterating over it
  2458. // The only way this can happen is if a child is being rendered into a parent
  2459. // shadow, and we don't need it to be added to the dirty list in that case.
  2460. if ( m_bUpdatingDirtyShadows )
  2461. return;
  2462. // Are we already in the dirty list?
  2463. if ( pRenderable->IsShadowDirty( ) )
  2464. return;
  2465. ClientShadowHandle_t handle = pRenderable->GetShadowHandle();
  2466. if ( handle == CLIENTSHADOW_INVALID_HANDLE )
  2467. return;
  2468. #ifdef _DEBUG
  2469. // Make sure everything's consistent
  2470. if ( handle != CLIENTSHADOW_INVALID_HANDLE )
  2471. {
  2472. IClientRenderable *pShadowRenderable = ClientEntityList().GetClientRenderableFromHandle( m_Shadows[handle].m_Entity );
  2473. Assert( pRenderable == pShadowRenderable );
  2474. }
  2475. #endif
  2476. pRenderable->MarkShadowDirty( true );
  2477. AddToDirtyShadowList( handle, bForce );
  2478. }
  2479. //-----------------------------------------------------------------------------
  2480. // Marks the render-to-texture shadow as needing to be re-rendered
  2481. //-----------------------------------------------------------------------------
  2482. void CClientShadowMgr::MarkRenderToTextureShadowDirty( ClientShadowHandle_t handle )
  2483. {
  2484. // Don't add bogus handles!
  2485. if (handle != CLIENTSHADOW_INVALID_HANDLE)
  2486. {
  2487. // Mark the shadow has having a dirty renter-to-texture
  2488. ClientShadow_t& shadow = m_Shadows[handle];
  2489. shadow.m_Flags |= SHADOW_FLAGS_TEXTURE_DIRTY;
  2490. // If we use our parent shadow, then it's dirty too...
  2491. IClientRenderable *pParent = GetParentShadowEntity( handle );
  2492. if ( pParent )
  2493. {
  2494. ClientShadowHandle_t parentHandle = pParent->GetShadowHandle();
  2495. if ( parentHandle != CLIENTSHADOW_INVALID_HANDLE )
  2496. {
  2497. m_Shadows[parentHandle].m_Flags |= SHADOW_FLAGS_TEXTURE_DIRTY;
  2498. }
  2499. }
  2500. }
  2501. }
  2502. //-----------------------------------------------------------------------------
  2503. // Update a shadow
  2504. //-----------------------------------------------------------------------------
  2505. void CClientShadowMgr::UpdateShadow( ClientShadowHandle_t handle, bool force )
  2506. {
  2507. ClientShadow_t& shadow = m_Shadows[handle];
  2508. // Get the client entity....
  2509. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity );
  2510. if ( !pRenderable )
  2511. {
  2512. // Retire the shadow if the entity is gone
  2513. DestroyShadow( handle );
  2514. return;
  2515. }
  2516. // Don't bother if there's no model on the renderable
  2517. if ( !pRenderable->GetModel() )
  2518. {
  2519. pRenderable->MarkShadowDirty( false );
  2520. return;
  2521. }
  2522. // FIXME: NOTE! Because this is called from PreRender, the falloff bias is
  2523. // off by a frame. We could move the code in PreRender to occur after world
  2524. // list building is done to fix this issue.
  2525. // Don't bother with it if the shadow is totally transparent
  2526. const ShadowInfo_t &shadowInfo = shadowmgr->GetInfo( shadow.m_ShadowHandle );
  2527. if ( shadowInfo.m_FalloffBias == 255 )
  2528. {
  2529. shadowmgr->EnableShadow( shadow.m_ShadowHandle, false );
  2530. m_TransparentShadows.AddToTail( handle );
  2531. return;
  2532. }
  2533. #ifdef _DEBUG
  2534. if (s_bBreak)
  2535. {
  2536. s_bBreak = false;
  2537. }
  2538. #endif
  2539. // Hierarchical children shouldn't be projecting shadows...
  2540. // Check to see if it's a child of an entity with a render-to-texture shadow...
  2541. if ( ShouldUseParentShadow( pRenderable ) || WillParentRenderBlobbyShadow( pRenderable ) )
  2542. {
  2543. shadowmgr->EnableShadow( shadow.m_ShadowHandle, false );
  2544. pRenderable->MarkShadowDirty( false );
  2545. return;
  2546. }
  2547. shadowmgr->EnableShadow( shadow.m_ShadowHandle, true );
  2548. // Figure out if the shadow moved...
  2549. // Even though we have dirty bits, some entities
  2550. // never clear those dirty bits
  2551. const Vector& origin = pRenderable->GetRenderOrigin();
  2552. const QAngle& angles = pRenderable->GetRenderAngles();
  2553. if (force || (origin != shadow.m_LastOrigin) || (angles != shadow.m_LastAngles))
  2554. {
  2555. // Store off the new pos/orientation
  2556. VectorCopy( origin, shadow.m_LastOrigin );
  2557. VectorCopy( angles, shadow.m_LastAngles );
  2558. CMatRenderContextPtr pRenderContext( materials );
  2559. const model_t *pModel = pRenderable->GetModel();
  2560. MaterialFogMode_t fogMode = pRenderContext->GetFogMode();
  2561. pRenderContext->FogMode( MATERIAL_FOG_NONE );
  2562. switch( modelinfo->GetModelType( pModel ) )
  2563. {
  2564. case mod_brush:
  2565. UpdateBrushShadow( pRenderable, handle );
  2566. break;
  2567. case mod_studio:
  2568. UpdateStudioShadow( pRenderable, handle );
  2569. break;
  2570. default:
  2571. // Shouldn't get here if not a brush or studio
  2572. Assert(0);
  2573. break;
  2574. }
  2575. pRenderContext->FogMode( fogMode );
  2576. }
  2577. // NOTE: We can't do this earlier because pEnt->GetRenderOrigin() can
  2578. // provoke a recomputation of render origin, which, for aiments, can cause everything
  2579. // to be marked as dirty. So don't clear the flag until this point.
  2580. pRenderable->MarkShadowDirty( false );
  2581. }
  2582. //-----------------------------------------------------------------------------
  2583. // Update a shadow
  2584. //-----------------------------------------------------------------------------
  2585. void CClientShadowMgr::UpdateProjectedTextureInternal( ClientShadowHandle_t handle, bool force )
  2586. {
  2587. ClientShadow_t& shadow = m_Shadows[handle];
  2588. if( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT )
  2589. {
  2590. VPROF_BUDGET( "CClientShadowMgr::UpdateProjectedTextureInternal", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  2591. Assert( ( shadow.m_Flags & SHADOW_FLAGS_SHADOW ) == 0 );
  2592. ClientShadow_t& shadowClient = m_Shadows[handle];
  2593. shadowmgr->EnableShadow( shadowClient.m_ShadowHandle, true );
  2594. // FIXME: What's the difference between brush and model shadows for light projectors? Answer: nothing.
  2595. UpdateBrushShadow( NULL, handle );
  2596. }
  2597. else
  2598. {
  2599. Assert( shadow.m_Flags & SHADOW_FLAGS_SHADOW );
  2600. Assert( ( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) == 0 );
  2601. UpdateShadow( handle, force );
  2602. }
  2603. }
  2604. //-----------------------------------------------------------------------------
  2605. // Update a shadow
  2606. //-----------------------------------------------------------------------------
  2607. void CClientShadowMgr::UpdateProjectedTexture( ClientShadowHandle_t handle, bool force )
  2608. {
  2609. VPROF_BUDGET( "CClientShadowMgr::UpdateProjectedTexture", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  2610. if ( handle == CLIENTSHADOW_INVALID_HANDLE )
  2611. return;
  2612. // NOTE: This can only work for flashlights, since UpdateProjectedTextureInternal
  2613. // depends on the falloff offset to cull shadows.
  2614. ClientShadow_t &shadow = m_Shadows[ handle ];
  2615. if( ( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) == 0 )
  2616. {
  2617. Warning( "CClientShadowMgr::UpdateProjectedTexture can only be used with flashlights!\n" );
  2618. return;
  2619. }
  2620. UpdateProjectedTextureInternal( handle, force );
  2621. RemoveShadowFromDirtyList( handle );
  2622. }
  2623. //-----------------------------------------------------------------------------
  2624. // Computes bounding sphere
  2625. //-----------------------------------------------------------------------------
  2626. void CClientShadowMgr::ComputeBoundingSphere( IClientRenderable* pRenderable, Vector& origin, float& radius )
  2627. {
  2628. Assert( pRenderable );
  2629. Vector mins, maxs;
  2630. pRenderable->GetShadowRenderBounds( mins, maxs, GetActualShadowCastType( pRenderable ) );
  2631. Vector size;
  2632. VectorSubtract( maxs, mins, size );
  2633. radius = size.Length() * 0.5f;
  2634. // Compute centroid (local space)
  2635. Vector centroid;
  2636. VectorAdd( mins, maxs, centroid );
  2637. centroid *= 0.5f;
  2638. // Transform centroid into world space
  2639. Vector vec[3];
  2640. AngleVectors( pRenderable->GetRenderAngles(), &vec[0], &vec[1], &vec[2] );
  2641. vec[1] *= -1.0f;
  2642. VectorCopy( pRenderable->GetRenderOrigin(), origin );
  2643. VectorMA( origin, centroid.x, vec[0], origin );
  2644. VectorMA( origin, centroid.y, vec[1], origin );
  2645. VectorMA( origin, centroid.z, vec[2], origin );
  2646. }
  2647. //-----------------------------------------------------------------------------
  2648. // Computes a rough AABB encompassing the volume of the shadow
  2649. //-----------------------------------------------------------------------------
  2650. void CClientShadowMgr::ComputeShadowBBox( IClientRenderable *pRenderable, const Vector &vecAbsCenter, float flRadius, Vector *pAbsMins, Vector *pAbsMaxs )
  2651. {
  2652. // This is *really* rough. Basically we simply determine the
  2653. // maximum shadow casting length and extrude the box by that distance
  2654. Vector vecShadowDir = GetShadowDirection( pRenderable );
  2655. for (int i = 0; i < 3; ++i)
  2656. {
  2657. float flShadowCastDistance = GetShadowDistance( pRenderable );
  2658. float flDist = flShadowCastDistance * vecShadowDir[i];
  2659. if (vecShadowDir[i] < 0)
  2660. {
  2661. (*pAbsMins)[i] = vecAbsCenter[i] - flRadius + flDist;
  2662. (*pAbsMaxs)[i] = vecAbsCenter[i] + flRadius;
  2663. }
  2664. else
  2665. {
  2666. (*pAbsMins)[i] = vecAbsCenter[i] - flRadius;
  2667. (*pAbsMaxs)[i] = vecAbsCenter[i] + flRadius + flDist;
  2668. }
  2669. }
  2670. }
  2671. //-----------------------------------------------------------------------------
  2672. // Compute a separating axis...
  2673. //-----------------------------------------------------------------------------
  2674. bool CClientShadowMgr::ComputeSeparatingPlane( IClientRenderable* pRend1, IClientRenderable* pRend2, cplane_t* pPlane )
  2675. {
  2676. Vector min1, max1, min2, max2;
  2677. pRend1->GetShadowRenderBounds( min1, max1, GetActualShadowCastType( pRend1 ) );
  2678. pRend2->GetShadowRenderBounds( min2, max2, GetActualShadowCastType( pRend2 ) );
  2679. return ::ComputeSeparatingPlane(
  2680. pRend1->GetRenderOrigin(), pRend1->GetRenderAngles(), min1, max1,
  2681. pRend2->GetRenderOrigin(), pRend2->GetRenderAngles(), min2, max2,
  2682. 3.0f, pPlane );
  2683. }
  2684. //-----------------------------------------------------------------------------
  2685. // Cull shadows based on rough bounding volumes
  2686. //-----------------------------------------------------------------------------
  2687. bool CClientShadowMgr::CullReceiver( ClientShadowHandle_t handle, IClientRenderable* pRenderable,
  2688. IClientRenderable* pSourceRenderable )
  2689. {
  2690. // check flags here instead and assert !pSourceRenderable
  2691. if( m_Shadows[handle].m_Flags & SHADOW_FLAGS_FLASHLIGHT )
  2692. {
  2693. VPROF_BUDGET( "CClientShadowMgr::CullReceiver", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  2694. Assert( !pSourceRenderable );
  2695. const Frustum_t &frustum = shadowmgr->GetFlashlightFrustum( m_Shadows[handle].m_ShadowHandle );
  2696. Vector mins, maxs;
  2697. pRenderable->GetRenderBoundsWorldspace( mins, maxs );
  2698. return R_CullBox( mins, maxs, frustum );
  2699. }
  2700. Assert( pSourceRenderable );
  2701. // Compute a bounding sphere for the renderable
  2702. Vector origin;
  2703. float radius;
  2704. ComputeBoundingSphere( pRenderable, origin, radius );
  2705. // Transform the sphere center into the space of the shadow
  2706. Vector localOrigin;
  2707. const ClientShadow_t& shadow = m_Shadows[handle];
  2708. const ShadowInfo_t& info = shadowmgr->GetInfo( shadow.m_ShadowHandle );
  2709. Vector3DMultiplyPosition( shadow.m_WorldToShadow, origin, localOrigin );
  2710. // Compute a rough bounding box for the shadow (in shadow space)
  2711. Vector shadowMin, shadowMax;
  2712. shadowMin.Init( -shadow.m_WorldSize.x * 0.5f, -shadow.m_WorldSize.y * 0.5f, 0 );
  2713. shadowMax.Init( shadow.m_WorldSize.x * 0.5f, shadow.m_WorldSize.y * 0.5f, info.m_MaxDist );
  2714. // If the bounding sphere doesn't intersect with the shadow volume, cull
  2715. if (!IsBoxIntersectingSphere( shadowMin, shadowMax, localOrigin, radius ))
  2716. return true;
  2717. Vector originSource;
  2718. float radiusSource;
  2719. ComputeBoundingSphere( pSourceRenderable, originSource, radiusSource );
  2720. // Fast check for separating plane...
  2721. bool foundSeparatingPlane = false;
  2722. cplane_t plane;
  2723. if (!IsSphereIntersectingSphere( originSource, radiusSource, origin, radius ))
  2724. {
  2725. foundSeparatingPlane = true;
  2726. // the plane normal doesn't need to be normalized...
  2727. VectorSubtract( origin, originSource, plane.normal );
  2728. }
  2729. else
  2730. {
  2731. foundSeparatingPlane = ComputeSeparatingPlane( pRenderable, pSourceRenderable, &plane );
  2732. }
  2733. if (foundSeparatingPlane)
  2734. {
  2735. // Compute which side of the plane the renderable is on..
  2736. Vector vecShadowDir = GetShadowDirection( pSourceRenderable );
  2737. float shadowDot = DotProduct( vecShadowDir, plane.normal );
  2738. float receiverDot = DotProduct( plane.normal, origin );
  2739. float sourceDot = DotProduct( plane.normal, originSource );
  2740. if (shadowDot > 0.0f)
  2741. {
  2742. if (receiverDot <= sourceDot)
  2743. {
  2744. // Vector dest;
  2745. // VectorMA( pSourceRenderable->GetRenderOrigin(), 50, plane.normal, dest );
  2746. // debugoverlay->AddLineOverlay( pSourceRenderable->GetRenderOrigin(), dest, 255, 255, 0, true, 1.0f );
  2747. return true;
  2748. }
  2749. else
  2750. {
  2751. // Vector dest;
  2752. // VectorMA( pSourceRenderable->GetRenderOrigin(), 50, plane.normal, dest );
  2753. // debugoverlay->AddLineOverlay( pSourceRenderable->GetRenderOrigin(), dest, 255, 0, 0, true, 1.0f );
  2754. }
  2755. }
  2756. else
  2757. {
  2758. if (receiverDot >= sourceDot)
  2759. {
  2760. // Vector dest;
  2761. // VectorMA( pSourceRenderable->GetRenderOrigin(), -50, plane.normal, dest );
  2762. // debugoverlay->AddLineOverlay( pSourceRenderable->GetRenderOrigin(), dest, 255, 255, 0, true, 1.0f );
  2763. return true;
  2764. }
  2765. else
  2766. {
  2767. // Vector dest;
  2768. // VectorMA( pSourceRenderable->GetRenderOrigin(), 50, plane.normal, dest );
  2769. // debugoverlay->AddLineOverlay( pSourceRenderable->GetRenderOrigin(), dest, 255, 0, 0, true, 1.0f );
  2770. }
  2771. }
  2772. }
  2773. // No additional clip planes? ok then it's a valid receiver
  2774. /*
  2775. if (shadow.m_ClipPlaneCount == 0)
  2776. return false;
  2777. // Check the additional cull planes
  2778. int i;
  2779. for ( i = 0; i < shadow.m_ClipPlaneCount; ++i)
  2780. {
  2781. // Fast sphere cull
  2782. if (DotProduct( origin, shadow.m_ClipPlane[i] ) - radius > shadow.m_ClipDist[i])
  2783. return true;
  2784. }
  2785. // More expensive box on plane side cull...
  2786. Vector vec[3];
  2787. Vector mins, maxs;
  2788. cplane_t plane;
  2789. AngleVectors( pRenderable->GetRenderAngles(), &vec[0], &vec[1], &vec[2] );
  2790. pRenderable->GetBounds( mins, maxs );
  2791. for ( i = 0; i < shadow.m_ClipPlaneCount; ++i)
  2792. {
  2793. // Transform the plane into the space of the receiver
  2794. plane.normal.x = DotProduct( vec[0], shadow.m_ClipPlane[i] );
  2795. plane.normal.y = DotProduct( vec[1], shadow.m_ClipPlane[i] );
  2796. plane.normal.z = DotProduct( vec[2], shadow.m_ClipPlane[i] );
  2797. plane.dist = shadow.m_ClipDist[i] - DotProduct( shadow.m_ClipPlane[i], pRenderable->GetRenderOrigin() );
  2798. // If the box is on the front side of the plane, we're done.
  2799. if (BoxOnPlaneSide2( mins, maxs, &plane, 3.0f ) == 1)
  2800. return true;
  2801. }
  2802. */
  2803. return false;
  2804. }
  2805. //-----------------------------------------------------------------------------
  2806. // deals with shadows being added to shadow receivers
  2807. //-----------------------------------------------------------------------------
  2808. void CClientShadowMgr::AddShadowToReceiver( ClientShadowHandle_t handle,
  2809. IClientRenderable* pRenderable, ShadowReceiver_t type )
  2810. {
  2811. ClientShadow_t &shadow = m_Shadows[handle];
  2812. // Don't add a shadow cast by an object to itself...
  2813. IClientRenderable* pSourceRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity );
  2814. // NOTE: if pSourceRenderable == NULL, the source is probably a flashlight since there is no entity.
  2815. if (pSourceRenderable == pRenderable)
  2816. return;
  2817. // Don't bother if this renderable doesn't receive shadows or light from flashlights
  2818. if( !pRenderable->ShouldReceiveProjectedTextures( SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK ) )
  2819. return;
  2820. // Cull if the origin is on the wrong side of a shadow clip plane....
  2821. if ( CullReceiver( handle, pRenderable, pSourceRenderable ) )
  2822. return;
  2823. // Do different things depending on the receiver type
  2824. switch( type )
  2825. {
  2826. case SHADOW_RECEIVER_BRUSH_MODEL:
  2827. if( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT )
  2828. {
  2829. VPROF_BUDGET( "CClientShadowMgr::AddShadowToReceiver", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  2830. if( (!shadow.m_hTargetEntity) || IsFlashlightTarget( handle, pRenderable ) )
  2831. {
  2832. shadowmgr->AddShadowToBrushModel( shadow.m_ShadowHandle,
  2833. const_cast<model_t*>(pRenderable->GetModel()),
  2834. pRenderable->GetRenderOrigin(), pRenderable->GetRenderAngles() );
  2835. shadowmgr->AddFlashlightRenderable( shadow.m_ShadowHandle, pRenderable );
  2836. }
  2837. }
  2838. else
  2839. {
  2840. shadowmgr->AddShadowToBrushModel( shadow.m_ShadowHandle,
  2841. const_cast<model_t*>(pRenderable->GetModel()),
  2842. pRenderable->GetRenderOrigin(), pRenderable->GetRenderAngles() );
  2843. }
  2844. break;
  2845. case SHADOW_RECEIVER_STATIC_PROP:
  2846. // Don't add shadows to props if we're not using render-to-texture
  2847. if ( GetActualShadowCastType( handle ) == SHADOWS_RENDER_TO_TEXTURE )
  2848. {
  2849. // Also don't add them unless an NPC or player casts them..
  2850. // They are wickedly expensive!!!
  2851. C_BaseEntity *pEnt = pSourceRenderable->GetIClientUnknown()->GetBaseEntity();
  2852. if ( pEnt && ( pEnt->GetFlags() & (FL_NPC | FL_CLIENT)) )
  2853. {
  2854. staticpropmgr->AddShadowToStaticProp( shadow.m_ShadowHandle, pRenderable );
  2855. }
  2856. }
  2857. else if( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT )
  2858. {
  2859. VPROF_BUDGET( "CClientShadowMgr::AddShadowToReceiver", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  2860. if( (!shadow.m_hTargetEntity) || IsFlashlightTarget( handle, pRenderable ) )
  2861. {
  2862. staticpropmgr->AddShadowToStaticProp( shadow.m_ShadowHandle, pRenderable );
  2863. shadowmgr->AddFlashlightRenderable( shadow.m_ShadowHandle, pRenderable );
  2864. }
  2865. }
  2866. break;
  2867. case SHADOW_RECEIVER_STUDIO_MODEL:
  2868. if( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT )
  2869. {
  2870. VPROF_BUDGET( "CClientShadowMgr::AddShadowToReceiver", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  2871. if( (!shadow.m_hTargetEntity) || IsFlashlightTarget( handle, pRenderable ) )
  2872. {
  2873. pRenderable->CreateModelInstance();
  2874. shadowmgr->AddShadowToModel( shadow.m_ShadowHandle, pRenderable->GetModelInstance() );
  2875. shadowmgr->AddFlashlightRenderable( shadow.m_ShadowHandle, pRenderable );
  2876. }
  2877. }
  2878. break;
  2879. // default:
  2880. }
  2881. }
  2882. //-----------------------------------------------------------------------------
  2883. // deals with shadows being added to shadow receivers
  2884. //-----------------------------------------------------------------------------
  2885. void CClientShadowMgr::RemoveAllShadowsFromReceiver(
  2886. IClientRenderable* pRenderable, ShadowReceiver_t type )
  2887. {
  2888. // Don't bother if this renderable doesn't receive shadows
  2889. if ( !pRenderable->ShouldReceiveProjectedTextures( SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK ) )
  2890. return;
  2891. // Do different things depending on the receiver type
  2892. switch( type )
  2893. {
  2894. case SHADOW_RECEIVER_BRUSH_MODEL:
  2895. {
  2896. model_t* pModel = const_cast<model_t*>(pRenderable->GetModel());
  2897. shadowmgr->RemoveAllShadowsFromBrushModel( pModel );
  2898. }
  2899. break;
  2900. case SHADOW_RECEIVER_STATIC_PROP:
  2901. staticpropmgr->RemoveAllShadowsFromStaticProp(pRenderable);
  2902. break;
  2903. case SHADOW_RECEIVER_STUDIO_MODEL:
  2904. if( pRenderable && pRenderable->GetModelInstance() != MODEL_INSTANCE_INVALID )
  2905. {
  2906. shadowmgr->RemoveAllShadowsFromModel( pRenderable->GetModelInstance() );
  2907. }
  2908. break;
  2909. // default:
  2910. // // FIXME: How do deal with this stuff? Add a method to IClientRenderable?
  2911. // C_BaseEntity* pEnt = static_cast<C_BaseEntity*>(pRenderable);
  2912. // pEnt->RemoveAllShadows();
  2913. }
  2914. }
  2915. //-----------------------------------------------------------------------------
  2916. // Computes + sets the render-to-texture texcoords
  2917. //-----------------------------------------------------------------------------
  2918. void CClientShadowMgr::SetRenderToTextureShadowTexCoords( ShadowHandle_t handle, int x, int y, int w, int h )
  2919. {
  2920. // Let the shadow mgr know about the texture coordinates...
  2921. // That way it'll be able to batch rendering better.
  2922. int textureW, textureH;
  2923. m_ShadowAllocator.GetTotalTextureSize( textureW, textureH );
  2924. // Go in a half-pixel to avoid blending with neighboring textures..
  2925. float u, v, du, dv;
  2926. u = ((float)x + 0.5f) / (float)textureW;
  2927. v = ((float)y + 0.5f) / (float)textureH;
  2928. du = ((float)w - 1) / (float)textureW;
  2929. dv = ((float)h - 1) / (float)textureH;
  2930. shadowmgr->SetShadowTexCoord( handle, u, v, du, dv );
  2931. }
  2932. //-----------------------------------------------------------------------------
  2933. // Setup all children shadows
  2934. //-----------------------------------------------------------------------------
  2935. bool CClientShadowMgr::BuildSetupShadowHierarchy( IClientRenderable *pRenderable, const ClientShadow_t &shadow, bool bChild )
  2936. {
  2937. bool bDrewTexture = false;
  2938. // Stop traversing when we hit a blobby shadow
  2939. ShadowType_t shadowType = GetActualShadowCastType( pRenderable );
  2940. if ( pRenderable && shadowType == SHADOWS_SIMPLE )
  2941. return false;
  2942. if ( !pRenderable || shadowType != SHADOWS_NONE )
  2943. {
  2944. bool bDrawModelShadow;
  2945. if ( !bChild )
  2946. {
  2947. bDrawModelShadow = ((shadow.m_Flags & SHADOW_FLAGS_BRUSH_MODEL) == 0);
  2948. }
  2949. else
  2950. {
  2951. int nModelType = modelinfo->GetModelType( pRenderable->GetModel() );
  2952. bDrawModelShadow = nModelType == mod_studio;
  2953. }
  2954. if ( bDrawModelShadow )
  2955. {
  2956. C_BaseEntity *pEntity = pRenderable->GetIClientUnknown()->GetBaseEntity();
  2957. if ( pEntity )
  2958. {
  2959. if ( pEntity->IsNPC() )
  2960. {
  2961. s_NPCShadowBoneSetups.AddToTail( assert_cast<C_BaseAnimating *>( pEntity ) );
  2962. }
  2963. else if ( pEntity->GetBaseAnimating() )
  2964. {
  2965. s_NonNPCShadowBoneSetups.AddToTail( assert_cast<C_BaseAnimating *>( pEntity ) );
  2966. }
  2967. }
  2968. bDrewTexture = true;
  2969. }
  2970. }
  2971. if ( !pRenderable )
  2972. return bDrewTexture;
  2973. IClientRenderable *pChild;
  2974. for ( pChild = pRenderable->FirstShadowChild(); pChild; pChild = pChild->NextShadowPeer() )
  2975. {
  2976. if ( BuildSetupShadowHierarchy( pChild, shadow, true ) )
  2977. {
  2978. bDrewTexture = true;
  2979. }
  2980. }
  2981. return bDrewTexture;
  2982. }
  2983. //-----------------------------------------------------------------------------
  2984. // Draws all children shadows into our own
  2985. //-----------------------------------------------------------------------------
  2986. bool CClientShadowMgr::DrawShadowHierarchy( IClientRenderable *pRenderable, const ClientShadow_t &shadow, bool bChild )
  2987. {
  2988. bool bDrewTexture = false;
  2989. // Stop traversing when we hit a blobby shadow
  2990. ShadowType_t shadowType = GetActualShadowCastType( pRenderable );
  2991. if ( pRenderable && shadowType == SHADOWS_SIMPLE )
  2992. return false;
  2993. if ( !pRenderable || shadowType != SHADOWS_NONE )
  2994. {
  2995. bool bDrawModelShadow;
  2996. bool bDrawBrushShadow;
  2997. if ( !bChild )
  2998. {
  2999. bDrawModelShadow = ((shadow.m_Flags & SHADOW_FLAGS_BRUSH_MODEL) == 0);
  3000. bDrawBrushShadow = !bDrawModelShadow;
  3001. }
  3002. else
  3003. {
  3004. int nModelType = modelinfo->GetModelType( pRenderable->GetModel() );
  3005. bDrawModelShadow = nModelType == mod_studio;
  3006. bDrawBrushShadow = nModelType == mod_brush;
  3007. }
  3008. if ( bDrawModelShadow )
  3009. {
  3010. DrawModelInfo_t info;
  3011. matrix3x4_t *pBoneToWorld = modelrender->DrawModelShadowSetup( pRenderable, pRenderable->GetBody(), pRenderable->GetSkin(), &info );
  3012. if ( pBoneToWorld )
  3013. {
  3014. modelrender->DrawModelShadow( pRenderable, info, pBoneToWorld );
  3015. }
  3016. bDrewTexture = true;
  3017. }
  3018. else if ( bDrawBrushShadow )
  3019. {
  3020. render->DrawBrushModelShadow( pRenderable );
  3021. bDrewTexture = true;
  3022. }
  3023. }
  3024. if ( !pRenderable )
  3025. return bDrewTexture;
  3026. IClientRenderable *pChild;
  3027. for ( pChild = pRenderable->FirstShadowChild(); pChild; pChild = pChild->NextShadowPeer() )
  3028. {
  3029. if ( DrawShadowHierarchy( pChild, shadow, true ) )
  3030. {
  3031. bDrewTexture = true;
  3032. }
  3033. }
  3034. return bDrewTexture;
  3035. }
  3036. //-----------------------------------------------------------------------------
  3037. // This gets called with every shadow that potentially will need to re-render
  3038. //-----------------------------------------------------------------------------
  3039. bool CClientShadowMgr::BuildSetupListForRenderToTextureShadow( unsigned short clientShadowHandle, float flArea )
  3040. {
  3041. ClientShadow_t& shadow = m_Shadows[clientShadowHandle];
  3042. bool bDirtyTexture = (shadow.m_Flags & SHADOW_FLAGS_TEXTURE_DIRTY) != 0;
  3043. bool bNeedsRedraw = m_ShadowAllocator.UseTexture( shadow.m_ShadowTexture, bDirtyTexture, flArea );
  3044. if ( bNeedsRedraw || bDirtyTexture )
  3045. {
  3046. shadow.m_Flags |= SHADOW_FLAGS_TEXTURE_DIRTY;
  3047. if ( !m_ShadowAllocator.HasValidTexture( shadow.m_ShadowTexture ) )
  3048. return false;
  3049. // shadow to be redrawn; for now, we'll always do it.
  3050. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity );
  3051. if ( BuildSetupShadowHierarchy( pRenderable, shadow ) )
  3052. return true;
  3053. }
  3054. return false;
  3055. }
  3056. //-----------------------------------------------------------------------------
  3057. // This gets called with every shadow that potentially will need to re-render
  3058. //-----------------------------------------------------------------------------
  3059. bool CClientShadowMgr::DrawRenderToTextureShadow( unsigned short clientShadowHandle, float flArea )
  3060. {
  3061. ClientShadow_t& shadow = m_Shadows[clientShadowHandle];
  3062. // If we were previously using the LOD shadow, set the material
  3063. bool bPreviouslyUsingLODShadow = ( shadow.m_Flags & SHADOW_FLAGS_USING_LOD_SHADOW ) != 0;
  3064. shadow.m_Flags &= ~SHADOW_FLAGS_USING_LOD_SHADOW;
  3065. if ( bPreviouslyUsingLODShadow )
  3066. {
  3067. shadowmgr->SetShadowMaterial( shadow.m_ShadowHandle, m_RenderShadow, m_RenderModelShadow, (void*)(uintp)clientShadowHandle );
  3068. }
  3069. // Mark texture as being used...
  3070. bool bDirtyTexture = (shadow.m_Flags & SHADOW_FLAGS_TEXTURE_DIRTY) != 0;
  3071. bool bDrewTexture = false;
  3072. bool bNeedsRedraw = ( !m_bThreaded && m_ShadowAllocator.UseTexture( shadow.m_ShadowTexture, bDirtyTexture, flArea ) );
  3073. if ( !m_ShadowAllocator.HasValidTexture( shadow.m_ShadowTexture ) )
  3074. {
  3075. DrawRenderToTextureShadowLOD( clientShadowHandle );
  3076. return false;
  3077. }
  3078. if ( bNeedsRedraw || bDirtyTexture )
  3079. {
  3080. // shadow to be redrawn; for now, we'll always do it.
  3081. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity );
  3082. CMatRenderContextPtr pRenderContext( materials );
  3083. // Sets the viewport state
  3084. int x, y, w, h;
  3085. m_ShadowAllocator.GetTextureRect( shadow.m_ShadowTexture, x, y, w, h );
  3086. pRenderContext->Viewport( IsX360() ? 0 : x, IsX360() ? 0 : y, w, h );
  3087. // Clear the selected viewport only (don't need to clear depth)
  3088. pRenderContext->ClearBuffers( true, false );
  3089. pRenderContext->MatrixMode( MATERIAL_VIEW );
  3090. pRenderContext->LoadMatrix( shadowmgr->GetInfo( shadow.m_ShadowHandle ).m_WorldToShadow );
  3091. if ( DrawShadowHierarchy( pRenderable, shadow ) )
  3092. {
  3093. bDrewTexture = true;
  3094. if ( IsX360() )
  3095. {
  3096. // resolve render target to system memory texture
  3097. Rect_t srcRect = { 0, 0, w, h };
  3098. Rect_t dstRect = { x, y, w, h };
  3099. pRenderContext->CopyRenderTargetToTextureEx( m_ShadowAllocator.GetTexture(), 0, &srcRect, &dstRect );
  3100. }
  3101. }
  3102. else
  3103. {
  3104. // NOTE: Think the flags reset + texcoord set should only happen in DrawShadowHierarchy
  3105. // but it's 2 days before 360 ship.. not going to change this now.
  3106. DevMsg( "Didn't draw shadow hierarchy.. bad shadow texcoords probably going to happen..grab Brian!\n" );
  3107. }
  3108. // Only clear the dirty flag if the caster isn't animating
  3109. if ( (shadow.m_Flags & SHADOW_FLAGS_ANIMATING_SOURCE) == 0 )
  3110. {
  3111. shadow.m_Flags &= ~SHADOW_FLAGS_TEXTURE_DIRTY;
  3112. }
  3113. SetRenderToTextureShadowTexCoords( shadow.m_ShadowHandle, x, y, w, h );
  3114. }
  3115. else if ( bPreviouslyUsingLODShadow )
  3116. {
  3117. // In this case, we were previously using the LOD shadow, but we didn't
  3118. // have to reconstitute the texture. In this case, we need to reset the texcoord
  3119. int x, y, w, h;
  3120. m_ShadowAllocator.GetTextureRect( shadow.m_ShadowTexture, x, y, w, h );
  3121. SetRenderToTextureShadowTexCoords( shadow.m_ShadowHandle, x, y, w, h );
  3122. }
  3123. return bDrewTexture;
  3124. }
  3125. //-----------------------------------------------------------------------------
  3126. // "Draws" the shadow LOD, which really means just set up the blobby shadow
  3127. //-----------------------------------------------------------------------------
  3128. void CClientShadowMgr::DrawRenderToTextureShadowLOD( unsigned short clientShadowHandle )
  3129. {
  3130. ClientShadow_t &shadow = m_Shadows[clientShadowHandle];
  3131. if ( (shadow.m_Flags & SHADOW_FLAGS_USING_LOD_SHADOW) == 0 )
  3132. {
  3133. shadowmgr->SetShadowMaterial( shadow.m_ShadowHandle, m_SimpleShadow, m_SimpleShadow, (void*)CLIENTSHADOW_INVALID_HANDLE );
  3134. shadowmgr->SetShadowTexCoord( shadow.m_ShadowHandle, 0, 0, 1, 1 );
  3135. ClearExtraClipPlanes( clientShadowHandle ); // this was ClearExtraClipPlanes( shadow.m_ShadowHandle ), fix is from Joe Demers
  3136. shadow.m_Flags |= SHADOW_FLAGS_USING_LOD_SHADOW;
  3137. }
  3138. }
  3139. //-----------------------------------------------------------------------------
  3140. // Advances to the next frame,
  3141. //-----------------------------------------------------------------------------
  3142. void CClientShadowMgr::AdvanceFrame()
  3143. {
  3144. // We're starting the next frame
  3145. m_ShadowAllocator.AdvanceFrame();
  3146. }
  3147. //-----------------------------------------------------------------------------
  3148. // Re-render shadow depth textures that lie in the leaf list
  3149. //-----------------------------------------------------------------------------
  3150. int CClientShadowMgr::BuildActiveShadowDepthList( const CViewSetup &viewSetup, int nMaxDepthShadows, ClientShadowHandle_t *pActiveDepthShadows )
  3151. {
  3152. int nActiveDepthShadowCount = 0;
  3153. for ( ClientShadowHandle_t i = m_Shadows.Head(); i != m_Shadows.InvalidIndex(); i = m_Shadows.Next(i) )
  3154. {
  3155. ClientShadow_t& shadow = m_Shadows[i];
  3156. // If this is not a flashlight which should use a shadow depth texture, skip!
  3157. if ( ( shadow.m_Flags & SHADOW_FLAGS_USE_DEPTH_TEXTURE ) == 0 )
  3158. continue;
  3159. const FlashlightState_t& flashlightState = shadowmgr->GetFlashlightState( shadow.m_ShadowHandle );
  3160. // Bail if this flashlight doesn't want shadows
  3161. if ( !flashlightState.m_bEnableShadows )
  3162. continue;
  3163. // Calculate an AABB around the shadow frustum
  3164. Vector vecAbsMins, vecAbsMaxs;
  3165. CalculateAABBFromProjectionMatrix( shadow.m_WorldToShadow, &vecAbsMins, &vecAbsMaxs );
  3166. Frustum_t viewFrustum;
  3167. GeneratePerspectiveFrustum( viewSetup.origin, viewSetup.angles, viewSetup.zNear, viewSetup.zFar, viewSetup.fov, viewSetup.m_flAspectRatio, viewFrustum );
  3168. // FIXME: Could do other sorts of culling here, such as frustum-frustum test, distance etc.
  3169. // If it's not in the view frustum, move on
  3170. if ( R_CullBox( vecAbsMins, vecAbsMaxs, viewFrustum ) )
  3171. {
  3172. shadowmgr->SetFlashlightDepthTexture( shadow.m_ShadowHandle, NULL, 0 );
  3173. continue;
  3174. }
  3175. if ( nActiveDepthShadowCount >= nMaxDepthShadows )
  3176. {
  3177. static bool s_bOverflowWarning = false;
  3178. if ( !s_bOverflowWarning )
  3179. {
  3180. Warning( "Too many depth textures rendered in a single view!\n" );
  3181. Assert( 0 );
  3182. s_bOverflowWarning = true;
  3183. }
  3184. shadowmgr->SetFlashlightDepthTexture( shadow.m_ShadowHandle, NULL, 0 );
  3185. continue;
  3186. }
  3187. pActiveDepthShadows[nActiveDepthShadowCount++] = i;
  3188. }
  3189. return nActiveDepthShadowCount;
  3190. }
  3191. //-----------------------------------------------------------------------------
  3192. // Sets the view's active flashlight render state
  3193. //-----------------------------------------------------------------------------
  3194. void CClientShadowMgr::SetViewFlashlightState( int nActiveFlashlightCount, ClientShadowHandle_t* pActiveFlashlights )
  3195. {
  3196. // NOTE: On the 360, we render the entire scene with the flashlight state
  3197. // set and don't render flashlights additively in the shadow mgr at a far later time
  3198. // because the CPU costs are prohibitive
  3199. if ( !IsX360() && !r_flashlight_version2.GetInt() )
  3200. return;
  3201. Assert( nActiveFlashlightCount<= 1 );
  3202. if ( nActiveFlashlightCount > 0 )
  3203. {
  3204. Assert( ( m_Shadows[ pActiveFlashlights[0] ].m_Flags & SHADOW_FLAGS_FLASHLIGHT ) != 0 );
  3205. shadowmgr->SetFlashlightRenderState( pActiveFlashlights[0] );
  3206. }
  3207. else
  3208. {
  3209. shadowmgr->SetFlashlightRenderState( SHADOW_HANDLE_INVALID );
  3210. }
  3211. }
  3212. //-----------------------------------------------------------------------------
  3213. // Re-render shadow depth textures that lie in the leaf list
  3214. //-----------------------------------------------------------------------------
  3215. void CClientShadowMgr::ComputeShadowDepthTextures( const CViewSetup &viewSetup )
  3216. {
  3217. VPROF_BUDGET( "CClientShadowMgr::ComputeShadowDepthTextures", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  3218. CMatRenderContextPtr pRenderContext( materials );
  3219. PIXEVENT( pRenderContext, "Shadow Depth Textures" );
  3220. // Build list of active render-to-texture shadows
  3221. ClientShadowHandle_t pActiveDepthShadows[1024];
  3222. int nActiveDepthShadowCount = BuildActiveShadowDepthList( viewSetup, ARRAYSIZE( pActiveDepthShadows ), pActiveDepthShadows );
  3223. // Iterate over all existing textures and allocate shadow textures
  3224. bool bDebugFrustum = r_flashlightdrawfrustum.GetBool();
  3225. for ( int j = 0; j < nActiveDepthShadowCount; ++j )
  3226. {
  3227. ClientShadow_t& shadow = m_Shadows[ pActiveDepthShadows[j] ];
  3228. CTextureReference shadowDepthTexture;
  3229. bool bGotShadowDepthTexture = LockShadowDepthTexture( &shadowDepthTexture );
  3230. if ( !bGotShadowDepthTexture )
  3231. {
  3232. // If we don't get one, that means we have too many this frame so bind no depth texture
  3233. static int bitchCount = 0;
  3234. if( bitchCount < 10 )
  3235. {
  3236. Warning( "Too many shadow maps this frame!\n" );
  3237. bitchCount++;
  3238. }
  3239. Assert(0);
  3240. shadowmgr->SetFlashlightDepthTexture( shadow.m_ShadowHandle, NULL, 0 );
  3241. continue;
  3242. }
  3243. CViewSetup shadowView;
  3244. shadowView.m_flAspectRatio = 1.0f;
  3245. shadowView.x = shadowView.y = 0;
  3246. shadowView.width = shadowDepthTexture->GetActualWidth();
  3247. shadowView.height = shadowDepthTexture->GetActualHeight();
  3248. shadowView.m_bOrtho = false;
  3249. shadowView.m_bDoBloomAndToneMapping = false;
  3250. // Copy flashlight parameters
  3251. const FlashlightState_t& flashlightState = shadowmgr->GetFlashlightState( shadow.m_ShadowHandle );
  3252. shadowView.fov = shadowView.fovViewmodel = flashlightState.m_fHorizontalFOVDegrees;
  3253. shadowView.origin = flashlightState.m_vecLightOrigin;
  3254. QuaternionAngles( flashlightState.m_quatOrientation, shadowView.angles ); // Convert from Quaternion to QAngle
  3255. shadowView.zNear = shadowView.zNearViewmodel = flashlightState.m_NearZ;
  3256. shadowView.zFar = shadowView.zFarViewmodel = flashlightState.m_FarZ;
  3257. // Can turn on all light frustum overlays or per light with flashlightState parameter...
  3258. if ( bDebugFrustum || flashlightState.m_bDrawShadowFrustum )
  3259. {
  3260. DebugDrawFrustum( shadowView.origin, shadow.m_WorldToShadow );
  3261. }
  3262. // Set depth bias factors specific to this flashlight
  3263. CMatRenderContextPtr pRenderContextMat( materials );
  3264. pRenderContextMat->SetShadowDepthBiasFactors( flashlightState.m_flShadowSlopeScaleDepthBias, flashlightState.m_flShadowDepthBias );
  3265. // Render to the shadow depth texture with appropriate view
  3266. view->UpdateShadowDepthTexture( m_DummyColorTexture, shadowDepthTexture, shadowView );
  3267. // Associate the shadow depth texture and stencil bit with the flashlight for use during scene rendering
  3268. shadowmgr->SetFlashlightDepthTexture( shadow.m_ShadowHandle, shadowDepthTexture, 0 );
  3269. }
  3270. SetViewFlashlightState( nActiveDepthShadowCount, pActiveDepthShadows );
  3271. }
  3272. //-----------------------------------------------------------------------------
  3273. // Re-renders all shadow textures for shadow casters that lie in the leaf list
  3274. //-----------------------------------------------------------------------------
  3275. static void SetupBonesOnBaseAnimating( C_BaseAnimating *&pBaseAnimating )
  3276. {
  3277. pBaseAnimating->SetupBones( NULL, -1, -1, gpGlobals->curtime );
  3278. }
  3279. void CClientShadowMgr::ComputeShadowTextures( const CViewSetup &viewShadow, int leafCount, LeafIndex_t* pLeafList )
  3280. {
  3281. VPROF_BUDGET( "CClientShadowMgr::ComputeShadowTextures", VPROF_BUDGETGROUP_SHADOW_RENDERING );
  3282. if ( !m_RenderToTextureActive || (r_shadows.GetInt() == 0) || r_shadows_gamecontrol.GetInt() == 0 )
  3283. return;
  3284. m_bThreaded = false;//( r_threaded_client_shadow_manager.GetBool() && g_pThreadPool->NumIdleThreads() );
  3285. MDLCACHE_CRITICAL_SECTION();
  3286. // First grab all shadow textures we may want to render
  3287. int nCount = s_VisibleShadowList.FindShadows( &viewShadow, leafCount, pLeafList );
  3288. if ( nCount == 0 )
  3289. return;
  3290. // FIXME: Add heuristics based on distance, etc. to futz with
  3291. // the shadow allocator + to select blobby shadows
  3292. CMatRenderContextPtr pRenderContext( materials );
  3293. PIXEVENT( pRenderContext, "Render-To-Texture Shadows" );
  3294. // Clear to white (color unused), black alpha
  3295. pRenderContext->ClearColor4ub( 255, 255, 255, 0 );
  3296. // No height clip mode please.
  3297. MaterialHeightClipMode_t oldHeightClipMode = pRenderContext->GetHeightClipMode();
  3298. pRenderContext->SetHeightClipMode( MATERIAL_HEIGHTCLIPMODE_DISABLE );
  3299. // No projection matrix (orthographic mode)
  3300. // FIXME: Make it work for projective shadows?
  3301. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  3302. pRenderContext->PushMatrix();
  3303. pRenderContext->LoadIdentity();
  3304. pRenderContext->Scale( 1, -1, 1 );
  3305. pRenderContext->Ortho( 0, 0, 1, 1, -9999, 0 );
  3306. pRenderContext->MatrixMode( MATERIAL_VIEW );
  3307. pRenderContext->PushMatrix();
  3308. pRenderContext->PushRenderTargetAndViewport( m_ShadowAllocator.GetTexture() );
  3309. if ( !IsX360() && m_bRenderTargetNeedsClear )
  3310. {
  3311. // don't need to clear absent depth buffer
  3312. pRenderContext->ClearBuffers( true, false );
  3313. m_bRenderTargetNeedsClear = false;
  3314. }
  3315. int nMaxShadows = r_shadowmaxrendered.GetInt();
  3316. int nModelsRendered = 0;
  3317. int i;
  3318. if ( m_bThreaded && g_pThreadPool->NumIdleThreads() )
  3319. {
  3320. s_NPCShadowBoneSetups.RemoveAll();
  3321. s_NonNPCShadowBoneSetups.RemoveAll();
  3322. for (i = 0; i < nCount; ++i)
  3323. {
  3324. const VisibleShadowInfo_t &info = s_VisibleShadowList.GetVisibleShadow(i);
  3325. if ( nModelsRendered < nMaxShadows )
  3326. {
  3327. if ( BuildSetupListForRenderToTextureShadow( info.m_hShadow, info.m_flArea ) )
  3328. {
  3329. ++nModelsRendered;
  3330. }
  3331. }
  3332. }
  3333. ParallelProcess( "NPCShadowBoneSetups", s_NPCShadowBoneSetups.Base(), s_NPCShadowBoneSetups.Count(), &SetupBonesOnBaseAnimating );
  3334. ParallelProcess( "NonNPCShadowBoneSetups", s_NonNPCShadowBoneSetups.Base(), s_NonNPCShadowBoneSetups.Count(), &SetupBonesOnBaseAnimating );
  3335. nModelsRendered = 0;
  3336. }
  3337. for (i = 0; i < nCount; ++i)
  3338. {
  3339. const VisibleShadowInfo_t &info = s_VisibleShadowList.GetVisibleShadow(i);
  3340. if ( nModelsRendered < nMaxShadows )
  3341. {
  3342. if ( DrawRenderToTextureShadow( info.m_hShadow, info.m_flArea ) )
  3343. {
  3344. ++nModelsRendered;
  3345. }
  3346. }
  3347. else
  3348. {
  3349. DrawRenderToTextureShadowLOD( info.m_hShadow );
  3350. }
  3351. }
  3352. // Render to the backbuffer again
  3353. pRenderContext->PopRenderTargetAndViewport();
  3354. // Restore the matrices
  3355. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  3356. pRenderContext->PopMatrix();
  3357. pRenderContext->MatrixMode( MATERIAL_VIEW );
  3358. pRenderContext->PopMatrix();
  3359. pRenderContext->SetHeightClipMode( oldHeightClipMode );
  3360. pRenderContext->SetHeightClipMode( oldHeightClipMode );
  3361. // Restore the clear color
  3362. pRenderContext->ClearColor3ub( 0, 0, 0 );
  3363. }
  3364. //-------------------------------------------------------------------------------------------------------
  3365. // Lock down the usage of a shadow depth texture...must be unlocked for use on subsequent views / frames
  3366. //-------------------------------------------------------------------------------------------------------
  3367. bool CClientShadowMgr::LockShadowDepthTexture( CTextureReference *shadowDepthTexture )
  3368. {
  3369. for ( int i=0; i < m_DepthTextureCache.Count(); i++ ) // Search for cached shadow depth texture
  3370. {
  3371. if ( m_DepthTextureCacheLocks[i] == false ) // If a free one is found
  3372. {
  3373. *shadowDepthTexture = m_DepthTextureCache[i];
  3374. m_DepthTextureCacheLocks[i] = true;
  3375. return true;
  3376. }
  3377. }
  3378. return false; // Didn't find it...
  3379. }
  3380. //------------------------------------------------------------------
  3381. // Unlock shadow depth texture for use on subsequent views / frames
  3382. //------------------------------------------------------------------
  3383. void CClientShadowMgr::UnlockAllShadowDepthTextures()
  3384. {
  3385. for (int i=0; i< m_DepthTextureCache.Count(); i++ )
  3386. {
  3387. m_DepthTextureCacheLocks[i] = false;
  3388. }
  3389. SetViewFlashlightState( 0, NULL );
  3390. }
  3391. void CClientShadowMgr::SetFlashlightTarget( ClientShadowHandle_t shadowHandle, EHANDLE targetEntity )
  3392. {
  3393. Assert( m_Shadows.IsValidIndex( shadowHandle ) );
  3394. CClientShadowMgr::ClientShadow_t &shadow = m_Shadows[ shadowHandle ];
  3395. if( ( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) == 0 )
  3396. return;
  3397. // shadow.m_pTargetRenderable = pRenderable;
  3398. shadow.m_hTargetEntity = targetEntity;
  3399. }
  3400. void CClientShadowMgr::SetFlashlightLightWorld( ClientShadowHandle_t shadowHandle, bool bLightWorld )
  3401. {
  3402. Assert( m_Shadows.IsValidIndex( shadowHandle ) );
  3403. ClientShadow_t &shadow = m_Shadows[ shadowHandle ];
  3404. if( ( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) == 0 )
  3405. return;
  3406. if ( bLightWorld )
  3407. {
  3408. shadow.m_Flags |= SHADOW_FLAGS_LIGHT_WORLD;
  3409. }
  3410. else
  3411. {
  3412. shadow.m_Flags &= ~SHADOW_FLAGS_LIGHT_WORLD;
  3413. }
  3414. }
  3415. bool CClientShadowMgr::IsFlashlightTarget( ClientShadowHandle_t shadowHandle, IClientRenderable *pRenderable )
  3416. {
  3417. ClientShadow_t &shadow = m_Shadows[ shadowHandle ];
  3418. if( shadow.m_hTargetEntity->GetClientRenderable() == pRenderable )
  3419. return true;
  3420. C_BaseEntity *pChild = shadow.m_hTargetEntity->FirstMoveChild();
  3421. while( pChild )
  3422. {
  3423. if( pChild->GetClientRenderable()==pRenderable )
  3424. return true;
  3425. pChild = pChild->NextMovePeer();
  3426. }
  3427. return false;
  3428. }
  3429. //-----------------------------------------------------------------------------
  3430. // A material proxy that resets the base texture to use the rendered shadow
  3431. //-----------------------------------------------------------------------------
  3432. class CShadowProxy : public IMaterialProxy
  3433. {
  3434. public:
  3435. CShadowProxy();
  3436. virtual ~CShadowProxy();
  3437. virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
  3438. virtual void OnBind( void *pProxyData );
  3439. virtual void Release( void ) { delete this; }
  3440. virtual IMaterial *GetMaterial();
  3441. private:
  3442. IMaterialVar* m_BaseTextureVar;
  3443. };
  3444. CShadowProxy::CShadowProxy()
  3445. {
  3446. m_BaseTextureVar = NULL;
  3447. }
  3448. CShadowProxy::~CShadowProxy()
  3449. {
  3450. }
  3451. bool CShadowProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
  3452. {
  3453. bool foundVar;
  3454. m_BaseTextureVar = pMaterial->FindVar( "$basetexture", &foundVar, false );
  3455. return foundVar;
  3456. }
  3457. void CShadowProxy::OnBind( void *pProxyData )
  3458. {
  3459. unsigned short clientShadowHandle = ( unsigned short )(int)pProxyData&0xffff;
  3460. ITexture* pTex = s_ClientShadowMgr.GetShadowTexture( clientShadowHandle );
  3461. m_BaseTextureVar->SetTextureValue( pTex );
  3462. if ( ToolsEnabled() )
  3463. {
  3464. ToolFramework_RecordMaterialParams( GetMaterial() );
  3465. }
  3466. }
  3467. IMaterial *CShadowProxy::GetMaterial()
  3468. {
  3469. return m_BaseTextureVar->GetOwningMaterial();
  3470. }
  3471. EXPOSE_INTERFACE( CShadowProxy, IMaterialProxy, "Shadow" IMATERIAL_PROXY_INTERFACE_VERSION );
  3472. //-----------------------------------------------------------------------------
  3473. // A material proxy that resets the base texture to use the rendered shadow
  3474. //-----------------------------------------------------------------------------
  3475. class CShadowModelProxy : public IMaterialProxy
  3476. {
  3477. public:
  3478. CShadowModelProxy();
  3479. virtual ~CShadowModelProxy();
  3480. virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
  3481. virtual void OnBind( void *pProxyData );
  3482. virtual void Release( void ) { delete this; }
  3483. virtual IMaterial *GetMaterial();
  3484. private:
  3485. IMaterialVar* m_BaseTextureVar;
  3486. IMaterialVar* m_BaseTextureOffsetVar;
  3487. IMaterialVar* m_BaseTextureScaleVar;
  3488. IMaterialVar* m_BaseTextureMatrixVar;
  3489. IMaterialVar* m_FalloffOffsetVar;
  3490. IMaterialVar* m_FalloffDistanceVar;
  3491. IMaterialVar* m_FalloffAmountVar;
  3492. };
  3493. CShadowModelProxy::CShadowModelProxy()
  3494. {
  3495. m_BaseTextureVar = NULL;
  3496. m_BaseTextureOffsetVar = NULL;
  3497. m_BaseTextureScaleVar = NULL;
  3498. m_BaseTextureMatrixVar = NULL;
  3499. m_FalloffOffsetVar = NULL;
  3500. m_FalloffDistanceVar = NULL;
  3501. m_FalloffAmountVar = NULL;
  3502. }
  3503. CShadowModelProxy::~CShadowModelProxy()
  3504. {
  3505. }
  3506. bool CShadowModelProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
  3507. {
  3508. bool foundVar;
  3509. m_BaseTextureVar = pMaterial->FindVar( "$basetexture", &foundVar, false );
  3510. if (!foundVar)
  3511. return false;
  3512. m_BaseTextureOffsetVar = pMaterial->FindVar( "$basetextureoffset", &foundVar, false );
  3513. if (!foundVar)
  3514. return false;
  3515. m_BaseTextureScaleVar = pMaterial->FindVar( "$basetexturescale", &foundVar, false );
  3516. if (!foundVar)
  3517. return false;
  3518. m_BaseTextureMatrixVar = pMaterial->FindVar( "$basetexturetransform", &foundVar, false );
  3519. if (!foundVar)
  3520. return false;
  3521. m_FalloffOffsetVar = pMaterial->FindVar( "$falloffoffset", &foundVar, false );
  3522. if (!foundVar)
  3523. return false;
  3524. m_FalloffDistanceVar = pMaterial->FindVar( "$falloffdistance", &foundVar, false );
  3525. if (!foundVar)
  3526. return false;
  3527. m_FalloffAmountVar = pMaterial->FindVar( "$falloffamount", &foundVar, false );
  3528. return foundVar;
  3529. }
  3530. void CShadowModelProxy::OnBind( void *pProxyData )
  3531. {
  3532. unsigned short clientShadowHandle = ( unsigned short )((int)pProxyData&0xffff);
  3533. ITexture* pTex = s_ClientShadowMgr.GetShadowTexture( clientShadowHandle );
  3534. m_BaseTextureVar->SetTextureValue( pTex );
  3535. const ShadowInfo_t& info = s_ClientShadowMgr.GetShadowInfo( clientShadowHandle );
  3536. m_BaseTextureMatrixVar->SetMatrixValue( info.m_WorldToShadow );
  3537. m_BaseTextureOffsetVar->SetVecValue( info.m_TexOrigin.Base(), 2 );
  3538. m_BaseTextureScaleVar->SetVecValue( info.m_TexSize.Base(), 2 );
  3539. m_FalloffOffsetVar->SetFloatValue( info.m_FalloffOffset );
  3540. m_FalloffDistanceVar->SetFloatValue( info.m_MaxDist );
  3541. m_FalloffAmountVar->SetFloatValue( info.m_FalloffAmount );
  3542. if ( ToolsEnabled() )
  3543. {
  3544. ToolFramework_RecordMaterialParams( GetMaterial() );
  3545. }
  3546. }
  3547. IMaterial *CShadowModelProxy::GetMaterial()
  3548. {
  3549. return m_BaseTextureVar->GetOwningMaterial();
  3550. }
  3551. EXPOSE_INTERFACE( CShadowModelProxy, IMaterialProxy, "ShadowModel" IMATERIAL_PROXY_INTERFACE_VERSION );