//========== Copyright (c) Valve Corporation, All rights reserved. ==========// // STATIC: "DUALSEQUENCE" "0..1" // STATIC: "SEQUENCE_BLEND_MODE" "0..2" // STATIC: "ADDBASETEXTURE2" "0..1" // STATIC: "MAXLUMFRAMEBLEND1" "0..1" // STATIC: "MAXLUMFRAMEBLEND2" "0..1" // STATIC: "EXTRACTGREENALPHA" "0..1" // STATIC: "COLORRAMP" "0..1" // STATIC: "ANIMBLEND" "0..1" // STATIC: "ADDSELF" "0..1" // STATIC: "MOD2X" "0..1" // STATIC: "DEPTHBLEND" "0..1" [CONSOLE] // STATIC: "DEPTHBLEND" "0..1" [PC] // STATIC: "INVERSEDEPTHBLEND" "0..1" [CONSOLE] // STATIC: "INVERSEDEPTHBLEND" "0..0" [PC] // STATIC: "SHADER_SRGB_READ" "0..1" [XBOX] // STATIC: "SHADER_SRGB_READ" "0..0" [PC] // STATIC: "SHADER_SRGB_READ" "0..0" [SONYPS3] // STATIC: "COLOR_LERP_PS" "0..1" // STATIC: "PACKED_INTERPOLATOR" "0..1" // STATIC: "DISTANCEALPHA" "0..1" // STATIC: "SOFTEDGES" "0..1" // STATIC: "OUTLINE" "0..1" // STATIC: "MULOUTPUTBYALPHA" "0..1" // SKIP: ( $DISTANCEALPHA == 0 ) && ( $SOFTEDGES || $OUTLINE ) // SKIP: $DISTANCEALPHA && $DUALSEQUENCE // SKIP: $DISTANCEALPHA && ( $MAXLUMFRAMEBLEND2 || $MAXLUMFRAMEBLEND1 ) // SKIP: ( $DUALSEQUENCE == 0 ) && ( $SEQUENCE_BLEND_MODE != 0 ) // SKIP: $INVERSEDEPTHBLEND && !$DEPTHBLEND [CONSOLE] // These are mutually exclusive because PACKED_INTERPOLATOR only fetches a single texture tile // SKIP: $PACKED_INTERPOLATOR && ( $ANIMBLEND || $MAXLUMFRAMEBLEND1 || $EXTRACTGREENALPHA || $DUALSEQUENCE ) #define COMBINE_MODE_AVERAGE 0 #define COMBINE_MODE_USE_FIRST_AS_ALPHA_MASK_ON_SECOND 1 #define COMBINE_MODE_USE_FIRST_OVER_SECOND 2 #define HDRTYPE HDR_TYPE_NONE #include "common_ps_fxc.h" HALF4 g_Parameters : register( c0 ); #define fAdditiveBlendWeight g_Parameters.x #define fOverbrightFactor g_Parameters.y #define fAdditiveSelfBlendWeight g_Parameters.z #define fIntensity g_Parameters.w float g_flMod2xIdentity : register( c1 ); float4 g_DepthFeatheringConstants : register( c2 ); float4 g_FogParams : register( c3 ); float3 g_EyePos : register( c4 ); HALF3 g_vColor0 : register( c5 ); HALF3 g_vColor1 : register( c6 ); // VS_OUTPUT in a common file. #define PIXELSHADER #include "common_spritecard_fxc.h" sampler BaseTextureSampler : register( s0 ); sampler ColorRampSampler : register( s1 ); sampler DepthSampler : register( s2 ); #if DISTANCEALPHA == 0 #define EDGESOFTNESS_START 0.5h #define EDGESOFTNESS_END 0.425h #define OUTLINECOLOR HALF4( 0, 1, 0, 1 ) #define OUTLINESTART0 0.2h #define OUTLINESTART1 0.3h #define OUTLINEEND0 0.49h #define OUTLINEEND1 0.6h #else HALF4 g_vecOutlineColor : register( c7 ); #define OUTLINECOLOR (HALF4)( g_vecOutlineColor * i.vecOutlineTint ) HALF4 g_vecOutlineControl : register( c8 ); #define OUTLINESTART0 ( g_vecOutlineControl.x ) #define OUTLINESTART1 ( g_vecOutlineControl.y ) #define OUTLINEEND0 ( g_vecOutlineControl.z ) #define OUTLINEEND1 ( g_vecOutlineControl.w ) HALF4 g_vecEdgeControl : register( c9 ); #define EDGESOFTNESS_START ( g_vecEdgeControl.x ) #define EDGESOFTNESS_END ( g_vecEdgeControl.y ) #endif HALF DepthFeatheringFullDepth( sampler DepthSampler, const float4 vProjPos, float4 vDepthBlendConstants ) { # if ( !(defined(SHADER_MODEL_PS_1_1) || defined(SHADER_MODEL_PS_1_4) || defined(SHADER_MODEL_PS_2_0)) ) //minimum requirement of ps2b { float2 vProjPosDivW = vProjPos.xy / vProjPos.w; float2 vScreenPos = vProjPosDivW * g_vDepthFeatherViewportMad.xy + g_vDepthFeatherViewportMad.zw; float flFeatheredAlpha; // Sample the scene's depth at the current fragment. float flSceneProjZ = tex2D( DepthSampler, vScreenPos ).r; float4 vSceneProjPos = float4( vProjPosDivW.x, vProjPosDivW.y, flSceneProjZ, 1.0f ); float flSceneViewZ = dot( vSceneProjPos, g_vDepthFeatherProjToViewZW[0] ); float flSceneViewW = dot( vSceneProjPos, g_vDepthFeatherProjToViewZW[1] ); flSceneViewZ /= flSceneViewW; // fragment's viewspace Z from its projection space coord. computed in VS float flSurfViewZ = vProjPos.z; flFeatheredAlpha = flSurfViewZ - flSceneViewZ; flFeatheredAlpha = saturate( saturate( vDepthBlendConstants.z * flFeatheredAlpha ) + vDepthBlendConstants.w ); return flFeatheredAlpha; } # else { return 1.0; } # endif } float4_color_return_type main( PS_INPUT i ) : COLOR { // Sample frames from textures HALF4 baseTex0 = h4tex2Dsrgb( BaseTextureSampler, i.texCoord0_1.xy ); HALF4 baseTex1; HALF4 result = baseTex0; HALF4 vVertexColor; #if ( PACKED_INTERPOLATOR ) { vVertexColor.rgba = i.texCoord0_1.zzzw; } #else { vVertexColor.rgba = i.argbcolor.rgba; baseTex1 = h4tex2Dsrgb( BaseTextureSampler, i.texCoord0_1.wz ); } #endif #if ( COLOR_LERP_PS ) { vVertexColor.rgb = lerp( g_vColor0.rgb, g_vColor1.rgb, saturate( vVertexColor.r ) ); } #endif // Blend by default (may override with bMaxLumFrameBlend1 or bExtractGreenAlpha) #if ( ANIMBLEND ) result = lerp( result, baseTex1, (HALF)i.blendfactor0.x ); #endif #if ( MAXLUMFRAMEBLEND1 ) { // Blend between animation frames based upon max luminance HALF lum0 = dot( HALF3(.3, .59, .11), baseTex0.rgb * (1.0h-(HALF)i.blendfactor0.x)); HALF lum1 = dot( HALF3(.3, .59, .11), baseTex1.rgb * (HALF)i.blendfactor0.x); if ( lum0 > lum1 ) result = baseTex0; else result = baseTex1; } #elif( EXTRACTGREENALPHA ) { // Weight Green/Alphas from the two frames for a scalar result result = dot( baseTex0, (HALF4)i.blendfactor0 ) + dot( baseTex1, (HALF4)i.blendfactor1 ); } #endif if ( DISTANCEALPHA ) { HALF flOrigAlpha = result.a; if ( SOFTEDGES ) { result.a = smoothstep( EDGESOFTNESS_END, EDGESOFTNESS_START, result.a ); } else { if ( result.a < 0.5h ) result = 0; } if ( OUTLINE ) { result.rgb *= vVertexColor.rgb; // multiply by vertex color before glow. if ( ( flOrigAlpha >= OUTLINESTART0 ) && ( flOrigAlpha <= OUTLINEEND1 ) ) { float oFactor = 1.0f; if ( flOrigAlpha <= OUTLINESTART1 ) { oFactor = smoothstep( OUTLINESTART0, OUTLINESTART1, flOrigAlpha ); } else { oFactor = smoothstep( OUTLINEEND1, OUTLINEEND0, flOrigAlpha ); } result = lerp( result, OUTLINECOLOR, oFactor ); } } } #if ( DUALSEQUENCE ) { baseTex0 = h4tex2Dsrgb( BaseTextureSampler, i.vSeq2TexCoord0_1.xy ); baseTex1 = h4tex2Dsrgb( BaseTextureSampler, i.vSeq2TexCoord0_1.wz ); // Blend by default (may override with bMaxLumFrameBlend2) HALF4 rgb2 = lerp( baseTex0, baseTex1, (HALF)i.blendfactor0.z ); #if ( MAXLUMFRAMEBLEND2 ) { // blend between animation frames based upon max luminance HALF tlum0 = dot( HALF3(.3, .59, .11), baseTex0.rgb * (1.0h-(HALF)i.blendfactor0.x)); HALF tlum1 = dot( HALF3(.3, .59, .11), baseTex1.rgb * (HALF)i.blendfactor0.x); if ( tlum0 > tlum1 ) rgb2 = baseTex0; else rgb2 = baseTex1; } #endif #if ( SEQUENCE_BLEND_MODE == COMBINE_MODE_AVERAGE ) { result = 0.5h * ( result + rgb2 ); } #elif ( SEQUENCE_BLEND_MODE == COMBINE_MODE_USE_FIRST_AS_ALPHA_MASK_ON_SECOND ) { result.rgb = rgb2.rgb; } #elif ( SEQUENCE_BLEND_MODE == COMBINE_MODE_USE_FIRST_OVER_SECOND ) { result.rgb = lerp( result.rgb, rgb2.rgb, rgb2.a ); } #endif } #endif // Optional color ramp #if ( COLORRAMP ) { result.rgb = h3tex2Dsrgb( ColorRampSampler, float2( result.r, result.g ) ).rgb; } #endif // Overbright result.rgb *= fOverbrightFactor; //Soft Particles FTW #if (DEPTHBLEND == 1) HALF fDepthBlend = DepthFeatheringFullDepth( DepthSampler, i.vProjPos, g_DepthFeatheringConstants ); #if (INVERSEDEPTHBLEND == 1) fDepthBlend = 1.0h - fDepthBlend; #endif vVertexColor.a *= fDepthBlend; #endif // Premultiply the alpha for a ONE:INVALPHA blend #if ( ADDBASETEXTURE2 ) { result.a *= vVertexColor.a; // In this case, we don't really want to pre-multiply by alpha #if ( !COLORRAMP ) { result.rgb *= result.a; } #endif #if ( EXTRACTGREENALPHA ) { result.rgb += fAdditiveBlendWeight * vVertexColor.a * result.rgb; } #else { result.rgb += fOverbrightFactor * fAdditiveBlendWeight * vVertexColor.a * h3tex2Dsrgb( BaseTextureSampler, i.texCoord2 ).rgb; } #endif result.rgb *= vVertexColor.rgb; } #else { #if ADDSELF { result.a *= vVertexColor.a; result.rgb *= result.a; result.rgb += fAdditiveSelfBlendWeight * result.rgb; result.rgb *= vVertexColor.rgb; } #else { #if ( MOD2X ) { result.rgb = lerp( (HALF3)g_flMod2xIdentity, result.rgb, vVertexColor.rgb ); result.a *= vVertexColor.a; } #else { if ( ! OUTLINE ) { result *= vVertexColor; // if outlined, we've already done this. don't want to mul glow by particle color. } else { result.a *= vVertexColor.a; } } #endif } #endif } #endif float4_color_return_type vOutput; #if ( MOD2X ) { // Blend towards a unity multiply as alpha gets closer to zero result.rgb = lerp( ( HALF3 )g_flMod2xIdentity, result.rgb, result.a ); // Don't tonemap scale since we are multiplying by what is already in the framebuffer. vOutput = FinalOutputHalf( result, 0, PIXEL_FOG_TYPE_NONE, TONEMAP_SCALE_NONE ); } #else { vOutput = FinalOutputHalf( result, 0, PIXEL_FOG_TYPE_NONE, TONEMAP_SCALE_LINEAR ); #if defined( _X360 ) && defined( CSTRIKE15 ) // TEMPORARY - fix up properly after PAX // undo the linear to gamma that would have been done in FinalOutput as we have other colour ops to perform vOutput.rgb = GammaToLinear( vOutput.rgb ); #endif } #endif vOutput = saturate( vOutput ); // Purposely multiplying after saturating. vOutput.rgb *= fIntensity; #if ( MULOUTPUTBYALPHA ) { // Do the final alpha multiply in the shader to avoid alpha blender unit precision problems. (This should only be enabled when we would normally // do SRC_RGB*SRC_ALPHA+DST_RGB blending.) vOutput.rgb *= vOutput.a; vOutput.a = 1.0h; } #endif #if ( MOD2X ) { } #else { #if defined( _X360 ) && defined( CSTRIKE15 ) // [mariod] - srgb write required in this shader - after FinalOutput due to other ops - Final output will skip since TONEMAP_SCALE is NONE vOutput.rgb = LinearToGamma( vOutput.rgb ); //vOutput.rgb = SrgbLinearToGamma( vOutput.rgb ); #endif } #endif return vOutput; }