summaryrefslogtreecommitdiff
path: root/game/client/dod/fx_dod_filmgrain.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/client/dod/fx_dod_filmgrain.cpp')
-rw-r--r--game/client/dod/fx_dod_filmgrain.cpp482
1 files changed, 482 insertions, 0 deletions
diff --git a/game/client/dod/fx_dod_filmgrain.cpp b/game/client/dod/fx_dod_filmgrain.cpp
new file mode 100644
index 0000000..d8b8bcb
--- /dev/null
+++ b/game/client/dod/fx_dod_filmgrain.cpp
@@ -0,0 +1,482 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+#include "cbase.h"
+
+#include "KeyValues.h"
+#include "cdll_client_int.h"
+#include "view_scene.h"
+#include "viewrender.h"
+#include "tier0/icommandline.h"
+#include "materialsystem/imesh.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imaterialsystemhardwareconfig.h"
+#include "materialsystem/imaterialvar.h"
+
+#include "ScreenSpaceEffects.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+static float g_flDX7NoiseScale = 4.0f;
+
+//------------------------------------------------------------------------------
+// Film grain post-processing effect
+//------------------------------------------------------------------------------
+struct FilmDustParticle_t
+{
+ int m_nChannel;
+
+ float m_flPositionX;
+ float m_flPositionY;
+
+ float m_flWidth;
+ float m_flHeight;
+
+ int m_nSplotchIndex;
+ int m_nOrientation;
+};
+
+class CFilmGrainEffect : public IScreenSpaceEffect
+{
+public:
+
+ CFilmGrainEffect( );
+ ~CFilmGrainEffect( );
+
+ void Init( );
+ void Shutdown( );
+
+ void SetParameters( KeyValues *params );
+
+ void Render( int x, int y, int w, int h );
+
+ void Enable( bool bEnable );
+ bool IsEnabled( );
+
+private:
+
+ void DrawSplotch( float x, float y, float width, float height, float u, float v, float uWidth, float vHeight, int orientation, int alpha=255 );
+
+ bool m_bEnable;
+
+ CMaterialReference m_GrainMaterial;
+ CMaterialReference m_DustMaterial;
+
+ Vector4D m_NoiseScale;
+
+ int m_nMaxDustParticles;
+
+ float m_flMinDustSize;
+ float m_flMaxDustSize;
+
+ float m_flChanceOfDust;
+
+ float m_flUpdateRate;
+
+ bool m_bEnableFlicker;
+ int m_nFlickerAlpha;
+
+ bool m_bSplitScreen;
+
+ int m_nCachedParticleTime;
+ CUtlVector< FilmDustParticle_t > m_CachedParticles;
+
+ float m_flEffectAlpha;
+
+ IMaterial * m_pFlickerMaterial;
+};
+
+ADD_SCREENSPACE_EFFECT( CFilmGrainEffect, filmgrain );
+
+//------------------------------------------------------------------------------
+// CFilmGrainEffect constructor
+//------------------------------------------------------------------------------
+CFilmGrainEffect::CFilmGrainEffect( )
+{
+ m_NoiseScale = Vector4D( 0.14f, 0.14f, 0.14f, 0.78f );
+
+ m_nMaxDustParticles = 3;
+
+ m_flMinDustSize = 0.03f;
+ m_flMaxDustSize = 0.15f;
+
+ m_flChanceOfDust = 0.75f;
+
+ m_flUpdateRate = 24.0f;
+
+ m_nCachedParticleTime = -1;
+
+ m_bSplitScreen = false;
+
+ m_bEnableFlicker = true;
+ m_nFlickerAlpha = 90;
+
+ m_flEffectAlpha = 1.0;
+
+ m_pFlickerMaterial = NULL;
+}
+
+
+//------------------------------------------------------------------------------
+// CFilmGrainEffect destructor
+//------------------------------------------------------------------------------
+CFilmGrainEffect::~CFilmGrainEffect( )
+{
+}
+
+
+//------------------------------------------------------------------------------
+// CFilmGrainEffect init
+//------------------------------------------------------------------------------
+void CFilmGrainEffect::Init( )
+{
+ KeyValues *pVMTKeyValues = new KeyValues( "filmgrain" );
+ pVMTKeyValues->SetString( "$GRAIN_TEXTURE", "Effects/FilmScan256" );
+ pVMTKeyValues->SetString( "$SCALEBIAS", "[0.0 0.0 0.0 0.0]" );
+ pVMTKeyValues->SetString( "$NOISESCALE", "[0.0 1.0 0.5 1.0]" );
+
+ m_GrainMaterial.Init( "engine/filmgrain", pVMTKeyValues );
+ m_GrainMaterial->Refresh( );
+
+ pVMTKeyValues = new KeyValues( "filmdust" );
+ pVMTKeyValues->SetString( "$DUST_TEXTURE", "Effects/Splotches256" );
+ pVMTKeyValues->SetString( "$SCALEBIAS", "[0.0 0.0 0.0 0.0]" );
+ pVMTKeyValues->SetString( "$CHANNEL_SELECT", "[1.0 0.0 0.0 0.0]" );
+
+ m_DustMaterial.Init( "engine/filmdust", pVMTKeyValues );
+ m_DustMaterial->Refresh( );
+
+ m_pFlickerMaterial = materials->FindMaterial( "effects/flicker_128", TEXTURE_GROUP_OTHER, false );
+ if ( m_pFlickerMaterial )
+ {
+ m_pFlickerMaterial->AddRef();
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// CFilmGrainEffect shutdown
+//------------------------------------------------------------------------------
+void CFilmGrainEffect::Shutdown( )
+{
+ m_DustMaterial.Shutdown();
+ m_GrainMaterial.Shutdown();
+
+ if ( m_pFlickerMaterial )
+ {
+ m_pFlickerMaterial->Release();
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// CFilmGrainEffect enable
+//------------------------------------------------------------------------------
+void CFilmGrainEffect::Enable( bool bEnable )
+{
+ m_bEnable = bEnable;
+}
+
+bool CFilmGrainEffect::IsEnabled( )
+{
+ return m_bEnable;
+}
+
+//------------------------------------------------------------------------------
+// CFilmGrainEffect SetParameters
+//------------------------------------------------------------------------------
+void CFilmGrainEffect::SetParameters( KeyValues *params )
+{
+ if( params->FindKey( "split_screen" ) )
+ {
+ int ival = params->GetInt( "split_screen" );
+ m_bSplitScreen = ival?true:false;
+
+ extern void EnableHUDFilmDemo( bool bEnable, const char *left_string_id, const char *right_string_id );
+ EnableHUDFilmDemo( m_bSplitScreen, "#Valve_FilmDemo_FilmGrain_LeftTitle", "#Valve_FilmDemo_FilmGrain_RightTitle" );
+ }
+
+ if( params->FindKey( "noise_scale" ) )
+ {
+ Color noise_color = params->GetColor( "noise_scale" );
+ int r, g, b, a;
+ noise_color.GetColor( r, g, b, a );
+ m_NoiseScale.x = r/255.0f;;
+ m_NoiseScale.y = g/255.0f;;
+ m_NoiseScale.z = b/255.0f;;
+ m_NoiseScale.w = a/255.0f;;
+ }
+
+ if( params->FindKey( "max_dust_particles" ) )
+ {
+ m_nMaxDustParticles = params->GetInt( "max_dust_particles" );
+ }
+
+ if( params->FindKey( "min_dust_size" ) )
+ {
+ m_flMinDustSize = params->GetFloat( "min_dust_size" );
+ }
+
+ if( params->FindKey( "max_dust_size" ) )
+ {
+ m_flMaxDustSize = params->GetFloat( "max_dust_size" );
+ }
+
+ if( params->FindKey( "dust_prob" ) )
+ {
+ m_flChanceOfDust = params->GetFloat( "dust_prob" );
+ }
+
+ if( params->FindKey( "update_rate" ) )
+ {
+ m_flUpdateRate = params->GetFloat( "update_rate" );
+ }
+
+ if( params->FindKey( "enable_flicker" ) )
+ {
+ m_bEnableFlicker = params->GetInt( "enable_flicker" );
+ }
+
+ if( params->FindKey( "flicker_alpha" ) )
+ {
+ m_nFlickerAlpha = params->GetInt( "flicker_alpha" );
+ }
+
+ if( params->FindKey( "effect_alpha" ) )
+ {
+ m_flEffectAlpha = params->GetFloat( "effect_alpha" );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Draws a quad to resolve accumulation buffer samples as needed
+//-----------------------------------------------------------------------------
+void CFilmGrainEffect::DrawSplotch( float x, float y, float flWidth, float flHeight, float u, float v, float uWidth, float vWidth, int orientation, int alpha )
+{
+ float flAlpha = ( alpha / 255.0f ) * m_flEffectAlpha;
+
+ float tempU[4] = { u, u, u+uWidth, u+uWidth };
+ float tempV[4] = { v, v+vWidth, v+vWidth, v };
+
+ float _u[4], _v[4];
+ for( int i=0;i<4;i++ )
+ {
+ _u[ (i + orientation)%4 ] = tempU[ i ];
+ _v[ (i + orientation)%4 ] = tempV[ i ];
+ }
+
+ CMatRenderContextPtr pRenderContext( materials );
+ IMesh *pMesh = pRenderContext->GetDynamicMesh();
+ CMeshBuilder meshBuilder;
+
+ pRenderContext->MatrixMode( MATERIAL_VIEW );
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadIdentity();
+
+ pRenderContext->MatrixMode( MATERIAL_PROJECTION );
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadIdentity();
+
+ meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
+
+ meshBuilder.Position3f( x, y, 0.0f ); // Upper left
+ meshBuilder.TexCoord2f( 0, _u[0], _v[0] );
+ meshBuilder.Color4f( 1.0f, 1.0f, 1.0f, flAlpha );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( x, y+flHeight, 0.0f ); // Lower left
+ meshBuilder.TexCoord2f( 0, _u[1], _v[1] );
+ meshBuilder.Color4f( 1.0f, 1.0f, 1.0f, flAlpha );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( x+flWidth, y+flHeight, 0.0 ); // Lower right
+ meshBuilder.TexCoord2f( 0, _u[2], _v[2] );
+ meshBuilder.Color4f( 1.0f, 1.0f, 1.0f, flAlpha );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( x+flWidth, y, 0.0 ); // Upper right
+ meshBuilder.TexCoord2f( 0, _u[3], _v[3] );
+ meshBuilder.Color4f( 1.0f, 1.0f, 1.0f, flAlpha );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.End();
+ pMesh->Draw();
+
+ pRenderContext->MatrixMode( MATERIAL_VIEW );
+ pRenderContext->PopMatrix();
+
+ pRenderContext->MatrixMode( MATERIAL_PROJECTION );
+ pRenderContext->PopMatrix();
+}
+
+
+//------------------------------------------------------------------------------
+// CFilmGrainEffect render
+//------------------------------------------------------------------------------
+void CFilmGrainEffect::Render( int x, int y, int w, int h )
+{
+ if( !m_bEnable )
+ return;
+
+ int nTime = (int)(gpGlobals->curtime * m_flUpdateRate);
+
+ // Set up random offsets for grain texture
+ float flBiasU = RandomFloat();
+ float flBiasV = RandomFloat();
+ float flScaleU = w / 256.0f;
+ float flScaleV = h / 256.0f;
+
+ flBiasU *= w;
+ flBiasV *= h;
+
+ int paramCount = m_GrainMaterial->ShaderParamCount();
+ IMaterialVar **pParams = m_GrainMaterial->GetShaderParams();
+ for( int i=0;i<paramCount;i++ )
+ {
+ IMaterialVar *pVar = pParams[i];
+
+ // alpha operates from 1.0 -> m_NoiseScale.w
+ float alpha = 1.0 - ( 1.0 - m_NoiseScale.w ) * m_flEffectAlpha;
+
+ if( !Q_stricmp( pVar->GetName(), "$noisescale" ) )
+ {
+ if( g_pMaterialSystemHardwareConfig->GetDXSupportLevel()<=70 )
+ {
+ pVar->SetVecValue( m_NoiseScale.x*g_flDX7NoiseScale * m_flEffectAlpha,
+ m_NoiseScale.y*g_flDX7NoiseScale * m_flEffectAlpha,
+ m_NoiseScale.z*g_flDX7NoiseScale * m_flEffectAlpha,
+ alpha );
+ }
+ else
+ {
+ pVar->SetVecValue( m_NoiseScale.x * m_flEffectAlpha,
+ m_NoiseScale.y * m_flEffectAlpha,
+ m_NoiseScale.z * m_flEffectAlpha,
+ alpha );
+ }
+ }
+ }
+
+ // Render Effect
+ CMatRenderContextPtr pRenderContext( materials );
+
+ pRenderContext->Bind( m_GrainMaterial );
+ if( m_bSplitScreen )
+ {
+ DrawSplotch( 0.0f, -1.0f, 2.0f, 2.0f, flBiasU, flBiasV, flScaleU, flScaleV, 0 );
+ }
+ else
+ {
+ DrawSplotch( -1.0f, -1.0f, 2.0f, 2.0f, flBiasU, flBiasV, flScaleU, flScaleV, 0 );
+ }
+
+ int screenWidth, screenHeight;
+ pRenderContext->GetRenderTargetDimensions( screenWidth, screenHeight );
+
+ // Now let's do the flicker
+ if( m_bEnableFlicker )
+ {
+ if( !IsErrorMaterial( m_pFlickerMaterial ) )
+ {
+ m_pFlickerMaterial->Refresh();
+ m_pFlickerMaterial->SetMaterialVarFlag( MATERIAL_VAR_VERTEXALPHA, true );
+ pRenderContext->Bind( m_pFlickerMaterial );
+
+ int nFlickerAlpha = (int)( m_nFlickerAlpha * m_flEffectAlpha );
+
+ if( !m_bSplitScreen )
+ {
+ DrawSplotch( -1.0f, -1.0f, 2.0f, 2.0f, 0.0f, 1.0f, 1.0f, -1.0f, 0, nFlickerAlpha );
+ }
+ else
+ {
+ DrawSplotch( 0.0f, -1.0f, 2.0f, 2.0f, 0.5f, 1.0f, 0.5f, -1.0f, 0, nFlickerAlpha );
+ }
+ }
+ }
+
+ // Now for some dust particles
+ if( nTime!=m_nCachedParticleTime )
+ {
+ // Need to regenerate our dust particles
+ m_CachedParticles.RemoveAll();
+ m_nCachedParticleTime = nTime;
+
+ float flDustProb = RandomFloat( 0.0f, 1.0f );
+ if( flDustProb < m_flChanceOfDust )
+ {
+ int numDustParticles = RandomInt( 0, m_nMaxDustParticles );
+ for( int i=0;i<numDustParticles;i++ )
+ {
+ FilmDustParticle_t particle;
+
+ particle.m_nChannel = RandomInt( 0, 2 );
+
+ particle.m_flPositionX = RandomFloat( -1.0f, 1.0f );
+ particle.m_flPositionY = RandomFloat( -1.0f, 1.0f );
+
+ particle.m_nOrientation = RandomInt( 0, 3 );
+
+ particle.m_nSplotchIndex = RandomInt( 0, 15 );
+ clamp( particle.m_nSplotchIndex, 0, 15 );
+
+ particle.m_flHeight = RandomFloat( m_flMinDustSize, m_flMaxDustSize );
+ particle.m_flWidth = particle.m_flHeight * (float)screenHeight / (float)screenWidth;
+
+ if( (!m_bSplitScreen) || (particle.m_flPositionX-particle.m_flWidth > 0.0f) )
+ {
+ m_CachedParticles.AddToTail( particle );
+ }
+ }
+ }
+ }
+
+ for( int i=0;i<m_CachedParticles.Count();i++ )
+ {
+ FilmDustParticle_t *particle = &m_CachedParticles[i];
+
+ float channelSelect[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ channelSelect[ particle->m_nChannel ] = 1.0f;
+
+ paramCount = m_DustMaterial->ShaderParamCount();
+ pParams = m_DustMaterial->GetShaderParams();
+ for( int i=0;i<paramCount;i++ )
+ {
+ IMaterialVar *pVar = pParams[i];
+
+ if( !Q_stricmp( pVar->GetName(), "$channel_select" ) )
+ {
+ pVar->SetVecValue( channelSelect[0], channelSelect[1], channelSelect[2], channelSelect[3] );
+ }
+ }
+
+ float flUOffset = (particle->m_nSplotchIndex % 4) / 4.0f;
+ float flVOffset = (particle->m_nSplotchIndex / 4) / 4.0f;
+
+ pRenderContext->Bind( m_DustMaterial );
+
+ DrawSplotch( particle->m_flPositionX, particle->m_flPositionY, particle->m_flWidth * m_flEffectAlpha, particle->m_flHeight * m_flEffectAlpha,
+ flUOffset, flVOffset, 0.25f, 0.25f, particle->m_nOrientation );
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// Console Interface
+//------------------------------------------------------------------------------
+static void EnableFilmGrain( IConVar *pConVar, char const *pOldString, float flOldValue )
+{
+ ConVarRef var( pConVar );
+ if( var.GetBool() )
+ {
+ g_pScreenSpaceEffects->EnableScreenSpaceEffect( "filmgrain" );
+ }
+ else
+ {
+ g_pScreenSpaceEffects->DisableScreenSpaceEffect( "filmgrain" );
+ }
+}
+
+static ConVar mat_filmgrain( "mat_filmgrain", "0", FCVAR_CLIENTDLL, "Enable/disable film grain post effect", EnableFilmGrain );
+