aboutsummaryrefslogtreecommitdiff
path: root/mp/src/materialsystem/stdshaders/common_ps_fxc.h
diff options
context:
space:
mode:
authorJoe Ludwig <[email protected]>2013-07-17 18:26:59 -0700
committerJoe Ludwig <[email protected]>2013-07-17 18:26:59 -0700
commite16ea21dc8a710237ade8413207f58d403c616a3 (patch)
tree85dcfbda9881e4e022dedafefbc2727e2fd2aa59 /mp/src/materialsystem/stdshaders/common_ps_fxc.h
parentMerge pull request #36 from AnAkIn1/fogplayerparams_fix (diff)
downloadsource-sdk-2013-e16ea21dc8a710237ade8413207f58d403c616a3.tar.xz
source-sdk-2013-e16ea21dc8a710237ade8413207f58d403c616a3.zip
* Added support for building shaders in your mod
* Added nav mesh support * fixed many warnings and misc bugs * Fixed the create*projects scripts in mp * Added a bunch of stuff to .gitignore
Diffstat (limited to 'mp/src/materialsystem/stdshaders/common_ps_fxc.h')
-rw-r--r--mp/src/materialsystem/stdshaders/common_ps_fxc.h804
1 files changed, 804 insertions, 0 deletions
diff --git a/mp/src/materialsystem/stdshaders/common_ps_fxc.h b/mp/src/materialsystem/stdshaders/common_ps_fxc.h
new file mode 100644
index 00000000..d4a47ea5
--- /dev/null
+++ b/mp/src/materialsystem/stdshaders/common_ps_fxc.h
@@ -0,0 +1,804 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Common pixel shader code
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#ifndef COMMON_PS_FXC_H_
+#define COMMON_PS_FXC_H_
+
+#include "common_fxc.h"
+
+// Put global skip commands here. . make sure and check that the appropriate vars are defined
+// so these aren't used on the wrong shaders!
+
+// --------------------------------------------------------------------------------
+// HDR should never be enabled if we don't aren't running in float or integer HDR mode.
+// SKIP: defined $HDRTYPE && defined $HDRENABLED && !$HDRTYPE && $HDRENABLED
+// --------------------------------------------------------------------------------
+// We don't ever write water fog to dest alpha if we aren't doing water fog.
+// SKIP: defined $PIXELFOGTYPE && defined $WRITEWATERFOGTODESTALPHA && ( $PIXELFOGTYPE != 1 ) && $WRITEWATERFOGTODESTALPHA
+// --------------------------------------------------------------------------------
+// We don't need fog in the pixel shader if we aren't in float fog mode2
+// NOSKIP: defined $HDRTYPE && defined $HDRENABLED && defined $PIXELFOGTYPE && $HDRTYPE != HDR_TYPE_FLOAT && $FOGTYPE != 0
+// --------------------------------------------------------------------------------
+// We don't do HDR and LIGHTING_PREVIEW at the same time since it's running LDR in hammer.
+// SKIP: defined $LIGHTING_PREVIEW && defined $HDRTYPE && $LIGHTING_PREVIEW && $HDRTYPE != 0
+// --------------------------------------------------------------------------------
+// Ditch all fastpath attempts if we are doing LIGHTING_PREVIEW.
+// SKIP: defined $LIGHTING_PREVIEW && defined $FASTPATHENVMAPTINT && $LIGHTING_PREVIEW && $FASTPATHENVMAPTINT
+// SKIP: defined $LIGHTING_PREVIEW && defined $FASTPATHENVMAPCONTRAST && $LIGHTING_PREVIEW && $FASTPATHENVMAPCONTRAST
+// SKIP: defined $LIGHTING_PREVIEW && defined $FASTPATH && $LIGHTING_PREVIEW && $FASTPATH
+// --------------------------------------------------------------------------------
+// Ditch flashlight depth when flashlight is disabled
+// SKIP: ($FLASHLIGHT || $FLASHLIGHTSHADOWS) && $LIGHTING_PREVIEW
+// --------------------------------------------------------------------------------
+
+// System defined pixel shader constants
+
+#if defined( _X360 )
+const bool g_bHighQualityShadows : register( b0 );
+#endif
+
+// NOTE: w == 1.0f / (Dest alpha compressed depth range).
+const float4 g_LinearFogColor : register( c29 );
+#define OO_DESTALPHA_DEPTH_RANGE (g_LinearFogColor.w)
+
+// Linear and gamma light scale values
+const float4 cLightScale : register( c30 );
+#define LINEAR_LIGHT_SCALE (cLightScale.x)
+#define LIGHT_MAP_SCALE (cLightScale.y)
+#define ENV_MAP_SCALE (cLightScale.z)
+#define GAMMA_LIGHT_SCALE (cLightScale.w)
+
+// Flashlight constants
+#if defined(SHADER_MODEL_PS_2_0) || defined(SHADER_MODEL_PS_2_B) || defined(SHADER_MODEL_PS_3_0)
+ const float4 cFlashlightColor : register( c28 );
+ const float4 cFlashlightScreenScale : register( c31 ); // .zw are currently unused
+ #define flFlashlightNoLambertValue cFlashlightColor.w // This is either 0.0 or 2.0
+#endif
+
+#define HDR_INPUT_MAP_SCALE 16.0f
+
+#define TONEMAP_SCALE_NONE 0
+#define TONEMAP_SCALE_LINEAR 1
+#define TONEMAP_SCALE_GAMMA 2
+
+#define PIXEL_FOG_TYPE_NONE -1 //MATERIAL_FOG_NONE is handled by PIXEL_FOG_TYPE_RANGE, this is for explicitly disabling fog in the shader
+#define PIXEL_FOG_TYPE_RANGE 0 //range+none packed together in ps2b. Simply none in ps20 (instruction limits)
+#define PIXEL_FOG_TYPE_HEIGHT 1
+
+// If you change these, make the corresponding change in hardwareconfig.cpp
+#define NVIDIA_PCF_POISSON 0
+#define ATI_NOPCF 1
+#define ATI_NO_PCF_FETCH4 2
+
+struct LPREVIEW_PS_OUT
+{
+ float4 color : COLOR0;
+ float4 normal : COLOR1;
+ float4 position : COLOR2;
+ float4 flags : COLOR3;
+};
+
+/*
+// unused
+HALF Luminance( HALF3 color )
+{
+ return dot( color, HALF3( HALF_CONSTANT(0.30f), HALF_CONSTANT(0.59f), HALF_CONSTANT(0.11f) ) );
+}
+*/
+
+/*
+// unused
+HALF LuminanceScaled( HALF3 color )
+{
+ return dot( color, HALF3( HALF_CONSTANT(0.30f) / MAX_HDR_OVERBRIGHT, HALF_CONSTANT(0.59f) / MAX_HDR_OVERBRIGHT, HALF_CONSTANT(0.11f) / MAX_HDR_OVERBRIGHT ) );
+}
+*/
+
+/*
+// unused
+HALF AvgColor( HALF3 color )
+{
+ return dot( color, HALF3( HALF_CONSTANT(0.33333f), HALF_CONSTANT(0.33333f), HALF_CONSTANT(0.33333f) ) );
+}
+*/
+
+/*
+// unused
+HALF4 DiffuseBump( sampler lightmapSampler,
+ float2 lightmapTexCoord1,
+ float2 lightmapTexCoord2,
+ float2 lightmapTexCoord3,
+ HALF3 normal )
+{
+ HALF3 lightmapColor1 = tex2D( lightmapSampler, lightmapTexCoord1 );
+ HALF3 lightmapColor2 = tex2D( lightmapSampler, lightmapTexCoord2 );
+ HALF3 lightmapColor3 = tex2D( lightmapSampler, lightmapTexCoord3 );
+
+ HALF3 diffuseLighting;
+ diffuseLighting = saturate( dot( normal, bumpBasis[0] ) ) * lightmapColor1 +
+ saturate( dot( normal, bumpBasis[1] ) ) * lightmapColor2 +
+ saturate( dot( normal, bumpBasis[2] ) ) * lightmapColor3;
+
+ return HALF4( diffuseLighting, LuminanceScaled( diffuseLighting ) );
+}
+*/
+
+
+/*
+// unused
+HALF Fresnel( HALF3 normal,
+ HALF3 eye,
+ HALF2 scaleBias )
+{
+ HALF fresnel = HALF_CONSTANT(1.0f) - dot( normal, eye );
+ fresnel = pow( fresnel, HALF_CONSTANT(5.0f) );
+
+ return fresnel * scaleBias.x + scaleBias.y;
+}
+*/
+
+/*
+// unused
+HALF4 GetNormal( sampler normalSampler,
+ float2 normalTexCoord )
+{
+ HALF4 normal = tex2D( normalSampler, normalTexCoord );
+ normal.rgb = HALF_CONSTANT(2.0f) * normal.rgb - HALF_CONSTANT(1.0f);
+
+ return normal;
+}
+*/
+
+// Needs to match NormalDecodeMode_t enum in imaterialsystem.h
+#define NORM_DECODE_NONE 0
+#define NORM_DECODE_ATI2N 1
+#define NORM_DECODE_ATI2N_ALPHA 2
+
+float4 DecompressNormal( sampler NormalSampler, float2 tc, int nDecompressionMode, sampler AlphaSampler )
+{
+ float4 normalTexel = tex2D( NormalSampler, tc );
+ float4 result;
+
+ if ( nDecompressionMode == NORM_DECODE_NONE )
+ {
+ result = float4(normalTexel.xyz * 2.0f - 1.0f, normalTexel.a );
+ }
+ else if ( nDecompressionMode == NORM_DECODE_ATI2N )
+ {
+ result.xy = normalTexel.xy * 2.0f - 1.0f;
+ result.z = sqrt( 1.0f - dot(result.xy, result.xy) );
+ result.a = 1.0f;
+ }
+ else // ATI2N plus ATI1N for alpha
+ {
+ result.xy = normalTexel.xy * 2.0f - 1.0f;
+ result.z = sqrt( 1.0f - dot(result.xy, result.xy) );
+ result.a = tex2D( AlphaSampler, tc ).x; // Note that this comes in on the X channel
+ }
+
+ return result;
+}
+
+float4 DecompressNormal( sampler NormalSampler, float2 tc, int nDecompressionMode )
+{
+ return DecompressNormal( NormalSampler, tc, nDecompressionMode, NormalSampler );
+}
+
+
+HALF3 NormalizeWithCubemap( sampler normalizeSampler, HALF3 input )
+{
+// return texCUBE( normalizeSampler, input ) * 2.0f - 1.0f;
+ return texCUBE( normalizeSampler, input );
+}
+
+/*
+HALF4 EnvReflect( sampler envmapSampler,
+ sampler normalizeSampler,
+ HALF3 normal,
+ float3 eye,
+ HALF2 fresnelScaleBias )
+{
+ HALF3 normEye = NormalizeWithCubemap( normalizeSampler, eye );
+ HALF fresnel = Fresnel( normal, normEye, fresnelScaleBias );
+ HALF3 reflect = CalcReflectionVectorUnnormalized( normal, eye );
+ return texCUBE( envmapSampler, reflect );
+}
+*/
+
+float CalcWaterFogAlpha( const float flWaterZ, const float flEyePosZ, const float flWorldPosZ, const float flProjPosZ, const float flFogOORange )
+{
+// float flDepthFromWater = flWaterZ - flWorldPosZ + 2.0f; // hackity hack . .this is for the DF_FUDGE_UP in view_scene.cpp
+ float flDepthFromWater = flWaterZ - flWorldPosZ;
+
+ // if flDepthFromWater < 0, then set it to 0
+ // This is the equivalent of moving the vert to the water surface if it's above the water surface
+ // We'll do this with the saturate at the end instead.
+// flDepthFromWater = max( 0.0f, flDepthFromWater );
+
+ // Calculate the ratio of water fog to regular fog (ie. how much of the distance from the viewer
+ // to the vert is actually underwater.
+ float flDepthFromEye = flEyePosZ - flWorldPosZ;
+ float f = saturate(flDepthFromWater * (1.0/flDepthFromEye));
+
+ // $tmp.w is now the distance that we see through water.
+ return saturate(f * flProjPosZ * flFogOORange);
+}
+
+float CalcRangeFog( const float flProjPosZ, const float flFogStartOverRange, const float flFogMaxDensity, const float flFogOORange )
+{
+#if !(defined(SHADER_MODEL_PS_1_1) || defined(SHADER_MODEL_PS_1_4) || defined(SHADER_MODEL_PS_2_0)) //Minimum requirement of ps2b
+ return saturate( min( flFogMaxDensity, (flProjPosZ * flFogOORange) - flFogStartOverRange ) );
+#else
+ return 0.0f; //ps20 shaders will never have range fog enabled because too many ran out of slots.
+#endif
+}
+
+float CalcPixelFogFactor( int iPIXELFOGTYPE, const float4 fogParams, const float flEyePosZ, const float flWorldPosZ, const float flProjPosZ )
+{
+ float retVal;
+ if ( iPIXELFOGTYPE == PIXEL_FOG_TYPE_NONE )
+ {
+ retVal = 0.0f;
+ }
+ if ( iPIXELFOGTYPE == PIXEL_FOG_TYPE_RANGE ) //range fog, or no fog depending on fog parameters
+ {
+ retVal = CalcRangeFog( flProjPosZ, fogParams.x, fogParams.z, fogParams.w );
+ }
+ else if ( iPIXELFOGTYPE == PIXEL_FOG_TYPE_HEIGHT ) //height fog
+ {
+ retVal = CalcWaterFogAlpha( fogParams.y, flEyePosZ, flWorldPosZ, flProjPosZ, fogParams.w );
+ }
+
+ return retVal;
+}
+
+//g_FogParams not defined by default, but this is the same layout for every shader that does define it
+#define g_FogEndOverRange g_FogParams.x
+#define g_WaterZ g_FogParams.y
+#define g_FogMaxDensity g_FogParams.z
+#define g_FogOORange g_FogParams.w
+
+float3 BlendPixelFog( const float3 vShaderColor, float pixelFogFactor, const float3 vFogColor, const int iPIXELFOGTYPE )
+{
+ if( iPIXELFOGTYPE == PIXEL_FOG_TYPE_RANGE ) //either range fog or no fog depending on fog parameters and whether this is ps20 or ps2b
+ {
+# if !(defined(SHADER_MODEL_PS_1_1) || defined(SHADER_MODEL_PS_1_4) || defined(SHADER_MODEL_PS_2_0)) //Minimum requirement of ps2b
+ pixelFogFactor = saturate( pixelFogFactor );
+ return lerp( vShaderColor.rgb, vFogColor.rgb, pixelFogFactor * pixelFogFactor ); //squaring the factor will get the middle range mixing closer to hardware fog
+# else
+ return vShaderColor;
+# endif
+ }
+ else if( iPIXELFOGTYPE == PIXEL_FOG_TYPE_HEIGHT )
+ {
+ return lerp( vShaderColor.rgb, vFogColor.rgb, saturate( pixelFogFactor ) );
+ }
+ else if( iPIXELFOGTYPE == PIXEL_FOG_TYPE_NONE )
+ {
+ return vShaderColor;
+ }
+}
+
+
+#if ((defined(SHADER_MODEL_PS_2_B) || defined(SHADER_MODEL_PS_3_0)) && ( CONVERT_TO_SRGB != 0 ) )
+sampler1D GammaTableSampler : register( s15 );
+
+float3 SRGBOutput( const float3 vShaderColor )
+{
+ //On ps2b capable hardware we always have the linear->gamma conversion table texture in sampler s15.
+ float3 result;
+ result.r = tex1D( GammaTableSampler, vShaderColor.r ).r;
+ result.g = tex1D( GammaTableSampler, vShaderColor.g ).r;
+ result.b = tex1D( GammaTableSampler, vShaderColor.b ).r;
+ return result;
+}
+
+#else
+
+float3 SRGBOutput( const float3 vShaderColor )
+{
+ return vShaderColor; //ps 1.1, 1.4, and 2.0 never do srgb conversion in the pixel shader
+}
+
+#endif
+
+
+float SoftParticleDepth( float flDepth )
+{
+ return flDepth * OO_DESTALPHA_DEPTH_RANGE;
+}
+
+
+float DepthToDestAlpha( const float flProjZ )
+{
+#if !(defined(SHADER_MODEL_PS_1_1) || defined(SHADER_MODEL_PS_1_4) || defined(SHADER_MODEL_PS_2_0)) //Minimum requirement of ps2b
+ return SoftParticleDepth( flProjZ );
+#else
+ return 1.0f;
+#endif
+}
+
+
+float4 FinalOutput( const float4 vShaderColor, float pixelFogFactor, const int iPIXELFOGTYPE, const int iTONEMAP_SCALE_TYPE, const bool bWriteDepthToDestAlpha = false, const float flProjZ = 1.0f )
+{
+ float4 result;
+ if( iTONEMAP_SCALE_TYPE == TONEMAP_SCALE_LINEAR )
+ {
+ result.rgb = vShaderColor.rgb * LINEAR_LIGHT_SCALE;
+ }
+ else if( iTONEMAP_SCALE_TYPE == TONEMAP_SCALE_GAMMA )
+ {
+ result.rgb = vShaderColor.rgb * GAMMA_LIGHT_SCALE;
+ }
+ else if( iTONEMAP_SCALE_TYPE == TONEMAP_SCALE_NONE )
+ {
+ result.rgb = vShaderColor.rgb;
+ }
+
+ if( bWriteDepthToDestAlpha )
+ result.a = DepthToDestAlpha( flProjZ );
+ else
+ result.a = vShaderColor.a;
+
+ result.rgb = BlendPixelFog( result.rgb, pixelFogFactor, g_LinearFogColor.rgb, iPIXELFOGTYPE );
+
+#if !(defined(SHADER_MODEL_PS_1_1) || defined(SHADER_MODEL_PS_1_4) || defined(SHADER_MODEL_PS_2_0)) //Minimum requirement of ps2b
+ result.rgb = SRGBOutput( result.rgb ); //SRGB in pixel shader conversion
+#endif
+
+ return result;
+}
+
+LPREVIEW_PS_OUT FinalOutput( const LPREVIEW_PS_OUT vShaderColor, float pixelFogFactor, const int iPIXELFOGTYPE, const int iTONEMAP_SCALE_TYPE )
+{
+ LPREVIEW_PS_OUT result;
+ result.color = FinalOutput( vShaderColor.color, pixelFogFactor, iPIXELFOGTYPE, iTONEMAP_SCALE_TYPE );
+ result.normal.rgb = SRGBOutput( vShaderColor.normal.rgb );
+ result.normal.a = vShaderColor.normal.a;
+
+ result.position.rgb = SRGBOutput( vShaderColor.position.rgb );
+ result.position.a = vShaderColor.position.a;
+
+ result.flags.rgb = SRGBOutput( vShaderColor.flags.rgb );
+ result.flags.a = vShaderColor.flags.a;
+
+ return result;
+}
+
+
+
+
+float RemapValClamped( float val, float A, float B, float C, float D)
+{
+ float cVal = (val - A) / (B - A);
+ cVal = saturate( cVal );
+
+ return C + (D - C) * cVal;
+}
+
+
+//===================================================================================//
+// This is based on Natasha Tatarchuk's Parallax Occlusion Mapping (ATI)
+//===================================================================================//
+// INPUT:
+// inTexCoord:
+// the texcoord for the height/displacement map before parallaxing
+//
+// vParallax:
+// Compute initial parallax displacement direction:
+// float2 vParallaxDirection = normalize( vViewTS.xy );
+// float fLength = length( vViewTS );
+// float fParallaxLength = sqrt( fLength * fLength - vViewTS.z * vViewTS.z ) / vViewTS.z;
+// Out.vParallax = vParallaxDirection * fParallaxLength * fProjectedBumpHeight;
+//
+// vNormal:
+// tangent space normal
+//
+// vViewW:
+// float3 vViewW = /*normalize*/(mul( matViewInverse, float4( 0, 0, 0, 1)) - inPosition );
+//
+// OUTPUT:
+// the new texcoord after parallaxing
+float2 CalcParallaxedTexCoord( float2 inTexCoord, float2 vParallax, float3 vNormal,
+ float3 vViewW, sampler HeightMapSampler )
+{
+ const int nMinSamples = 8;
+ const int nMaxSamples = 50;
+
+ // Normalize the incoming view vector to avoid artifacts:
+// vView = normalize( vView );
+ vViewW = normalize( vViewW );
+// vLight = normalize( vLight );
+
+ // Change the number of samples per ray depending on the viewing angle
+ // for the surface. Oblique angles require smaller step sizes to achieve
+ // more accurate precision
+ int nNumSteps = (int) lerp( nMaxSamples, nMinSamples, dot( vViewW, vNormal ) );
+
+ float4 cResultColor = float4( 0, 0, 0, 1 );
+
+ //===============================================//
+ // Parallax occlusion mapping offset computation //
+ //===============================================//
+ float fCurrHeight = 0.0;
+ float fStepSize = 1.0 / (float) nNumSteps;
+ float fPrevHeight = 1.0;
+ float fNextHeight = 0.0;
+
+ int nStepIndex = 0;
+// bool bCondition = true;
+
+ float2 dx = ddx( inTexCoord );
+ float2 dy = ddy( inTexCoord );
+
+ float2 vTexOffsetPerStep = fStepSize * vParallax;
+
+ float2 vTexCurrentOffset = inTexCoord;
+ float fCurrentBound = 1.0;
+
+ float x = 0;
+ float y = 0;
+ float xh = 0;
+ float yh = 0;
+
+ float2 texOffset2 = 0;
+
+ bool bCondition = true;
+ while ( bCondition == true && nStepIndex < nNumSteps )
+ {
+ vTexCurrentOffset -= vTexOffsetPerStep;
+
+ fCurrHeight = tex2Dgrad( HeightMapSampler, vTexCurrentOffset, dx, dy ).r;
+
+ fCurrentBound -= fStepSize;
+
+ if ( fCurrHeight > fCurrentBound )
+ {
+ x = fCurrentBound;
+ y = fCurrentBound + fStepSize;
+ xh = fCurrHeight;
+ yh = fPrevHeight;
+
+ texOffset2 = vTexCurrentOffset - vTexOffsetPerStep;
+
+ bCondition = false;
+ }
+ else
+ {
+ nStepIndex++;
+ fPrevHeight = fCurrHeight;
+ }
+
+ } // End of while ( bCondition == true && nStepIndex > -1 )#else
+
+ fCurrentBound -= fStepSize;
+
+ float fParallaxAmount;
+ float numerator = (x * (y - yh) - y * (x - xh));
+ float denomenator = ((y - yh) - (x - xh));
+ // avoid NaN generation
+ if( ( numerator == 0.0f ) && ( denomenator == 0.0f ) )
+ {
+ fParallaxAmount = 0.0f;
+ }
+ else
+ {
+ fParallaxAmount = numerator / denomenator;
+ }
+
+ float2 vParallaxOffset = vParallax * (1 - fParallaxAmount );
+
+ // Sample the height at the next possible step:
+ fNextHeight = tex2Dgrad( HeightMapSampler, texOffset2, dx, dy ).r;
+
+ // Original offset:
+ float2 texSampleBase = inTexCoord - vParallaxOffset;
+
+ return texSampleBase;
+
+#if 0
+ cResultColor.rgb = ComputeDiffuseColor( texSampleBase, vLight );
+
+ float fBound = 1.0 - fStepSize * nStepIndex;
+ if ( fNextHeight < fCurrentBound )
+// if( 0 )
+ {
+ //void DoIteration( in float2 vParallaxJittered, in float3 vLight, inout float4 cResultColor )
+ //cResultColor.rgb = float3(1,0,0);
+ DoIteration( vParallax + vPixelSize, vLight, fStepSize, inTexCoord, nStepIndex, dx, dy, fBound, cResultColor );
+ DoIteration( vParallax - vPixelSize, vLight, fStepSize, inTexCoord, nStepIndex, dx, dy, fBound, cResultColor );
+ DoIteration( vParallax + float2( -vPixelSize.x, vPixelSize.y ), vLight, fStepSize, inTexCoord, nStepIndex, dx, dy, fBound, cResultColor );
+ DoIteration( vParallax + float2( vPixelSize.x, -vPixelSize.y ), vLight, fStepSize, inTexCoord, nStepIndex, dx, dy, fBound, cResultColor );
+
+ cResultColor.rgb /= 5;
+// cResultColor.rgb = float3( 1.0f, 0.0f, 0.0f );
+ } // End of if ( fNextHeight < fCurrentBound )
+
+#if DOSHADOWS
+ {
+ //============================================//
+ // Soft shadow and self-occlusion computation //
+ //============================================//
+ // Compute the blurry shadows (note that this computation takes into
+ // account self-occlusion for shadow computation):
+ float sh0 = tex2D( sNormalMap, texSampleBase).w;
+ float shA = (tex2D( sNormalMap, texSampleBase + inXY * 0.88 ).w - sh0 - 0.88 ) * 1 * fShadowSoftening;
+ float sh9 = (tex2D( sNormalMap, texSampleBase + inXY * 0.77 ).w - sh0 - 0.77 ) * 2 * fShadowSoftening;
+ float sh8 = (tex2D( sNormalMap, texSampleBase + inXY * 0.66 ).w - sh0 - 0.66 ) * 4 * fShadowSoftening;
+ float sh7 = (tex2D( sNormalMap, texSampleBase + inXY * 0.55 ).w - sh0 - 0.55 ) * 6 * fShadowSoftening;
+ float sh6 = (tex2D( sNormalMap, texSampleBase + inXY * 0.44 ).w - sh0 - 0.44 ) * 8 * fShadowSoftening;
+ float sh5 = (tex2D( sNormalMap, texSampleBase + inXY * 0.33 ).w - sh0 - 0.33 ) * 10 * fShadowSoftening;
+ float sh4 = (tex2D( sNormalMap, texSampleBase + inXY * 0.22 ).w - sh0 - 0.22 ) * 12 * fShadowSoftening;
+
+ // Compute the actual shadow strength:
+ float fShadow = 1 - max( max( max( max( max( max( shA, sh9 ), sh8 ), sh7 ), sh6 ), sh5 ), sh4 );
+
+ cResultColor.rgb *= fShadow * 0.6 + 0.4;
+ }
+#endif
+
+ return cResultColor;
+#endif
+}
+
+
+//======================================//
+// HSL Color space conversion routines //
+//======================================//
+
+#define HUE 0
+#define SATURATION 1
+#define LIGHTNESS 2
+
+// Convert from RGB to HSL color space
+float4 RGBtoHSL( float4 inColor )
+{
+ float h, s;
+ float flMax = max( inColor.r, max( inColor.g, inColor.b ) );
+ float flMin = min( inColor.r, min( inColor.g, inColor.b ) );
+
+ float l = (flMax + flMin) / 2.0f;
+
+ if (flMax == flMin) // achromatic case
+ {
+ s = h = 0;
+ }
+ else // chromatic case
+ {
+ // Next, calculate the hue
+ float delta = flMax - flMin;
+
+ // First, calculate the saturation
+ if (l < 0.5f) // If we're in the lower hexcone
+ {
+ s = delta/(flMax + flMin);
+ }
+ else
+ {
+ s = delta/(2 - flMax - flMin);
+ }
+
+ if ( inColor.r == flMax )
+ {
+ h = (inColor.g - inColor.b)/delta; // color between yellow and magenta
+ }
+ else if ( inColor.g == flMax )
+ {
+ h = 2 + (inColor.b - inColor.r)/delta; // color between cyan and yellow
+ }
+ else // blue must be max
+ {
+ h = 4 + (inColor.r - inColor.g)/delta; // color between magenta and cyan
+ }
+
+ h *= 60.0f;
+
+ if (h < 0.0f)
+ {
+ h += 360.0f;
+ }
+
+ h /= 360.0f;
+ }
+
+ return float4 (h, s, l, 1.0f);
+}
+
+float HueToRGB( float v1, float v2, float vH )
+{
+ float fResult = v1;
+
+ vH = fmod (vH + 1.0f, 1.0f);
+
+ if ( ( 6.0f * vH ) < 1.0f )
+ {
+ fResult = ( v1 + ( v2 - v1 ) * 6.0f * vH );
+ }
+ else if ( ( 2.0f * vH ) < 1.0f )
+ {
+ fResult = ( v2 );
+ }
+ else if ( ( 3.0f * vH ) < 2.0f )
+ {
+ fResult = ( v1 + ( v2 - v1 ) * ( ( 2.0f / 3.0f ) - vH ) * 6.0f );
+ }
+
+ return fResult;
+}
+
+// Convert from HSL to RGB color space
+float4 HSLtoRGB( float4 hsl )
+{
+ float r, g, b;
+ float h = hsl[HUE];
+ float s = hsl[SATURATION];
+ float l = hsl[LIGHTNESS];
+
+ if ( s == 0 )
+ {
+ r = g = b = l;
+ }
+ else
+ {
+ float v1, v2;
+
+ if ( l < 0.5f )
+ v2 = l * ( 1.0f + s );
+ else
+ v2 = ( l + s ) - ( s * l );
+
+ v1 = 2 * l - v2;
+
+ r = HueToRGB( v1, v2, h + ( 1.0f / 3.0f ) );
+ g = HueToRGB( v1, v2, h );
+ b = HueToRGB( v1, v2, h - ( 1.0f / 3.0f ) );
+ }
+
+ return float4( r, g, b, 1.0f );
+}
+
+
+// texture combining modes for combining base and detail/basetexture2
+#define TCOMBINE_RGB_EQUALS_BASE_x_DETAILx2 0 // original mode
+#define TCOMBINE_RGB_ADDITIVE 1 // base.rgb+detail.rgb*fblend
+#define TCOMBINE_DETAIL_OVER_BASE 2
+#define TCOMBINE_FADE 3 // straight fade between base and detail.
+#define TCOMBINE_BASE_OVER_DETAIL 4 // use base alpha for blend over detail
+#define TCOMBINE_RGB_ADDITIVE_SELFILLUM 5 // add detail color post lighting
+#define TCOMBINE_RGB_ADDITIVE_SELFILLUM_THRESHOLD_FADE 6
+#define TCOMBINE_MOD2X_SELECT_TWO_PATTERNS 7 // use alpha channel of base to select between mod2x channels in r+a of detail
+#define TCOMBINE_MULTIPLY 8
+#define TCOMBINE_MASK_BASE_BY_DETAIL_ALPHA 9 // use alpha channel of detail to mask base
+#define TCOMBINE_SSBUMP_BUMP 10 // use detail to modulate lighting as an ssbump
+#define TCOMBINE_SSBUMP_NOBUMP 11 // detail is an ssbump but use it as an albedo. shader does the magic here - no user needs to specify mode 11
+
+float4 TextureCombine( float4 baseColor, float4 detailColor, int combine_mode,
+ float fBlendFactor )
+{
+ if ( combine_mode == TCOMBINE_MOD2X_SELECT_TWO_PATTERNS)
+ {
+ float3 dc=lerp(detailColor.r,detailColor.a, baseColor.a);
+ baseColor.rgb*=lerp(float3(1,1,1),2.0*dc,fBlendFactor);
+ }
+ if ( combine_mode == TCOMBINE_RGB_EQUALS_BASE_x_DETAILx2)
+ baseColor.rgb*=lerp(float3(1,1,1),2.0*detailColor.rgb,fBlendFactor);
+ if ( combine_mode == TCOMBINE_RGB_ADDITIVE )
+ baseColor.rgb += fBlendFactor * detailColor.rgb;
+ if ( combine_mode == TCOMBINE_DETAIL_OVER_BASE )
+ {
+ float fblend=fBlendFactor * detailColor.a;
+ baseColor.rgb = lerp( baseColor.rgb, detailColor.rgb, fblend);
+ }
+ if ( combine_mode == TCOMBINE_FADE )
+ {
+ baseColor = lerp( baseColor, detailColor, fBlendFactor);
+ }
+ if ( combine_mode == TCOMBINE_BASE_OVER_DETAIL )
+ {
+ float fblend=fBlendFactor * (1-baseColor.a);
+ baseColor.rgb = lerp( baseColor.rgb, detailColor.rgb, fblend );
+ baseColor.a = detailColor.a;
+ }
+ if ( combine_mode == TCOMBINE_MULTIPLY )
+ {
+ baseColor = lerp( baseColor, baseColor*detailColor, fBlendFactor);
+ }
+
+ if (combine_mode == TCOMBINE_MASK_BASE_BY_DETAIL_ALPHA )
+ {
+ baseColor.a = lerp( baseColor.a, baseColor.a*detailColor.a, fBlendFactor );
+ }
+ if ( combine_mode == TCOMBINE_SSBUMP_NOBUMP )
+ {
+ baseColor.rgb = baseColor.rgb * dot( detailColor.rgb, 2.0/3.0 );
+ }
+ return baseColor;
+}
+
+float3 lerp5(float3 f1, float3 f2, float i1, float i2, float x)
+{
+ return f1+(f2-f1)*(x-i1)/(i2-i1);
+}
+
+float3 TextureCombinePostLighting( float3 lit_baseColor, float4 detailColor, int combine_mode,
+ float fBlendFactor )
+{
+ if ( combine_mode == TCOMBINE_RGB_ADDITIVE_SELFILLUM )
+ lit_baseColor += fBlendFactor * detailColor.rgb;
+ if ( combine_mode == TCOMBINE_RGB_ADDITIVE_SELFILLUM_THRESHOLD_FADE )
+ {
+ // fade in an unusual way - instead of fading out color, remap an increasing band of it from
+ // 0..1
+ //if (fBlendFactor > 0.5)
+ // lit_baseColor += min(1, (1.0/fBlendFactor)*max(0, detailColor.rgb-(1-fBlendFactor) ) );
+ //else
+ // lit_baseColor += 2*fBlendFactor*2*max(0, detailColor.rgb-.5);
+
+ float f = fBlendFactor - 0.5;
+ float fMult = (f >= 0) ? 1.0/fBlendFactor : 4*fBlendFactor;
+ float fAdd = (f >= 0) ? 1.0-fMult : -0.5*fMult;
+ lit_baseColor += saturate(fMult * detailColor.rgb + fAdd);
+ }
+ return lit_baseColor;
+}
+
+//NOTE: On X360. fProjZ is expected to be pre-reversed for cheaper math here in the pixel shader
+float DepthFeathering( sampler DepthSampler, const float2 vScreenPos, float fProjZ, float fProjW, 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
+ {
+ float flFeatheredAlpha;
+ float2 flDepths;
+#define flSceneDepth flDepths.x
+#define flSpriteDepth flDepths.y
+
+# if ( defined( _X360 ) )
+ {
+ //Get depth from the depth texture. Need to sample with the offset of (0.5, 0.5) to fix rounding errors
+ asm {
+ tfetch2D flDepths.x___, vScreenPos, DepthSampler, OffsetX=0.5, OffsetY=0.5, MinFilter=point, MagFilter=point, MipFilter=point
+ };
+
+# if( !defined( REVERSE_DEPTH_ON_X360 ) )
+ flSceneDepth = 1.0f - flSceneDepth;
+# endif
+
+ //get the sprite depth into the same range as the texture depth
+ flSpriteDepth = fProjZ / fProjW;
+
+ //unproject to get at the pre-projection z. This value is much more linear than depth
+ flDepths = vDepthBlendConstants.z / flDepths;
+ flDepths = vDepthBlendConstants.y - flDepths;
+
+ flFeatheredAlpha = flSceneDepth - flSpriteDepth;
+ flFeatheredAlpha *= vDepthBlendConstants.x;
+ flFeatheredAlpha = saturate( flFeatheredAlpha );
+ }
+# else
+ {
+ flSceneDepth = tex2D( DepthSampler, vScreenPos ).a; // PC uses dest alpha of the frame buffer
+ flSpriteDepth = SoftParticleDepth( fProjZ );
+
+ flFeatheredAlpha = abs(flSceneDepth - flSpriteDepth) * vDepthBlendConstants.x;
+ flFeatheredAlpha = max( smoothstep( 0.75f, 1.0f, flSceneDepth ), flFeatheredAlpha ); //as the sprite approaches the edge of our compressed depth space, the math stops working. So as the sprite approaches the far depth, smoothly remove feathering.
+ flFeatheredAlpha = saturate( flFeatheredAlpha );
+ }
+# endif
+
+#undef flSceneDepth
+#undef flSpriteDepth
+
+ return flFeatheredAlpha;
+ }
+# else
+ {
+ return 1.0f;
+ }
+# endif
+}
+
+#endif //#ifndef COMMON_PS_FXC_H_