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

584 lines
15 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "view.h"
  9. #include "iviewrender.h"
  10. #include "c_sun.h"
  11. #include "particles_simple.h"
  12. #include "precache_register.h"
  13. #include "c_pixel_visibility.h"
  14. #include "glow_overlay.h"
  15. #include "utllinkedlist.h"
  16. #include "view_shared.h"
  17. #include "tier0/vprof.h"
  18. #include "materialsystem/imaterialvar.h"
  19. // memdbgon must be the last include file in a .cpp file!!!
  20. #include "tier0/memdbgon.h"
  21. PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheEffectGlow )
  22. PRECACHE( MATERIAL, "sun/overlay" )
  23. PRECACHE( MATERIAL, "sprites/light_glow02_add_noz" )
  24. PRECACHE_REGISTER_END()
  25. class CGlowOverlaySystem : public CAutoGameSystem
  26. {
  27. public:
  28. CGlowOverlaySystem() : CAutoGameSystem( "CGlowOverlaySystem" )
  29. {
  30. }
  31. // Level init, shutdown
  32. virtual void LevelInitPreEntity() {}
  33. virtual void LevelShutdownPostEntity()
  34. {
  35. m_GlowOverlays.PurgeAndDeleteElements();
  36. }
  37. unsigned short AddToOverlayList( CGlowOverlay *pGlow )
  38. {
  39. return m_GlowOverlays.AddToTail( pGlow );
  40. }
  41. void RemoveFromOverlayList( unsigned short handle )
  42. {
  43. if( handle != m_GlowOverlays.InvalidIndex() )
  44. {
  45. m_GlowOverlays.Remove( handle );
  46. }
  47. }
  48. CUtlLinkedList<CGlowOverlay*, unsigned short> m_GlowOverlays;
  49. };
  50. CGlowOverlaySystem g_GlowOverlaySystem;
  51. ConVar cl_ShowSunVectors( "cl_ShowSunVectors", "0", 0 );
  52. ConVar cl_sun_decay_rate( "cl_sun_decay_rate", "0.05", FCVAR_CHEAT );
  53. // Dot product space the overlays are drawn in.
  54. // Here it's setup to allow you to see it if you're looking within 40 degrees of the source.
  55. float g_flOverlayRange = cos( DEG2RAD( 40 ) );
  56. // ----------------------------------------------------------------------------- //
  57. // ----------------------------------------------------------------------------- //
  58. void Do2DRotation( Vector vIn, Vector &vOut, float flDegrees, int i1, int i2, int i3 )
  59. {
  60. float c, s;
  61. SinCos( DEG2RAD( flDegrees ), &s, &c );
  62. vOut[i1] = vIn[i1]*c - vIn[i2]*s;
  63. vOut[i2] = vIn[i1]*s + vIn[i2]*c;
  64. vOut[i3] = vIn[i3];
  65. }
  66. // ----------------------------------------------------------------------------- //
  67. // ----------------------------------------------------------------------------- //
  68. CGlowOverlay::CGlowOverlay()
  69. {
  70. m_ListIndex = 0xFFFF;
  71. m_nSprites = 0;
  72. m_flGlowObstructionScale = 0.0f;
  73. m_bDirectional = false;
  74. m_bInSky = false;
  75. m_skyObstructionScale = 1.0f;
  76. m_bActivated = false;
  77. m_flProxyRadius = 2.0f;
  78. m_queryHandle = 0;
  79. m_flHDRColorScale = 1.0f;
  80. //Init our sprites
  81. for ( int i = 0; i < MAX_SUN_LAYERS; i++ )
  82. {
  83. m_Sprites[i].m_vColor.Init();
  84. m_Sprites[i].m_flHorzSize = 1.0f;
  85. m_Sprites[i].m_flVertSize = 1.0f;
  86. m_Sprites[i].m_pMaterial = NULL;
  87. }
  88. #ifdef PORTAL
  89. for( int i = 0; i != MAX_PORTAL_RECURSIVE_VIEWS; ++i )
  90. {
  91. m_skyObstructionScaleBackups[i] = 1.0f;
  92. }
  93. #endif
  94. }
  95. CGlowOverlay::~CGlowOverlay()
  96. {
  97. g_GlowOverlaySystem.RemoveFromOverlayList( m_ListIndex );
  98. }
  99. bool CGlowOverlay::Update()
  100. {
  101. return true;
  102. }
  103. void BuildingCubemapsChanged( IConVar *var, const char *pOldValue, float flOldValue )
  104. {
  105. C_BaseEntity::UpdateVisibilityAllEntities();
  106. }
  107. ConVar building_cubemaps( "building_cubemaps", "0", FCVAR_CHEAT, "Indicates we're building cubemaps", BuildingCubemapsChanged );
  108. float CGlowOverlay::CalcGlowAspect()
  109. {
  110. if ( m_nSprites )
  111. {
  112. if ( m_Sprites[0].m_flHorzSize != 0 && m_Sprites[0].m_flVertSize != 0 )
  113. return m_Sprites[0].m_flHorzSize / m_Sprites[0].m_flVertSize;
  114. }
  115. return 1.0f;
  116. }
  117. void CGlowOverlay::UpdateSkyGlowObstruction( float zFar, bool bCacheFullSceneState )
  118. {
  119. Assert( m_bInSky );
  120. // If we already cached the sky obstruction and are still using that, early-out
  121. if ( bCacheFullSceneState && m_bCacheSkyObstruction )
  122. return;
  123. // Turning on sky obstruction caching mode
  124. if ( bCacheFullSceneState && !m_bCacheSkyObstruction )
  125. {
  126. m_bCacheSkyObstruction = true;
  127. }
  128. // Turning off sky obstruction caching mode
  129. if ( !bCacheFullSceneState && m_bCacheSkyObstruction )
  130. {
  131. m_bCacheSkyObstruction = false;
  132. }
  133. if ( PixelVisibility_IsAvailable() )
  134. {
  135. // Trace a ray at the object.
  136. Vector pos = CurrentViewOrigin() + m_vDirection * zFar * 0.99f;
  137. // UNDONE: Can probably do only the pixelvis query in this case if you can figure out where
  138. // to put it - or save the position of this trace
  139. pixelvis_queryparams_t params;
  140. params.Init( pos, m_flProxyRadius );
  141. params.bSizeInScreenspace = true;
  142. m_skyObstructionScale = PixelVisibility_FractionVisible( params, &m_queryHandle );
  143. return;
  144. }
  145. // Trace a ray at the object.
  146. trace_t trace;
  147. UTIL_TraceLine( CurrentViewOrigin(), CurrentViewOrigin() + (m_vDirection*MAX_TRACE_LENGTH),
  148. CONTENTS_SOLID, NULL, COLLISION_GROUP_NONE, &trace );
  149. // back the trace with a pixel query to occlude with models
  150. if ( trace.surface.flags & SURF_SKY )
  151. {
  152. m_skyObstructionScale = 1.0f;
  153. }
  154. else
  155. {
  156. m_skyObstructionScale = 0.0f;
  157. }
  158. }
  159. void CGlowOverlay::UpdateGlowObstruction( const Vector &vToGlow, bool bCacheFullSceneState )
  160. {
  161. // If we already cached the glow obstruction and are still using that, early-out
  162. if ( bCacheFullSceneState && m_bCacheGlowObstruction )
  163. return;
  164. if ( bCacheFullSceneState && !m_bCacheGlowObstruction ) // If turning on sky obstruction caching mode
  165. {
  166. m_bCacheGlowObstruction = true;
  167. }
  168. if ( !bCacheFullSceneState && m_bCacheGlowObstruction )
  169. {
  170. m_bCacheGlowObstruction = false;
  171. }
  172. if ( PixelVisibility_IsAvailable() )
  173. {
  174. if ( m_bInSky )
  175. {
  176. const CViewSetup *pViewSetup = view->GetViewSetup();
  177. Vector pos = CurrentViewOrigin() + m_vDirection * (pViewSetup->zFar * 0.999f);
  178. pixelvis_queryparams_t params;
  179. params.Init( pos, m_flProxyRadius, CalcGlowAspect() );
  180. params.bSizeInScreenspace = true;
  181. // use a pixel query to occlude with models
  182. m_flGlowObstructionScale = PixelVisibility_FractionVisible( params, &m_queryHandle ) * m_skyObstructionScale;
  183. }
  184. else
  185. {
  186. // If it's not in the sky, then we need a valid position or else we don't
  187. // know what's in front of it.
  188. Assert( !m_bDirectional );
  189. pixelvis_queryparams_t params;
  190. params.Init( m_vPos, m_flProxyRadius, CalcGlowAspect() );
  191. m_flGlowObstructionScale = PixelVisibility_FractionVisible( params, &m_queryHandle );
  192. }
  193. return;
  194. }
  195. bool bFade = false;
  196. if ( m_bInSky )
  197. {
  198. // Trace a ray at the object.
  199. trace_t trace;
  200. UTIL_TraceLine( CurrentViewOrigin(), CurrentViewOrigin() + (vToGlow*MAX_TRACE_LENGTH),
  201. CONTENTS_SOLID, NULL, COLLISION_GROUP_NONE, &trace );
  202. bFade = (trace.fraction < 1 && !(trace.surface.flags & SURF_SKY));
  203. }
  204. else
  205. {
  206. // If it's not in the sky, then we need a valid position or else we don't
  207. // know what's in front of it.
  208. Assert( !m_bDirectional );
  209. pixelvis_queryparams_t params;
  210. params.Init( m_vPos, m_flProxyRadius );
  211. bFade = PixelVisibility_FractionVisible( params, &m_queryHandle ) < 1.0f ? true : false;
  212. }
  213. if ( bFade )
  214. {
  215. if ( building_cubemaps.GetBool() )
  216. {
  217. m_flGlowObstructionScale = 0.0f;
  218. }
  219. else
  220. {
  221. m_flGlowObstructionScale -= gpGlobals->frametime / cl_sun_decay_rate.GetFloat();
  222. m_flGlowObstructionScale = MAX( m_flGlowObstructionScale, 0.0f );
  223. }
  224. }
  225. else
  226. {
  227. if ( building_cubemaps.GetBool() )
  228. {
  229. m_flGlowObstructionScale = 1.0f;
  230. }
  231. else
  232. {
  233. m_flGlowObstructionScale += gpGlobals->frametime / cl_sun_decay_rate.GetFloat();
  234. m_flGlowObstructionScale = MIN( m_flGlowObstructionScale, 1.0f );
  235. }
  236. }
  237. }
  238. void CGlowOverlay::CalcSpriteColorAndSize(
  239. float flDot,
  240. CGlowSprite *pSprite,
  241. float *flHorzSize,
  242. float *flVertSize,
  243. Vector *vColor )
  244. {
  245. // The overlay is largest and completely translucent at g_flOverlayRange.
  246. // When the dot product is 1, then it's smaller and more opaque.
  247. const float flSizeAtOverlayRangeMul = 150;
  248. const float flSizeAtOneMul = 70;
  249. const float flOpacityAtOverlayRange = 0;
  250. const float flOpacityAtOne = 1;
  251. // Figure out how big and how opaque it will be.
  252. *flHorzSize = RemapValClamped(
  253. flDot,
  254. g_flOverlayRange,
  255. 1,
  256. flSizeAtOverlayRangeMul * pSprite->m_flHorzSize,
  257. flSizeAtOneMul * pSprite->m_flHorzSize );
  258. *flVertSize = RemapValClamped(
  259. flDot,
  260. g_flOverlayRange,
  261. 1,
  262. flSizeAtOverlayRangeMul * pSprite->m_flVertSize,
  263. flSizeAtOneMul * pSprite->m_flVertSize );
  264. float flOpacity = RemapValClamped(
  265. flDot,
  266. g_flOverlayRange,
  267. 1,
  268. flOpacityAtOverlayRange,
  269. flOpacityAtOne );
  270. flOpacity = flOpacity * m_flGlowObstructionScale;
  271. *vColor = pSprite->m_vColor * flOpacity;
  272. }
  273. void CGlowOverlay::CalcBasis(
  274. const Vector &vToGlow,
  275. float flHorzSize,
  276. float flVertSize,
  277. Vector &vBasePt,
  278. Vector &vUp,
  279. Vector &vRight )
  280. {
  281. const float flOverlayDist = 100;
  282. vBasePt = CurrentViewOrigin() + vToGlow * flOverlayDist;
  283. vUp.Init( 0, 0, 1 );
  284. vRight = vToGlow.Cross( vUp );
  285. VectorNormalize( vRight );
  286. vUp = vRight.Cross( vToGlow );
  287. VectorNormalize( vUp );
  288. vRight *= flHorzSize;
  289. vUp *= flVertSize;
  290. }
  291. void CGlowOverlay::Draw( bool bCacheFullSceneState )
  292. {
  293. extern ConVar r_drawsprites;
  294. if( !r_drawsprites.GetBool() )
  295. return;
  296. // Get the vector to the sun.
  297. Vector vToGlow;
  298. if( m_bDirectional )
  299. vToGlow = m_vDirection;
  300. else
  301. vToGlow = m_vPos - CurrentViewOrigin();
  302. VectorNormalize( vToGlow );
  303. float flDot = vToGlow.Dot( CurrentViewForward() );
  304. UpdateGlowObstruction( vToGlow, bCacheFullSceneState );
  305. if( m_flGlowObstructionScale == 0 )
  306. return;
  307. bool bWireframe = ShouldDrawInWireFrameMode() || (r_drawsprites.GetInt() == 2);
  308. CMatRenderContextPtr pRenderContext( materials );
  309. for( int iSprite=0; iSprite < m_nSprites; iSprite++ )
  310. {
  311. CGlowSprite *pSprite = &m_Sprites[iSprite];
  312. // Figure out the color and size to draw it.
  313. float flHorzSize, flVertSize;
  314. Vector vColor;
  315. CalcSpriteColorAndSize( flDot, pSprite, &flHorzSize, &flVertSize, &vColor );
  316. // If we're alpha'd out, then don't bother
  317. if ( vColor.LengthSqr() < 0.00001f )
  318. continue;
  319. // Setup the basis to draw the sprite.
  320. Vector vBasePt, vUp, vRight;
  321. CalcBasis( vToGlow, flHorzSize, flVertSize, vBasePt, vUp, vRight );
  322. //Get our diagonal radius
  323. float radius = (vRight+vUp).Length();
  324. if ( R_CullSphere( view->GetFrustum(), 5, &vBasePt, radius ) )
  325. continue;
  326. // Get our material (deferred default load)
  327. if ( m_Sprites[iSprite].m_pMaterial == NULL )
  328. {
  329. m_Sprites[iSprite].m_pMaterial = materials->FindMaterial( "sprites/light_glow02_add_noz", TEXTURE_GROUP_CLIENT_EFFECTS );
  330. }
  331. Assert( m_Sprites[iSprite].m_pMaterial );
  332. static unsigned int nHDRColorScaleCache = 0;
  333. IMaterialVar *pHDRColorScaleVar = m_Sprites[iSprite].m_pMaterial->FindVarFast( "$hdrcolorscale", &nHDRColorScaleCache );
  334. if( pHDRColorScaleVar )
  335. {
  336. pHDRColorScaleVar->SetFloatValue( m_flHDRColorScale );
  337. }
  338. // Draw the sprite.
  339. IMesh *pMesh = pRenderContext->GetDynamicMesh( false, 0, 0, m_Sprites[iSprite].m_pMaterial );
  340. CMeshBuilder builder;
  341. builder.Begin( pMesh, MATERIAL_QUADS, 1 );
  342. Vector vPt;
  343. vPt = vBasePt - vRight + vUp;
  344. builder.Position3fv( vPt.Base() );
  345. builder.Color4f( VectorExpand(vColor), 1 );
  346. builder.TexCoord2f( 0, 0, 1 );
  347. builder.AdvanceVertex();
  348. vPt = vBasePt + vRight + vUp;
  349. builder.Position3fv( vPt.Base() );
  350. builder.Color4f( VectorExpand(vColor), 1 );
  351. builder.TexCoord2f( 0, 1, 1 );
  352. builder.AdvanceVertex();
  353. vPt = vBasePt + vRight - vUp;
  354. builder.Position3fv( vPt.Base() );
  355. builder.Color4f( VectorExpand(vColor), 1 );
  356. builder.TexCoord2f( 0, 1, 0 );
  357. builder.AdvanceVertex();
  358. vPt = vBasePt - vRight - vUp;
  359. builder.Position3fv( vPt.Base() );
  360. builder.Color4f( VectorExpand(vColor), 1 );
  361. builder.TexCoord2f( 0, 0, 0 );
  362. builder.AdvanceVertex();
  363. builder.End( false, true );
  364. if( bWireframe )
  365. {
  366. IMaterial *pWireframeMaterial = materials->FindMaterial( "debug/debugwireframevertexcolor", TEXTURE_GROUP_OTHER );
  367. pRenderContext->Bind( pWireframeMaterial );
  368. // Draw the sprite.
  369. IMesh *pMesh = pRenderContext->GetDynamicMesh( false, 0, 0, pWireframeMaterial );
  370. CMeshBuilder builder;
  371. builder.Begin( pMesh, MATERIAL_QUADS, 1 );
  372. Vector vPt;
  373. vPt = vBasePt - vRight + vUp;
  374. builder.Position3fv( vPt.Base() );
  375. builder.Color3f( 1.0f, 0.0f, 0.0f );
  376. builder.AdvanceVertex();
  377. vPt = vBasePt + vRight + vUp;
  378. builder.Position3fv( vPt.Base() );
  379. builder.Color3f( 1.0f, 0.0f, 0.0f );
  380. builder.AdvanceVertex();
  381. vPt = vBasePt + vRight - vUp;
  382. builder.Position3fv( vPt.Base() );
  383. builder.Color3f( 1.0f, 0.0f, 0.0f );
  384. builder.AdvanceVertex();
  385. vPt = vBasePt - vRight - vUp;
  386. builder.Position3fv( vPt.Base() );
  387. builder.Color3f( 1.0f, 0.0f, 0.0f );
  388. builder.AdvanceVertex();
  389. builder.End( false, true );
  390. }
  391. }
  392. }
  393. void CGlowOverlay::Activate()
  394. {
  395. m_bActivated = true;
  396. if( m_ListIndex == 0xFFFF )
  397. {
  398. m_ListIndex = g_GlowOverlaySystem.AddToOverlayList( this );
  399. }
  400. }
  401. void CGlowOverlay::Deactivate()
  402. {
  403. m_bActivated = false;
  404. }
  405. void CGlowOverlay::DrawOverlays( bool bCacheFullSceneState )
  406. {
  407. VPROF("CGlowOverlay::DrawOverlays()");
  408. CMatRenderContextPtr pRenderContext( materials );
  409. bool bClippingEnabled = pRenderContext->EnableClipping( true );
  410. unsigned short iNext;
  411. for( unsigned short i=g_GlowOverlaySystem.m_GlowOverlays.Head(); i != g_GlowOverlaySystem.m_GlowOverlays.InvalidIndex(); i = iNext )
  412. {
  413. iNext = g_GlowOverlaySystem.m_GlowOverlays.Next( i );
  414. CGlowOverlay *pOverlay = g_GlowOverlaySystem.m_GlowOverlays[i];
  415. if( !pOverlay->m_bActivated )
  416. continue;
  417. if( pOverlay->Update() )
  418. {
  419. pRenderContext->EnableClipping( ((pOverlay->m_bInSky) ? (false):(bClippingEnabled)) ); //disable clipping in skybox, restore clipping to pre-existing state when not in skybox (it may be off as well)
  420. pOverlay->Draw( bCacheFullSceneState );
  421. }
  422. else
  423. {
  424. delete pOverlay;
  425. }
  426. }
  427. pRenderContext->EnableClipping( bClippingEnabled ); //restore clipping to original state
  428. }
  429. void CGlowOverlay::UpdateSkyOverlays( float zFar, bool bCacheFullSceneState )
  430. {
  431. unsigned short iNext;
  432. for( unsigned short i=g_GlowOverlaySystem.m_GlowOverlays.Head(); i != g_GlowOverlaySystem.m_GlowOverlays.InvalidIndex(); i = iNext )
  433. {
  434. iNext = g_GlowOverlaySystem.m_GlowOverlays.Next( i );
  435. CGlowOverlay *pOverlay = g_GlowOverlaySystem.m_GlowOverlays[i];
  436. if( !pOverlay->m_bActivated || !pOverlay->m_bDirectional || !pOverlay->m_bInSky )
  437. continue;
  438. pOverlay->UpdateSkyGlowObstruction( zFar, bCacheFullSceneState );
  439. }
  440. }
  441. #ifdef PORTAL
  442. void CGlowOverlay::BackupSkyOverlayData( int iBackupToSlot )
  443. {
  444. unsigned short iNext;
  445. for( unsigned short i=g_GlowOverlaySystem.m_GlowOverlays.Head(); i != g_GlowOverlaySystem.m_GlowOverlays.InvalidIndex(); i = iNext )
  446. {
  447. iNext = g_GlowOverlaySystem.m_GlowOverlays.Next( i );
  448. CGlowOverlay *pOverlay = g_GlowOverlaySystem.m_GlowOverlays[i];
  449. if( !pOverlay->m_bActivated || !pOverlay->m_bDirectional || !pOverlay->m_bInSky )
  450. continue;
  451. pOverlay->m_skyObstructionScaleBackups[iBackupToSlot] = pOverlay->m_skyObstructionScale;
  452. }
  453. }
  454. void CGlowOverlay::RestoreSkyOverlayData( int iRestoreFromSlot )
  455. {
  456. unsigned short iNext;
  457. for( unsigned short i=g_GlowOverlaySystem.m_GlowOverlays.Head(); i != g_GlowOverlaySystem.m_GlowOverlays.InvalidIndex(); i = iNext )
  458. {
  459. iNext = g_GlowOverlaySystem.m_GlowOverlays.Next( i );
  460. CGlowOverlay *pOverlay = g_GlowOverlaySystem.m_GlowOverlays[i];
  461. if( !pOverlay->m_bActivated || !pOverlay->m_bDirectional || !pOverlay->m_bInSky )
  462. continue;
  463. pOverlay->m_skyObstructionScale = pOverlay->m_skyObstructionScaleBackups[iRestoreFromSlot];
  464. }
  465. }
  466. #endif //#ifdef PORTAL