//========== 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" [XBOX] // STATIC: "DEPTHBLEND" "0..0" [PC] // STATIC: "INVERSEDEPTHBLEND" "0..1" [XBOX] // STATIC: "INVERSEDEPTHBLEND" "0..0" [PC] // STATIC: "SHADER_SRGB_READ" "0..1" [XBOX] // STATIC: "SHADER_SRGB_READ" "0..0" [PC] // STATIC: "COLOR_LERP_PS" "0..1" // STATIC: "PACKED_INTERPOLATOR" "0..1" // STATIC: "DISTANCEALPHA" "0..1" // STATIC: "SOFTEDGES" "0..1" // STATIC: "OUTLINE" "0..1" // SKIP: ( $DISTANCEALPHA == 0 ) && ( $SOFTEDGES || $OUTLINE ) // SKIP: $DISTANCEALPHA && $DUALSEQUENCE // SKIP: $DISTANCEALPHA && ( $MAXLUMFRAMEBLEND2 || $MAXLUMFRAMEBLEND1 ) // SKIP: ( $DUALSEQUENCE == 0 ) && ( $SEQUENCE_BLEND_MODE != 0 ) // SKIP: $INVERSEDEPTHBLEND && !$DEPTHBLEND [XBOX] // 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" float4 g_Parameters : register( c0 ); #define fAdditiveBlendWeight g_Parameters.x #define fOverbrightFactor g_Parameters.y #define fAdditiveSelfBlendWeight g_Parameters.z float g_flMod2xIdentity : register( c1 ); float4 g_DepthFeatheringConstants : register( c2 ); float4 g_FogParams : register( c3 ); float3 g_EyePos : register( c4 ); float3 g_vColor0 : register( c5 ); float3 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.5 #define EDGESOFTNESS_END 0.425 #define OUTLINECOLOR float4( 0, 1, 0, 1 ) #define OUTLINESTART0 0.2 #define OUTLINESTART1 0.3 #define OUTLINEEND0 0.49 #define OUTLINEEND1 0.6 #else float4 g_vecOutlineColor : register( c7 ); #define OUTLINECOLOR ( g_vecOutlineColor * i.vecOutlineTint ) float4 g_vecOutlineControl : register( c8 ); #define OUTLINESTART0 ( g_vecOutlineControl.x ) #define OUTLINESTART1 ( g_vecOutlineControl.y ) #define OUTLINEEND0 ( g_vecOutlineControl.z ) #define OUTLINEEND1 ( g_vecOutlineControl.w ) float4 g_vecEdgeControl : register( c9 ); #define EDGESOFTNESS_START ( g_vecEdgeControl.x ) #define EDGESOFTNESS_END ( g_vecEdgeControl.y ) #endif float4 main( PS_INPUT i ) : COLOR { // Sample frames from textures float4 baseTex0 = tex2Dsrgb( BaseTextureSampler, i.texCoord0_1.xy ); float4 baseTex1; float4 result = baseTex0; float4 vVertexColor; #if ( PACKED_INTERPOLATOR ) { vVertexColor.rgba = i.texCoord0_1.zzzw; } #else { vVertexColor.rgba = i.argbcolor.rgba; baseTex1 = tex2Dsrgb( 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, i.blendfactor0.x ); #endif #if ( MAXLUMFRAMEBLEND1 ) { // Blend between animation frames based upon max luminance float lum0 = dot( float3(.3, .59, .11), baseTex0.rgb * (1-i.blendfactor0.x)); float lum1 = dot( float3(.3, .59, .11), baseTex1.rgb * 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, i.blendfactor0 ) + dot( baseTex1, i.blendfactor1 ); } #endif if ( DISTANCEALPHA ) { float flOrigAlpha = result.a; if ( SOFTEDGES ) { result.a = smoothstep( EDGESOFTNESS_END, EDGESOFTNESS_START, result.a ); } else { if ( result.a < 0.5f ) result = 0; } if ( OUTLINE ) { result.rgb *= vVertexColor; // 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 = tex2Dsrgb( BaseTextureSampler, i.vSeq2TexCoord0_1.xy ); baseTex1 = tex2Dsrgb( BaseTextureSampler, i.vSeq2TexCoord0_1.wz ); // Blend by default (may override with bMaxLumFrameBlend2) float4 rgb2 = lerp( baseTex0, baseTex1, i.blendfactor0.z ); #if ( MAXLUMFRAMEBLEND2 ) { // blend between animation frames based upon max luminance float tlum0 = dot( float3(.3, .59, .11), baseTex0.rgb * (1-i.blendfactor0.x)); float tlum1 = dot( float3(.3, .59, .11), baseTex1.rgb * i.blendfactor0.x); if ( tlum0 > tlum1 ) rgb2 = baseTex0; else rgb2 = baseTex1; } #endif #if ( SEQUENCE_BLEND_MODE == COMBINE_MODE_AVERAGE ) { result = 0.5 * ( 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 = tex2Dsrgb( ColorRampSampler, float2( result.r, result.g ) ); } #endif // Overbright result.rgb *= fOverbrightFactor; //Soft Particles FTW #if (DEPTHBLEND == 1) #if defined( REVERSE_DEPTH_ON_X360 ) float fDepthBlend = DepthFeathering( DepthSampler, i.vScreenPos_ReverseZ.xy / i.vScreenPos_ReverseZ.w, i.vScreenPos_ReverseZ.z, i.vScreenPos_ReverseZ.w, g_DepthFeatheringConstants ); #else float fDepthBlend = DepthFeathering( DepthSampler, i.vScreenPos.xy / i.vScreenPos.w, i.vScreenPos.z, i.vScreenPos.w, g_DepthFeatheringConstants ); #endif #if (INVERSEDEPTHBLEND == 1) fDepthBlend = 1.0f - 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 * tex2Dsrgb( BaseTextureSampler, i.texCoord2 ); } #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( ( float3 )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 #if ( MOD2X ) { // Blend towards a unity multiply as alpha gets closer to zero result.rgb = lerp( ( float3 )g_flMod2xIdentity, result.rgb, result.a ); // Don't tonemap scale since we are multiplying by what is already in the framebuffer. return FinalOutput( result, 0, PIXEL_FOG_TYPE_NONE, TONEMAP_SCALE_NONE ); } #else { return FinalOutput( result, 0, PIXEL_FOG_TYPE_NONE, TONEMAP_SCALE_LINEAR ); } #endif }