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.

482 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. #include "cbase.h"
  3. #include "KeyValues.h"
  4. #include "cdll_client_int.h"
  5. #include "view_scene.h"
  6. #include "viewrender.h"
  7. #include "tier0/icommandline.h"
  8. #include "materialsystem/imesh.h"
  9. #include "materialsystem/imaterial.h"
  10. #include "materialsystem/imaterialsystemhardwareconfig.h"
  11. #include "materialsystem/imaterialvar.h"
  12. #include "ScreenSpaceEffects.h"
  13. // memdbgon must be the last include file in a .cpp file!!!
  14. #include "tier0/memdbgon.h"
  15. static float g_flDX7NoiseScale = 4.0f;
  16. //------------------------------------------------------------------------------
  17. // Film grain post-processing effect
  18. //------------------------------------------------------------------------------
  19. struct FilmDustParticle_t
  20. {
  21. int m_nChannel;
  22. float m_flPositionX;
  23. float m_flPositionY;
  24. float m_flWidth;
  25. float m_flHeight;
  26. int m_nSplotchIndex;
  27. int m_nOrientation;
  28. };
  29. class CFilmGrainEffect : public IScreenSpaceEffect
  30. {
  31. public:
  32. CFilmGrainEffect( );
  33. ~CFilmGrainEffect( );
  34. void Init( );
  35. void Shutdown( );
  36. void SetParameters( KeyValues *params );
  37. void Render( int x, int y, int w, int h );
  38. void Enable( bool bEnable );
  39. bool IsEnabled( );
  40. private:
  41. void DrawSplotch( float x, float y, float width, float height, float u, float v, float uWidth, float vHeight, int orientation, int alpha=255 );
  42. bool m_bEnable;
  43. CMaterialReference m_GrainMaterial;
  44. CMaterialReference m_DustMaterial;
  45. Vector4D m_NoiseScale;
  46. int m_nMaxDustParticles;
  47. float m_flMinDustSize;
  48. float m_flMaxDustSize;
  49. float m_flChanceOfDust;
  50. float m_flUpdateRate;
  51. bool m_bEnableFlicker;
  52. int m_nFlickerAlpha;
  53. bool m_bSplitScreen;
  54. int m_nCachedParticleTime;
  55. CUtlVector< FilmDustParticle_t > m_CachedParticles;
  56. float m_flEffectAlpha;
  57. IMaterial * m_pFlickerMaterial;
  58. };
  59. ADD_SCREENSPACE_EFFECT( CFilmGrainEffect, filmgrain );
  60. //------------------------------------------------------------------------------
  61. // CFilmGrainEffect constructor
  62. //------------------------------------------------------------------------------
  63. CFilmGrainEffect::CFilmGrainEffect( )
  64. {
  65. m_NoiseScale = Vector4D( 0.14f, 0.14f, 0.14f, 0.78f );
  66. m_nMaxDustParticles = 3;
  67. m_flMinDustSize = 0.03f;
  68. m_flMaxDustSize = 0.15f;
  69. m_flChanceOfDust = 0.75f;
  70. m_flUpdateRate = 24.0f;
  71. m_nCachedParticleTime = -1;
  72. m_bSplitScreen = false;
  73. m_bEnableFlicker = true;
  74. m_nFlickerAlpha = 90;
  75. m_flEffectAlpha = 1.0;
  76. m_pFlickerMaterial = NULL;
  77. }
  78. //------------------------------------------------------------------------------
  79. // CFilmGrainEffect destructor
  80. //------------------------------------------------------------------------------
  81. CFilmGrainEffect::~CFilmGrainEffect( )
  82. {
  83. }
  84. //------------------------------------------------------------------------------
  85. // CFilmGrainEffect init
  86. //------------------------------------------------------------------------------
  87. void CFilmGrainEffect::Init( )
  88. {
  89. KeyValues *pVMTKeyValues = new KeyValues( "filmgrain" );
  90. pVMTKeyValues->SetString( "$GRAIN_TEXTURE", "Effects/FilmScan256" );
  91. pVMTKeyValues->SetString( "$SCALEBIAS", "[0.0 0.0 0.0 0.0]" );
  92. pVMTKeyValues->SetString( "$NOISESCALE", "[0.0 1.0 0.5 1.0]" );
  93. m_GrainMaterial.Init( "engine/filmgrain", pVMTKeyValues );
  94. m_GrainMaterial->Refresh( );
  95. pVMTKeyValues = new KeyValues( "filmdust" );
  96. pVMTKeyValues->SetString( "$DUST_TEXTURE", "Effects/Splotches256" );
  97. pVMTKeyValues->SetString( "$SCALEBIAS", "[0.0 0.0 0.0 0.0]" );
  98. pVMTKeyValues->SetString( "$CHANNEL_SELECT", "[1.0 0.0 0.0 0.0]" );
  99. m_DustMaterial.Init( "engine/filmdust", pVMTKeyValues );
  100. m_DustMaterial->Refresh( );
  101. m_pFlickerMaterial = materials->FindMaterial( "effects/flicker_128", TEXTURE_GROUP_OTHER, false );
  102. if ( m_pFlickerMaterial )
  103. {
  104. m_pFlickerMaterial->AddRef();
  105. }
  106. }
  107. //------------------------------------------------------------------------------
  108. // CFilmGrainEffect shutdown
  109. //------------------------------------------------------------------------------
  110. void CFilmGrainEffect::Shutdown( )
  111. {
  112. m_DustMaterial.Shutdown();
  113. m_GrainMaterial.Shutdown();
  114. if ( m_pFlickerMaterial )
  115. {
  116. m_pFlickerMaterial->Release();
  117. }
  118. }
  119. //------------------------------------------------------------------------------
  120. // CFilmGrainEffect enable
  121. //------------------------------------------------------------------------------
  122. void CFilmGrainEffect::Enable( bool bEnable )
  123. {
  124. m_bEnable = bEnable;
  125. }
  126. bool CFilmGrainEffect::IsEnabled( )
  127. {
  128. return m_bEnable;
  129. }
  130. //------------------------------------------------------------------------------
  131. // CFilmGrainEffect SetParameters
  132. //------------------------------------------------------------------------------
  133. void CFilmGrainEffect::SetParameters( KeyValues *params )
  134. {
  135. if( params->FindKey( "split_screen" ) )
  136. {
  137. int ival = params->GetInt( "split_screen" );
  138. m_bSplitScreen = ival?true:false;
  139. extern void EnableHUDFilmDemo( bool bEnable, const char *left_string_id, const char *right_string_id );
  140. EnableHUDFilmDemo( m_bSplitScreen, "#Valve_FilmDemo_FilmGrain_LeftTitle", "#Valve_FilmDemo_FilmGrain_RightTitle" );
  141. }
  142. if( params->FindKey( "noise_scale" ) )
  143. {
  144. Color noise_color = params->GetColor( "noise_scale" );
  145. int r, g, b, a;
  146. noise_color.GetColor( r, g, b, a );
  147. m_NoiseScale.x = r/255.0f;;
  148. m_NoiseScale.y = g/255.0f;;
  149. m_NoiseScale.z = b/255.0f;;
  150. m_NoiseScale.w = a/255.0f;;
  151. }
  152. if( params->FindKey( "max_dust_particles" ) )
  153. {
  154. m_nMaxDustParticles = params->GetInt( "max_dust_particles" );
  155. }
  156. if( params->FindKey( "min_dust_size" ) )
  157. {
  158. m_flMinDustSize = params->GetFloat( "min_dust_size" );
  159. }
  160. if( params->FindKey( "max_dust_size" ) )
  161. {
  162. m_flMaxDustSize = params->GetFloat( "max_dust_size" );
  163. }
  164. if( params->FindKey( "dust_prob" ) )
  165. {
  166. m_flChanceOfDust = params->GetFloat( "dust_prob" );
  167. }
  168. if( params->FindKey( "update_rate" ) )
  169. {
  170. m_flUpdateRate = params->GetFloat( "update_rate" );
  171. }
  172. if( params->FindKey( "enable_flicker" ) )
  173. {
  174. m_bEnableFlicker = params->GetInt( "enable_flicker" );
  175. }
  176. if( params->FindKey( "flicker_alpha" ) )
  177. {
  178. m_nFlickerAlpha = params->GetInt( "flicker_alpha" );
  179. }
  180. if( params->FindKey( "effect_alpha" ) )
  181. {
  182. m_flEffectAlpha = params->GetFloat( "effect_alpha" );
  183. }
  184. }
  185. //-----------------------------------------------------------------------------
  186. // Draws a quad to resolve accumulation buffer samples as needed
  187. //-----------------------------------------------------------------------------
  188. void CFilmGrainEffect::DrawSplotch( float x, float y, float flWidth, float flHeight, float u, float v, float uWidth, float vWidth, int orientation, int alpha )
  189. {
  190. float flAlpha = ( alpha / 255.0f ) * m_flEffectAlpha;
  191. float tempU[4] = { u, u, u+uWidth, u+uWidth };
  192. float tempV[4] = { v, v+vWidth, v+vWidth, v };
  193. float _u[4], _v[4];
  194. for( int i=0;i<4;i++ )
  195. {
  196. _u[ (i + orientation)%4 ] = tempU[ i ];
  197. _v[ (i + orientation)%4 ] = tempV[ i ];
  198. }
  199. CMatRenderContextPtr pRenderContext( materials );
  200. IMesh *pMesh = pRenderContext->GetDynamicMesh();
  201. CMeshBuilder meshBuilder;
  202. pRenderContext->MatrixMode( MATERIAL_VIEW );
  203. pRenderContext->PushMatrix();
  204. pRenderContext->LoadIdentity();
  205. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  206. pRenderContext->PushMatrix();
  207. pRenderContext->LoadIdentity();
  208. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  209. meshBuilder.Position3f( x, y, 0.0f ); // Upper left
  210. meshBuilder.TexCoord2f( 0, _u[0], _v[0] );
  211. meshBuilder.Color4f( 1.0f, 1.0f, 1.0f, flAlpha );
  212. meshBuilder.AdvanceVertex();
  213. meshBuilder.Position3f( x, y+flHeight, 0.0f ); // Lower left
  214. meshBuilder.TexCoord2f( 0, _u[1], _v[1] );
  215. meshBuilder.Color4f( 1.0f, 1.0f, 1.0f, flAlpha );
  216. meshBuilder.AdvanceVertex();
  217. meshBuilder.Position3f( x+flWidth, y+flHeight, 0.0 ); // Lower right
  218. meshBuilder.TexCoord2f( 0, _u[2], _v[2] );
  219. meshBuilder.Color4f( 1.0f, 1.0f, 1.0f, flAlpha );
  220. meshBuilder.AdvanceVertex();
  221. meshBuilder.Position3f( x+flWidth, y, 0.0 ); // Upper right
  222. meshBuilder.TexCoord2f( 0, _u[3], _v[3] );
  223. meshBuilder.Color4f( 1.0f, 1.0f, 1.0f, flAlpha );
  224. meshBuilder.AdvanceVertex();
  225. meshBuilder.End();
  226. pMesh->Draw();
  227. pRenderContext->MatrixMode( MATERIAL_VIEW );
  228. pRenderContext->PopMatrix();
  229. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  230. pRenderContext->PopMatrix();
  231. }
  232. //------------------------------------------------------------------------------
  233. // CFilmGrainEffect render
  234. //------------------------------------------------------------------------------
  235. void CFilmGrainEffect::Render( int x, int y, int w, int h )
  236. {
  237. if( !m_bEnable )
  238. return;
  239. int nTime = (int)(gpGlobals->curtime * m_flUpdateRate);
  240. // Set up random offsets for grain texture
  241. float flBiasU = RandomFloat();
  242. float flBiasV = RandomFloat();
  243. float flScaleU = w / 256.0f;
  244. float flScaleV = h / 256.0f;
  245. flBiasU *= w;
  246. flBiasV *= h;
  247. int paramCount = m_GrainMaterial->ShaderParamCount();
  248. IMaterialVar **pParams = m_GrainMaterial->GetShaderParams();
  249. for( int i=0;i<paramCount;i++ )
  250. {
  251. IMaterialVar *pVar = pParams[i];
  252. // alpha operates from 1.0 -> m_NoiseScale.w
  253. float alpha = 1.0 - ( 1.0 - m_NoiseScale.w ) * m_flEffectAlpha;
  254. if( !Q_stricmp( pVar->GetName(), "$noisescale" ) )
  255. {
  256. if( g_pMaterialSystemHardwareConfig->GetDXSupportLevel()<=70 )
  257. {
  258. pVar->SetVecValue( m_NoiseScale.x*g_flDX7NoiseScale * m_flEffectAlpha,
  259. m_NoiseScale.y*g_flDX7NoiseScale * m_flEffectAlpha,
  260. m_NoiseScale.z*g_flDX7NoiseScale * m_flEffectAlpha,
  261. alpha );
  262. }
  263. else
  264. {
  265. pVar->SetVecValue( m_NoiseScale.x * m_flEffectAlpha,
  266. m_NoiseScale.y * m_flEffectAlpha,
  267. m_NoiseScale.z * m_flEffectAlpha,
  268. alpha );
  269. }
  270. }
  271. }
  272. // Render Effect
  273. CMatRenderContextPtr pRenderContext( materials );
  274. pRenderContext->Bind( m_GrainMaterial );
  275. if( m_bSplitScreen )
  276. {
  277. DrawSplotch( 0.0f, -1.0f, 2.0f, 2.0f, flBiasU, flBiasV, flScaleU, flScaleV, 0 );
  278. }
  279. else
  280. {
  281. DrawSplotch( -1.0f, -1.0f, 2.0f, 2.0f, flBiasU, flBiasV, flScaleU, flScaleV, 0 );
  282. }
  283. int screenWidth, screenHeight;
  284. pRenderContext->GetRenderTargetDimensions( screenWidth, screenHeight );
  285. // Now let's do the flicker
  286. if( m_bEnableFlicker )
  287. {
  288. if( !IsErrorMaterial( m_pFlickerMaterial ) )
  289. {
  290. m_pFlickerMaterial->Refresh();
  291. m_pFlickerMaterial->SetMaterialVarFlag( MATERIAL_VAR_VERTEXALPHA, true );
  292. pRenderContext->Bind( m_pFlickerMaterial );
  293. int nFlickerAlpha = (int)( m_nFlickerAlpha * m_flEffectAlpha );
  294. if( !m_bSplitScreen )
  295. {
  296. DrawSplotch( -1.0f, -1.0f, 2.0f, 2.0f, 0.0f, 1.0f, 1.0f, -1.0f, 0, nFlickerAlpha );
  297. }
  298. else
  299. {
  300. DrawSplotch( 0.0f, -1.0f, 2.0f, 2.0f, 0.5f, 1.0f, 0.5f, -1.0f, 0, nFlickerAlpha );
  301. }
  302. }
  303. }
  304. // Now for some dust particles
  305. if( nTime!=m_nCachedParticleTime )
  306. {
  307. // Need to regenerate our dust particles
  308. m_CachedParticles.RemoveAll();
  309. m_nCachedParticleTime = nTime;
  310. float flDustProb = RandomFloat( 0.0f, 1.0f );
  311. if( flDustProb < m_flChanceOfDust )
  312. {
  313. int numDustParticles = RandomInt( 0, m_nMaxDustParticles );
  314. for( int i=0;i<numDustParticles;i++ )
  315. {
  316. FilmDustParticle_t particle;
  317. particle.m_nChannel = RandomInt( 0, 2 );
  318. particle.m_flPositionX = RandomFloat( -1.0f, 1.0f );
  319. particle.m_flPositionY = RandomFloat( -1.0f, 1.0f );
  320. particle.m_nOrientation = RandomInt( 0, 3 );
  321. particle.m_nSplotchIndex = RandomInt( 0, 15 );
  322. clamp( particle.m_nSplotchIndex, 0, 15 );
  323. particle.m_flHeight = RandomFloat( m_flMinDustSize, m_flMaxDustSize );
  324. particle.m_flWidth = particle.m_flHeight * (float)screenHeight / (float)screenWidth;
  325. if( (!m_bSplitScreen) || (particle.m_flPositionX-particle.m_flWidth > 0.0f) )
  326. {
  327. m_CachedParticles.AddToTail( particle );
  328. }
  329. }
  330. }
  331. }
  332. for( int i=0;i<m_CachedParticles.Count();i++ )
  333. {
  334. FilmDustParticle_t *particle = &m_CachedParticles[i];
  335. float channelSelect[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
  336. channelSelect[ particle->m_nChannel ] = 1.0f;
  337. paramCount = m_DustMaterial->ShaderParamCount();
  338. pParams = m_DustMaterial->GetShaderParams();
  339. for( int i=0;i<paramCount;i++ )
  340. {
  341. IMaterialVar *pVar = pParams[i];
  342. if( !Q_stricmp( pVar->GetName(), "$channel_select" ) )
  343. {
  344. pVar->SetVecValue( channelSelect[0], channelSelect[1], channelSelect[2], channelSelect[3] );
  345. }
  346. }
  347. float flUOffset = (particle->m_nSplotchIndex % 4) / 4.0f;
  348. float flVOffset = (particle->m_nSplotchIndex / 4) / 4.0f;
  349. pRenderContext->Bind( m_DustMaterial );
  350. DrawSplotch( particle->m_flPositionX, particle->m_flPositionY, particle->m_flWidth * m_flEffectAlpha, particle->m_flHeight * m_flEffectAlpha,
  351. flUOffset, flVOffset, 0.25f, 0.25f, particle->m_nOrientation );
  352. }
  353. }
  354. //------------------------------------------------------------------------------
  355. // Console Interface
  356. //------------------------------------------------------------------------------
  357. static void EnableFilmGrain( IConVar *pConVar, char const *pOldString, float flOldValue )
  358. {
  359. ConVarRef var( pConVar );
  360. if( var.GetBool() )
  361. {
  362. g_pScreenSpaceEffects->EnableScreenSpaceEffect( "filmgrain" );
  363. }
  364. else
  365. {
  366. g_pScreenSpaceEffects->DisableScreenSpaceEffect( "filmgrain" );
  367. }
  368. }
  369. static ConVar mat_filmgrain( "mat_filmgrain", "0", FCVAR_CLIENTDLL, "Enable/disable film grain post effect", EnableFilmGrain );