/* //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/* // ENBSeries effect file
/* // visit https://www.youtube.com/channel/UCTz6il72-ulpQ3vhm5ulkSg?view_as=subscriber
/* // Copyright  KararszKonsol
/* //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/* // MasterEffect KararszKonsol
/* // Coypright  KararsIzKonsol
/* //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



// Shader global descriptions
float Script : STANDARDSGLOBAL
<
  string Script =
           "NoPreview;"
           "LocalConstants;"
           "ShaderDrawType = Custom;"
           "ShaderType = PostProcess;"
>; 

sampler2D rainbowSampler = sampler_state
{
  Texture = textures/defaults/glitter_color.dds;
  MinFilter = LINEAR;  
  MagFilter = LINEAR;
  MipFilter = LINEAR; 
  AddressU = Wrap;
  AddressV = Wrap;
};

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Texture To Texture technique /////////////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

/// Constants ////////////////////////////

float4 texToTexParams0;
float4 texToTexParams1;

////////////////// samplers /////////////////////

///////////////// vertex shader //////////////////

struct vtxOutTexToTex
{
  float4 HPosition  : POSITION;
  float4 baseTC0 : TEXCOORDN;    
  float4 baseTC1 : TEXCOORDN;    
  float4 baseTC2 : TEXCOORDN;    
  float4 baseTC3 : TEXCOORDN;    
  float4 baseTC4 : TEXCOORDN;    
};

vtxOutTexToTex TexToTexVS(vtxIn IN)
{
  vtxOutTexToTex OUT = (vtxOutTexToTex)0; 

  float4 vPos = IN.Position;
  OUT.HPosition = mul(vpMatrix, vPos);  

  OUT.baseTC0.xy = IN.baseTC.xy;
  OUT.baseTC1.xy = IN.baseTC.xy+texToTexParams0.xy;
  OUT.baseTC2.xy = IN.baseTC.xy+texToTexParams0.zw;
  OUT.baseTC3.xy = IN.baseTC.xy+texToTexParams1.xy;
  OUT.baseTC4.xy = IN.baseTC.xy+texToTexParams1.zw; 
  
  return OUT;
}

///////////////// pixel shader //////////////////
pixout TexToTexPS(vtxOutTexToTex IN)
{
  pixout OUT;
  OUT.Color = tex2D(_tex0, IN.baseTC0.xy);    
  return OUT;
}

// With rotated grid sampling (less artifacts). Used for image rescaling
pixout TexToTexSampledPS(vtxOutTexToTex IN)
{
  pixout OUT;

  half4 baseColor0 = tex2D(_tex0, IN.baseTC0.xy);
  half4 baseColor1 = tex2D(_tex0, IN.baseTC1.xy);
  half4 baseColor2 = tex2D(_tex0, IN.baseTC2.xy);
  half4 baseColor3 = tex2D(_tex0, IN.baseTC3.xy);
  half4 baseColor4 = tex2D(_tex0, IN.baseTC4.xy);

  OUT.Color = (baseColor0+baseColor1+baseColor2+baseColor3+baseColor4)*0.2f;
   
  return OUT;
}


// Version for SSAO z-target
pixout TexToTexSampledAOPS(vtxOutTexToTex IN)
{
  pixout OUT;
      
  half4 baseColor0 = tex2D(_tex0, IN.baseTC0.xy);
  half4 baseColor1 = tex2D(_tex0, IN.baseTC1.xy);
  half4 baseColor2 = tex2D(_tex0, IN.baseTC2.xy);
  half4 baseColor3 = tex2D(_tex0, IN.baseTC3.xy);
  half4 baseColor4 = tex2D(_tex0, IN.baseTC4.xy);
  
  // Use max to prevent artifacts.
  OUT.Color = max(baseColor0, max(max(baseColor1.r, baseColor3.r), max(baseColor2.r, baseColor4.r)));
  //OUT.Color = (baseColor0+baseColor1+baseColor2+baseColor3+baseColor4)*0.2f;
   
  return OUT;
}

////////////////// technique /////////////////////

technique TextureToTextureResampledAO
{
  pass p0
  {
    VertexShader = CompileVS TexToTexVS();            
    PixelShader = CompilePS TexToTexSampledAOPS();
    CullMode = None;        
  }
}

technique TextureToTexture
{
  pass p0
  {
    VertexShader = CompileVS TexToTexVS();            
    PixelShader = CompilePS TexToTexPS();
    CullMode = None;        
  }
}

technique TextureToTextureResampled
{
  pass p0
  {
    VertexShader = CompileVS TexToTexVS();            
    PixelShader = CompilePS TexToTexSampledPS();
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Post-Process Anti Aliasing technique ///////////////////////////////////////////////////////////
///	FXAA technique and original code is copyright (C) NVIDIA by Timothy Lottes

/// Specific data ////////////////////////
static const float4 fxaaParams0 = {0.08f, 0.16f, 0.75f, 0.25f};
static const float4 fxaaParams1 = {4.f, 0.05f, 0.125f, 0.0f}; 

/// Constants ////////////////////////////

/// Samplers ////////////////////////////

///////////////// vertex shader //////////////////

struct vtxOutFXAA
{
  float4 HPosition  : POSITION;
  float4 baseTC     : TEXCOORD0;
  float4 baseTC1	: TEXCOORD1;
};

vtxOutFXAA FXAA_VS(vtxIn IN)
{
  vtxOutFXAA OUT = (vtxOutFXAA)0; 

  float4 vPos = IN.Position;
  OUT.HPosition = mul(vpMatrix, vPos);  
  OUT.baseTC.xy = IN.baseTC.xy;
  
  // Output with subpixel offset into wz
  OUT.baseTC1.xy = IN.baseTC.xy - 0.5 * g_VS_ScreenSize.zw;
  OUT.baseTC1.zw = IN.baseTC.xy + 0.5 * g_VS_ScreenSize.zw;

  return OUT;
}

///////////////// pixel shader //////////////////

pixout FXAA_PS(vtxOutFXAA IN)
{
  pixout OUT = (pixout)0;

	// Pixel sizes.
	float2 vPixelSizes = PS_ScreenSize.zw * 2.0;
	
	// Initial sample. Used on early-out.
	float4 cSampleCenter = tex2Dlod(_tex0, float4(IN.baseTC.xy,0,0));
	OUT.Color = cSampleCenter;

	float fLumCenter = cSampleCenter.w;
	float fLumBottom = tex2Dlod(_tex0, float4(IN.baseTC.xy + float2( 0, 1) * vPixelSizes.xy,0,0)).w;
	float fLumRight  = tex2Dlod(_tex0, float4(IN.baseTC.xy + float2( 1, 0) * vPixelSizes.xy,0,0)).w;
	float fLumTop    = tex2Dlod(_tex0, float4(IN.baseTC.xy + float2( 0,-1) * vPixelSizes.xy,0,0)).w;
	float fLumLeft   = tex2Dlod(_tex0, float4(IN.baseTC.xy + float2(-1, 0) * vPixelSizes.xy,0,0)).w;

    float fMaxRange = max(max(fLumTop, fLumLeft), max(fLumRight, max(fLumBottom, fLumCenter)));
    float fMinRange = min(min(fLumTop, fLumLeft), min(fLumRight, min(fLumBottom, fLumCenter)));
    float fRange = fMaxRange - fMinRange;
    
    // Early out.
    if(fRange < max(fxaaParams0.x, fMaxRange * fxaaParams0.y))
		return OUT;
		
	float fLumTopLeft     = tex2Dlod(_tex0, float4(IN.baseTC.xy + float2(-1,-1) * vPixelSizes.xy,0,0)).w;
	float fLumBottomRight = tex2Dlod(_tex0, float4(IN.baseTC.xy + float2( 1, 1) * vPixelSizes.xy,0,0)).w;
	float fLumTopRight	  = tex2Dlod(_tex0, float4(IN.baseTC.xy + float2( 1,-1) * vPixelSizes.xy,0,0)).w;
	float fLumBottomLeft  = tex2Dlod(_tex0, float4(IN.baseTC.xy + float2(-1, 1) * vPixelSizes.xy,0,0)).w;
    
    float fLumTopBottom = fLumTop  + fLumBottom;
    float fLumLeftRight = fLumLeft + fLumRight;
    float fLumSubPixel = fLumTopBottom + fLumLeftRight;
    
    float fEdgeH1 = (-2.0 * fLumCenter) + fLumTopBottom;
    float fEdgeV1 = (-2.0 * fLumCenter) + fLumLeftRight;

    float fLumTopBottomRight = fLumTopRight + fLumBottomRight;
    float fLumTopLeftRight = fLumTopLeft + fLumTopRight;
    float fEdgeH2 = (-2.0 * fLumRight) + fLumTopBottomRight;
    float fEdgeV2 = (-2.0 * fLumTop) + fLumTopLeftRight;

    float fLumTopBottomLeft = fLumTopLeft + fLumBottomLeft;
    float fLumBottomLeftRight = fLumBottomLeft + fLumBottomRight;
    float fEdgeH4 = (abs(fEdgeH1) * 2.0) + abs(fEdgeH2);
    float fEdgeV4 = (abs(fEdgeV1) * 2.0) + abs(fEdgeV2);
    float fEdgeH3 = (-2.0 * fLumLeft) + fLumTopBottomLeft;
    float fEdgeV3 = (-2.0 * fLumBottom) + fLumBottomLeftRight;
    float fEdgeH = abs(fEdgeH3) + fEdgeH4;
    float fEdgeV = abs(fEdgeV3) + fEdgeV4;

    float fBlendSubPixel = fLumTopBottomLeft + fLumTopBottomRight; 
    float fLengthSign = vPixelSizes.x;
    bool bHorizontalSpan = fEdgeH >= fEdgeV;
    float fSubPixelA = fLumSubPixel * 2.0 + fBlendSubPixel; 

    if(!bHorizontalSpan) fLumTop = fLumLeft; 
    if(!bHorizontalSpan) fLumBottom = fLumRight;
    if(bHorizontalSpan) fLengthSign = vPixelSizes.y;
    float fSubPixelB = (fSubPixelA * (1.0/12.0)) - fLumCenter;	
        
    float fGradientN = fLumTop - fLumCenter;
    float fGradientS = fLumBottom - fLumCenter;
    float fLumTopCenter = fLumTop + fLumCenter;
    float fLumBottomCenter = fLumBottom + fLumCenter;
    bool fPairN = abs(fGradientN) >= abs(fGradientS);
    float fGradient = max(abs(fGradientN), abs(fGradientS));
    if(fPairN) fLengthSign = -fLengthSign;
    float fSubPixelC = saturate(abs(fSubPixelB) * (1.0 / fRange));
    
    float2 vPositionB;
    vPositionB.x = IN.baseTC.x;
    vPositionB.y = IN.baseTC.y;
    float2 vOffsetNP;
    vOffsetNP.x = (!bHorizontalSpan) ? 0.0 : vPixelSizes.x;
    vOffsetNP.y = ( bHorizontalSpan) ? 0.0 : vPixelSizes.y;
    if(!bHorizontalSpan) vPositionB.x += fLengthSign * 0.5;
    if( bHorizontalSpan) vPositionB.y += fLengthSign * 0.5;
    
    float2 vPositionN;
    vPositionN.x = vPositionB.x - vOffsetNP.x;
    vPositionN.y = vPositionB.y - vOffsetNP.y;
    
    float2 vPositionP;
    vPositionP.x = vPositionB.x + vOffsetNP.x;
    vPositionP.y = vPositionB.y + vOffsetNP.y;
    
    float fSubPixelD = ((-2.0)*fSubPixelC) + 3.0;
    float fLumEndN = tex2Dlod(_tex0, float4(vPositionN,0,0)).w;
    float fLumEndP = tex2Dlod(_tex0, float4(vPositionP,0,0)).w;
    
    float fSubPixelE = (fSubPixelC * fSubPixelC);
    
    if(!fPairN) fLumTopCenter = fLumBottomCenter;
    float fGradientScaled = fGradient * 1.0/4.0;
    float fSubPixelF = fSubPixelD * fSubPixelE;
    bool bLumZero = (fLumCenter - fLumTopCenter * 0.5) < 0.0;
    
    fLumEndN -= fLumTopCenter * 0.5;
    fLumEndP -= fLumTopCenter * 0.5;
    bool bDoneN = abs(fLumEndN) >= fGradientScaled;
    bool bDoneP = abs(fLumEndP) >= fGradientScaled;
    if(!bDoneN) vPositionN.x -= vOffsetNP.x;
    if(!bDoneN) vPositionN.y -= vOffsetNP.y;
    bool bDoneNP = (!bDoneN) || (!bDoneP);
    if(!bDoneP) vPositionP.x += vOffsetNP.x;
    if(!bDoneP) vPositionP.y += vOffsetNP.y;
    
    static const half fSearchScale[11] = {1.0, 1.0, 1.0, 1.0, 1.5, 2.0, 2.0, 2.0, 2.0, 4.0, 8.0};

    #if D3D10
    [unroll]
    #endif
    // Search edges.
    for(int i = 0; i < 11; i++)
    {
        if(!bDoneN) fLumEndN = tex2Dlod(_tex0, float4(vPositionN.xy,0,0)).w;
        if(!bDoneP) fLumEndP = tex2Dlod(_tex0, float4(vPositionP.xy,0,0)).w;
        if(!bDoneN) fLumEndN = fLumEndN - fLumTopCenter * 0.5;
        if(!bDoneP) fLumEndP = fLumEndP - fLumTopCenter * 0.5;
        bDoneN = abs(fLumEndN) >= fGradientScaled;
        bDoneP = abs(fLumEndP) >= fGradientScaled;
        if(!bDoneN) vPositionN.x -= vOffsetNP.x * fSearchScale[i];
        if(!bDoneN) vPositionN.y -= vOffsetNP.y * fSearchScale[i];
        bDoneNP = (!bDoneN) || (!bDoneP);
        if(!bDoneP) vPositionP.x += vOffsetNP.x * fSearchScale[i];
        if(!bDoneP) vPositionP.y += vOffsetNP.y * fSearchScale[i];
    }
                    
    float fDestN = IN.baseTC.x - vPositionN.x;
    float fDestP = vPositionP.x - IN.baseTC.x;
    
    if(!bHorizontalSpan) fDestN = IN.baseTC.y - vPositionN.y;
    if(!bHorizontalSpan) fDestP = vPositionP.y - IN.baseTC.y;
    
    float fSpanLength = (fDestP + fDestN);
    bool bGoodSpanN = (fLumEndN < 0.0) != bLumZero;
    bool bGoodSpanP = (fLumEndP < 0.0) != bLumZero;

    bool bDirectionN = fDestN < fDestP;
    float fDest = min(fDestN, fDestP);
    bool bGoodSpan = bDirectionN ? bGoodSpanN : bGoodSpanP;
    float fSubPixelG = fSubPixelF * fSubPixelF;
    float fPixelOffset = (fDest * (-(1.0/fSpanLength))) + 0.5;
    float fSubPixelH = fSubPixelG * fxaaParams0.z;

    float fPixelOffsetGood = bGoodSpan ? fPixelOffset : 0.0;
    float fPixelOffsetSubpix = max(fPixelOffsetGood, fSubPixelH);
    if(!bHorizontalSpan) IN.baseTC.x += fPixelOffsetSubpix * fLengthSign;
    if( bHorizontalSpan) IN.baseTC.y += fPixelOffsetSubpix * fLengthSign;
    
    OUT.Color = tex2Dlod(_tex0, float4(IN.baseTC.xy,0,0));
        
    return OUT;
}

///////////////// pixel shader //////////////////
pixout FXAAFast_PS(vtxOutFXAA IN)
{
  pixout OUT = (pixout)0;

  const half4 vPixelSizes = PS_ScreenSize.zwzw * half4(4.0, 4.0, 1.0, 1.0);

  // Initial sample. Used on early-out.
  float4 cSampleCenter = tex2Dlod(_tex0, half4(IN.baseTC.xy,0,0));
  OUT.Color = cSampleCenter;

  half4 vDir;
  vDir.y = 0.0;
  half4 fLumTopRight = tex2Dlod(_tex0, half4(IN.baseTC1.zy,0,0));
  fLumTopRight.w += half(1.0 / 384.0);
  vDir.x = -fLumTopRight.w;
  vDir.z = -fLumTopRight.w;
	
  half4 fLumBottomLeft = tex2Dlod(_tex0, half4(IN.baseTC1.xw,0,0));
  vDir.x += fLumBottomLeft.w;
  vDir.z += fLumBottomLeft.w;
  
  half4 fLumTopLeft = tex2Dlod(_tex0, half4(IN.baseTC1.xy,0,0));
  vDir.x -= fLumTopLeft.w;
  vDir.z += fLumTopLeft.w;	
   
  half4 fLumBottomRight = tex2Dlod(_tex0, half4(IN.baseTC1.zw,0,0));
  vDir.x += fLumBottomRight.w;
  vDir.z -= fLumBottomRight.w;
    
  half fLumMin = min(min(fLumTopLeft.w, fLumBottomLeft.w), min(fLumTopRight.w, fLumBottomRight.w));
  half fLumMax = max(max(fLumTopLeft.w, fLumBottomLeft.w), max(fLumTopRight.w, fLumBottomRight.w));
   
  if((max(fLumMax, cSampleCenter.w) - min(fLumMin, cSampleCenter.w)) < max(fxaaParams1.y, fLumMax * fxaaParams1.z))
	return OUT;
	
  half4 vDir1;
  vDir1.xy = normalize(vDir.xyz).xz;
  half fDirAbsMinTimesC = min(abs(vDir1.x), abs(vDir1.y)) * fxaaParams1.x;

  half4 vDir2;
  vDir2.xy = clamp(vDir1.xy / fDirAbsMinTimesC, -2.0h, 2.0h);
  vDir1.zw = IN.baseTC.xy;
  vDir2.zw = IN.baseTC.xy;
  half4 temp1N;
  temp1N.xy = vDir1.zw - vDir1.xy * vPixelSizes.zw;
  
  temp1N = tex2Dlod(_tex0, float4(temp1N.xy,0,0));
  half4 rgby1;
  rgby1.xy = vDir1.zw + vDir1.xy * vPixelSizes.zw;
  
  rgby1 = tex2Dlod(_tex0, float4(rgby1.xy,0,0));
  rgby1 = (temp1N + rgby1) * 0.5;
  
  half4 temp2N;
  temp2N.xy = vDir2.zw - vDir2.xy * vPixelSizes.xy;
  temp2N = tex2Dlod(_tex0, float4(temp2N.xy,0,0));
  
  half4 rgby2;
  rgby2.xy = vDir2.zw + vDir2.xy * vPixelSizes.xy;
  rgby2 = tex2D(_tex0, float4(rgby2.xy,0,0));
  rgby2 = (temp2N + rgby2) * 0.5;
    
  rgby2 = (rgby2 + rgby1) * 0.5;
    
  bool twoTapLt = rgby2.w < fLumMin;
  bool twoTapGt = rgby2.w > fLumMax;
  
  if(twoTapLt || twoTapGt) rgby2 = rgby1;
    
  OUT.Color = rgby2;
 
  return OUT;
}

////////////////// technique /////////////////////

technique FXAA
{
  pass p0
  {        
    CullMode = None;        
    VertexShader = CompileVS FXAA_VS();
	PixelShader = CompilePS FXAA_PS();
  }
}

technique FXAAFast
{ 
  pass p0
  {        
    CullMode = None;  
	VertexShader = CompileVS FXAA_VS();
	PixelShader = CompilePS FXAAFast_PS();
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Clear screen technique //////////////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

/// Constants ////////////////////////////

float4 clrScrParams;

/// Samplers ////////////////////////////
// none

///////////////// vertex shader //////////////////

struct vtxOutClrScr
{
  float4 HPosition  : POSITION;
};

vtxOutClrScr ClearScreenVS(vtxIn IN)
{
  vtxOutClrScr OUT = (vtxOutClrScr)0; 
  OUT.HPosition = mul(vpMatrix, IN.Position);    
  return OUT;
}

///////////////// pixel shader //////////////////
pixout ClearScreenPS(vtxOutClrScr IN)
{
  pixout OUT;  
  OUT.Color = clrScrParams;        
  return OUT;
}

////////////////// technique /////////////////////
technique ClearScreen
{
  pass p0
  {
    VertexShader = CompileVS ClearScreenVS();
    PixelShader = CompilePS ClearScreenPS();    
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Kawase Blur technique //////////////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

/// Constants ////////////////////////////

float4 blurParams0;
float4 blurParams1;

/// Samplers ////////////////////////////

// none
sampler2D blurMap0 : register(s0);

///////////////// vertex shader //////////////////

struct vtxOutKawase
{
  float4 HPosition  : POSITION;
  float2 baseTC0 : TEXCOORDN;    
  float2 baseTC1 : TEXCOORDN;    
  float2 baseTC2 : TEXCOORDN;    
  float2 baseTC3 : TEXCOORDN;    
  float2 baseTC4 : TEXCOORDN;    
};

vtxOutKawase KawaseBlurVS(vtxIn IN)
{
  vtxOutKawase OUT = (vtxOutKawase)0; 

  float4 vPos = IN.Position;
  OUT.HPosition = mul(vpMatrix, vPos);  
  
  OUT.baseTC0.xy = IN.baseTC.xy; // Also sample midle pixel to keep some detail
  OUT.baseTC1.xy = IN.baseTC.xy+blurParams0.xy;
  OUT.baseTC2.xy = IN.baseTC.xy+blurParams0.zw;
  OUT.baseTC3.xy = IN.baseTC.xy+blurParams1.xy;
  OUT.baseTC4.xy = IN.baseTC.xy+blurParams1.zw;

  return OUT;
}

///////////////// pixel shader //////////////////
pixout KawaseBlurPS(vtxOutKawase IN)
{
  pixout OUT;
  
  half4 baseColor0 = tex2D(blurMap0, IN.baseTC0.xy);
  half4 baseColor1 = tex2D(blurMap0, IN.baseTC1.xy);
  half4 baseColor2 = tex2D(blurMap0, IN.baseTC2.xy);
  half4 baseColor3 = tex2D(blurMap0, IN.baseTC3.xy);
  half4 baseColor4 = tex2D(blurMap0, IN.baseTC4.xy);
  
  OUT.Color = (baseColor0+baseColor1+baseColor2+baseColor3+baseColor4)/5.0;        
  
  return OUT;
}

////////////////// technique /////////////////////
technique KawaseBlur
{
  pass p0
  {
    VertexShader = CompileVS KawaseBlurVS();
    PixelShader = CompilePS KawaseBlurPS();
    
    CullMode = Back;        
  }
}

// =================================================================================================
// Technique: GaussBlur/GaussBlurBilinear
// Description: Applies a separatable vertical/horizontal gaussian blur filter
// =================================================================================================

float4 PI_psOffsets[16];
float4 psWeights[16];

struct vtxOutGauss
{
  float4 HPosition : POSITION;
  float2 baseTC : TEXCOORDN;  
  float4 tc0 : TEXCOORDN;    
  float4 tc1 : TEXCOORDN;    
  float4 tc2 : TEXCOORDN;    
  float4 tc3 : TEXCOORDN;   
  float4 tc4 : TEXCOORDN;    
  float4 tc5 : TEXCOORDN;    
  float4 tc6 : TEXCOORDN;    
  float4 tc7 : TEXCOORDN;  
};

struct vtxOutGaussMasked
{
  float4 HPosition : POSITION;
  float4 tc0 : TEXCOORDN;    
  float4 tc1 : TEXCOORDN;    
  float2 tc2 : TEXCOORDN;    
  float2 tc3 : TEXCOORDN;    
  float2 tc4 : TEXCOORDN;    
  float2 tc5 : TEXCOORDN;      
  float2 tc6 : TEXCOORDN;    
  float2 tc7 : TEXCOORDN;    
};

vtxOutGauss GaussBlurBilinearVS(vtxIn IN)
{
  vtxOutGauss OUT = (vtxOutGauss) 0;

  float4 vPos = IN.Position;
  OUT.HPosition = mul(vpMatrix, vPos);  
  
  OUT.baseTC.xy = IN.baseTC.xy;
  
  OUT.tc0.xy = IN.baseTC.xy + PI_psOffsets[0].xy;
  OUT.tc1.xy = IN.baseTC.xy + PI_psOffsets[1].xy;
  OUT.tc2.xy = IN.baseTC.xy + PI_psOffsets[2].xy;
  OUT.tc3.xy = IN.baseTC.xy + PI_psOffsets[3].xy;
  OUT.tc4.xy = IN.baseTC.xy + PI_psOffsets[4].xy;
  OUT.tc5.xy = IN.baseTC.xy + PI_psOffsets[5].xy;
  OUT.tc6.xy = IN.baseTC.xy + PI_psOffsets[6].xy;
  OUT.tc7.xy = IN.baseTC.xy + PI_psOffsets[7].xy;

  #if !%_RT_SAMPLE0
	  // Coordinates for wider bloom blur.
	  half2 fScale = 750.0f * ScrSize.zw * float2(0.75*(ScrSize.x/ScrSize.y), 1.0);

	  OUT.tc0.wz = IN.baseTC.xy + PI_psOffsets[0].xy * fScale;
	  OUT.tc1.wz = IN.baseTC.xy + PI_psOffsets[1].xy * fScale;
	  OUT.tc2.wz = IN.baseTC.xy + PI_psOffsets[2].xy * fScale;
	  OUT.tc3.wz = IN.baseTC.xy + PI_psOffsets[3].xy * fScale;
	  OUT.tc4.wz = IN.baseTC.xy + PI_psOffsets[4].xy * fScale;
	  OUT.tc5.wz = IN.baseTC.xy + PI_psOffsets[5].xy * fScale;
	  OUT.tc6.wz = IN.baseTC.xy + PI_psOffsets[6].xy * fScale;
	  OUT.tc7.wz = IN.baseTC.xy + PI_psOffsets[7].xy * fScale;
  #endif

  return OUT;
}

vtxOutGaussMasked MaskedGaussBlurBilinearVS(vtxIn IN)
{
  vtxOutGaussMasked OUT = (vtxOutGaussMasked) 0;

  float4 vPos = IN.Position;
  OUT.HPosition = mul(vpMatrix, vPos);  
  
  OUT.tc0.xy = IN.baseTC.xy + PI_psOffsets[0].xy;
  OUT.tc1.xy = IN.baseTC.xy + PI_psOffsets[1].xy;
  OUT.tc2.xy = IN.baseTC.xy + PI_psOffsets[2].xy;
  OUT.tc3.xy = IN.baseTC.xy + PI_psOffsets[3].xy;
  OUT.tc4.xy = IN.baseTC.xy + PI_psOffsets[4].xy;
  OUT.tc5.xy = IN.baseTC.xy + PI_psOffsets[5].xy;
  OUT.tc6.xy = IN.baseTC.xy + PI_psOffsets[6].xy;
  OUT.tc7.xy = IN.baseTC.xy + PI_psOffsets[7].xy;

  // output with correct aspect ratio into wz
  OUT.tc0.wz = IN.baseTC.xy;
  OUT.tc1.wz = (IN.baseTC.xy -0.5 ) * float2(0.75*(ScrSize.x/ScrSize.y), 1.0) + 0.5;

  return OUT;
}

pixout GaussBlurBilinearPS(vtxOutGauss IN)
{
  pixout OUT;

  // Alpha channel remains unblurred for skin mask.
  half4 sum = tex2D(_tex0, IN.baseTC.xy);
    
  // Sample taps for blur.
  half4 col = tex2D(_tex0, IN.tc0.xy);  	
  sum = col * (half) psWeights[0].x;  

  col = tex2D(_tex0, IN.tc1.xy);  
  sum += col * (half) psWeights[1].x;  
	
  col = tex2D(_tex0, IN.tc2.xy);  
  sum += col * (half) psWeights[2].x;  

  col = tex2D(_tex0, IN.tc3.xy);  
  sum += col * (half) psWeights[3].x;  

  col = tex2D(_tex0, IN.tc4.xy);  
  sum += col * (half) psWeights[4].x;  
	
  col = tex2D(_tex0, IN.tc5.xy);  
  sum += col * (half) psWeights[5].x;  
	
  col = tex2D(_tex0, IN.tc6.xy);  
  sum += col * (half) psWeights[6].x;  
	
  col = tex2D(_tex0, IN.tc7.xy);  
  sum += col * (half) psWeights[7].x;  
  
  OUT.Color = sum;
  
  #if !%_RT_SAMPLE0
  	  // Second pass, wider blur for bloom
	  col = tex2D(_tex0, IN.tc0.wz);  	
	  sum.rgb += col * (half) psWeights[0].x;  

	  col = tex2D(_tex0, IN.tc1.wz);  
	  sum.rgb += col * (half) psWeights[1].x;  
		
	  col = tex2D(_tex0, IN.tc2.wz);  
	  sum.rgb += col * (half) psWeights[2].x;  

	  col = tex2D(_tex0, IN.tc3.wz);  
	  sum.rgb += col * (half) psWeights[3].x;  

	  col = tex2D(_tex0, IN.tc4.wz);  
	  sum.rgb += col * (half) psWeights[4].x;  
		
	  col = tex2D(_tex0, IN.tc5.wz);  
	  sum.rgb += col * (half) psWeights[5].x;  
		
	  col = tex2D(_tex0, IN.tc6.wz);  
	  sum.rgb += col * (half) psWeights[6].x;  
		
	  col = tex2D(_tex0, IN.tc7.wz);  
	  sum.rgb += col * (half) psWeights[7].x;  
	  
	  OUT.Color.rgb = sum.rgb * 0.5;
  #endif
  
  return OUT;
}

pixout MaskedGaussBlurBilinearPS(vtxOutGaussMasked IN)
{
  pixout OUT;

  half4 sum = 0;
  half4 orig = tex2D(_tex0, IN.tc0.wz);
  half mask = tex2D(_tex1, IN.tc1.wz).x;
  
  half4 col = tex2D(_tex0, IN.tc0.xy);  	
  col = lerp(orig, col, mask);
  sum += col * (half) psWeights[0].x;  

  col = tex2D(_tex0, IN.tc1.xy);  
  col = lerp(orig, col, mask);
  sum += col * (half) psWeights[1].x;  
	
  col = tex2D(_tex0, IN.tc2.xy);  
  col = lerp(orig, col, mask);
  sum += col * (half) psWeights[2].x;  

  col = tex2D(_tex0, IN.tc3.xy);  
  col = lerp(orig, col, mask);
  sum += col * (half) psWeights[3].x;  

  col = tex2D(_tex0, IN.tc4.xy);  
  col = lerp(orig, col, mask);
  sum += col * (half) psWeights[4].x;  
	
  col = tex2D(_tex0, IN.tc5.xy);  
  col = lerp(orig, col, mask);
  sum += col * (half) psWeights[5].x;  
	
  col = tex2D(_tex0, IN.tc6.xy);  
  col = lerp(orig, col, mask);
  sum += col * (half) psWeights[6].x;  
	
  col = tex2D(_tex0, IN.tc7.xy);  
  col = lerp(orig, col, mask);
  sum += col * (half) psWeights[7].x;
  
  OUT.Color = sum;

  return OUT;
}

pixout GaussBlurBilinearEncodedPS(vtxOutGaussMasked IN)
{
  pixout OUT;
      
  half3 sum = 0;
  half3 col = DecodeRGBS( tex2D(_tex0, IN.tc0.xy) );  	
  sum += col * (half) psWeights[0].x;  

  col = DecodeRGBS( tex2D(_tex0, IN.tc1.xy) );  
  sum += col * (half) psWeights[1].x;  
	
  col = DecodeRGBS( tex2D(_tex0, IN.tc2.xy) );  
  sum += col * (half) psWeights[2].x;  

  col = DecodeRGBS(tex2D(_tex0, IN.tc3.xy) );  
  sum += col * (half) psWeights[3].x;  

  col = DecodeRGBS(tex2D(_tex0, IN.tc4.xy) );  
  sum += col * (half) psWeights[4].x;  
	
  col = DecodeRGBS(tex2D(_tex0, IN.tc5.xy) );  
  sum += col * (half) psWeights[5].x;  
	
  col = DecodeRGBS(tex2D(_tex0, IN.tc6.xy) );  
  sum += col * (half) psWeights[6].x;  
	
  col = DecodeRGBS(tex2D(_tex0, IN.tc7.xy) );  
  sum += col * (half) psWeights[7].x;  

  OUT.Color = EncodeRGBS( float4( sum.xyz, 1) );
    
  return OUT;
}

// Optimized gauss blur version, making use of bilinear filtering
technique GaussBlurBilinear
{
  pass p0
  {
    VertexShader = CompileVS GaussBlurBilinearVS();
    PixelShader = CompilePS GaussBlurBilinearPS();    
  }
}

technique MaskedGaussBlurBilinear
{
  pass p0
  {
    VertexShader = CompileVS MaskedGaussBlurBilinearVS();
    PixelShader = CompilePS MaskedGaussBlurBilinearPS();    
  }
}

technique GaussBlurBilinearEncoded
{
  pass p0
  {
    VertexShader = CompileVS MaskedGaussBlurBilinearVS();
    PixelShader = CompilePS GaussBlurBilinearEncodedPS();    
  }
}

// ===================================================================================================
// Technique: GaussAlphaBlur
// Description: Applies a separatable vertical/horizontal gaussian blur filter for alpha channel only
// ===================================================================================================
// FIX:: oprimize
struct vtxOutAlphaBlur
{
  float4 HPosition : POSITION;
  float4 tc0 : TEXCOORDN;    
  float2 tc1 : TEXCOORDN;    
  float2 tc2 : TEXCOORDN;    
  float2 tc3 : TEXCOORDN;    
  float2 tc4 : TEXCOORDN;    
  float2 tc5 : TEXCOORDN;      
  float2 tc6 : TEXCOORDN;    
  float2 tc7 : TEXCOORDN;    
};

vtxOutAlphaBlur GaussAlphaBlurVS(vtxIn IN)
{
  vtxOutAlphaBlur OUT = (vtxOutAlphaBlur) 0;

  float4 vPos = IN.Position;
  OUT.HPosition = mul(vpMatrix, vPos);  
  
	OUT.tc0.zw = IN.baseTC.xy;

  OUT.tc0.xy = IN.baseTC.xy + PI_psOffsets[0].xy;
  OUT.tc1.xy = IN.baseTC.xy + PI_psOffsets[1].xy;
  OUT.tc2.xy = IN.baseTC.xy + PI_psOffsets[2].xy;
  OUT.tc3.xy = IN.baseTC.xy + PI_psOffsets[3].xy;
  OUT.tc4.xy = IN.baseTC.xy + PI_psOffsets[4].xy;
  OUT.tc5.xy = IN.baseTC.xy + PI_psOffsets[5].xy;
  OUT.tc6.xy = IN.baseTC.xy + PI_psOffsets[6].xy;
  OUT.tc7.xy = IN.baseTC.xy + PI_psOffsets[7].xy;

  return OUT;
}

pixout GaussAlphaBlurPS(vtxOutAlphaBlur IN)
{
  pixout OUT;

  half sum = 0;
  
	half col = tex2D(_tex0, IN.tc0.xy).a ;  	
	sum += col * (half) psWeights[0].x;  

	col = tex2D(_tex0, IN.tc1.xy).a ;  
	sum += col * (half) psWeights[1].x;  
	
  col = tex2D(_tex0, IN.tc2.xy).a ;  
	sum += col * (half) psWeights[2].x;  

	col = tex2D(_tex0, IN.tc3.xy).a ;  
	sum += col * (half) psWeights[3].x;  

	col = tex2D(_tex0, IN.tc4.xy).a ;  
	sum += col * (half) psWeights[4].x;  
	
	col = tex2D(_tex0, IN.tc5.xy).a ;  
	sum += col * (half) psWeights[5].x;  
	
	col = tex2D(_tex0, IN.tc6.xy).a ;  
	sum += col * (half) psWeights[6].x;  
	
	col = tex2D(_tex0, IN.tc7.xy).a ;  
	sum += col * (half) psWeights[7].x;  

  OUT.Color.xyz = tex2D(_tex0, IN.tc0.zw).xyz; 
	OUT.Color.a = sum;
  return OUT;
}

technique GaussAlphaBlur
{
  pass p0
  {
    VertexShader = CompileVS GaussAlphaBlurVS();
    PixelShader = CompilePS GaussAlphaBlurPS();    
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Kawase Blur technique //////////////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

///////////////// vertex shader //////////////////

struct vtxOutAnisotropicVertical
{
  float4 HPosition  : POSITION;
  float2 baseTC0 : TEXCOORDN;    
  float2 baseTC1 : TEXCOORDN;    
  float2 baseTC2 : TEXCOORDN;    
  float2 baseTC3 : TEXCOORDN;    
  float2 baseTC4 : TEXCOORDN;    
  float2 baseTC5 : TEXCOORDN;    
  float2 baseTC6 : TEXCOORDN;    
  float2 baseTC7 : TEXCOORDN;    
};

vtxOutAnisotropicVertical AnisotropicVerticalVS(vtxIn IN)
{
  vtxOutAnisotropicVertical OUT = (vtxOutAnisotropicVertical)0; 

  float4 vPos = IN.Position;
  OUT.HPosition = mul(vpMatrix, vPos);  
    
  OUT.baseTC0.xy = IN.baseTC.xy + float2(0,blurParams0.x)*0.125*0.75f;
  OUT.baseTC1.xy = IN.baseTC.xy + float2(0,blurParams0.y)*0.125*0.75f;
  OUT.baseTC2.xy = IN.baseTC.xy + float2(0,blurParams0.z)*0.125*0.75f;
  OUT.baseTC3.xy = IN.baseTC.xy + float2(0,blurParams0.w)*0.125*0.75f;

  OUT.baseTC4.xy = IN.baseTC.xy - float2(0,blurParams0.x)*0.75f;
  OUT.baseTC5.xy = IN.baseTC.xy - float2(0,blurParams0.y)*0.75f;
  OUT.baseTC6.xy = IN.baseTC.xy - float2(0,blurParams0.z)*0.75f;
  OUT.baseTC7.xy = IN.baseTC.xy - float2(0,blurParams0.w)*0.75f;
  
  return OUT;
}

///////////////// pixel shader //////////////////
pixout AnisotropicVerticalBlurPS(vtxOutAnisotropicVertical IN)
{
  pixout OUT;
  
  float4 canis = tex2D(blurMap0, IN.baseTC0.xy);
  canis += tex2D(blurMap0, IN.baseTC1.xy);
  canis += tex2D(blurMap0, IN.baseTC2.xy);
  canis += tex2D(blurMap0, IN.baseTC3.xy);
  canis += tex2D(blurMap0, IN.baseTC4.xy);
  canis += tex2D(blurMap0, IN.baseTC5.xy);
  canis += tex2D(blurMap0, IN.baseTC6.xy);
  canis += tex2D(blurMap0, IN.baseTC7.xy);
 

  OUT.Color = canis / 8.0;
  
  return OUT;
}

////////////////// technique /////////////////////
technique AnisotropicVertical
{
  pass p0
  {
    VertexShader = CompileVS AnisotropicVerticalVS();
    PixelShader = CompilePS AnisotropicVerticalBlurPS();
    
    CullMode = Back;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Dilate technique for sprites ///////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

float4 vPixelOffset;			// PS 1/width,1/height,?,?
float4 vDilateParams;			// PS brightness_multiplier,?,?,?

/// Constants ///////////////////////////

////////////////// samplers /////////////////////

///////////////// vertex shader //////////////////

struct vtxInDilate
{
  IN_P
  IN_TBASE
  IN_C0
};

struct vtxOutDilate
{
  float4 HPosition  : POSITION;
  float2 baseTC : TEXCOORD0;    
};

vtxOutDilate DilateVS(vtxInDilate IN)
{
  vtxOutDilate OUT = (vtxOutDilate)0; 

  float4 vPos = IN.Position;
  OUT.HPosition = mul(vpMatrix, vPos);    
  OUT.baseTC.xy = IN.baseTC.xy;

	OUT.baseTC.xy+=0.00001f;		// lookup more in the middle of the texel - fixes white spots on DX10

  return OUT;
}


///////////////// pixel shader //////////////////
pixout DilatePS(vtxOutDilate IN)
{
  pixout OUT;

	const half2 Kernel_Neighbors[8+12] = 
	{
		-1.0f,0.0f,
		1.0f,0.0f,
		0.0f,-1.0f,
		0.0f,1.0f,

		-1.0f,-1.0f,
		-1.0f,1.0f,
		1.0f,-1.0f,
		1.0f,1.0f,

		-2.0f,0.0f,
		2.0f,0.0f,
		0.0f,-2.0f,
		0.0f,2.0f,

		-2.0f,1.0f,
		2.0f,1.0f,
		1.0f,-2.0f,
		1.0f,2.0f,

		-2.0f,-1.0f,
		2.0f,-1.0f,
		-1.0f,-2.0f,
		-1.0f,2.0f,
	};

	// weighted - for fast dilation
	const float3 Kernel_WeightedNeighbors[13] = 
	{
		0.0f,0.0f,		256.0f*16.0f, 

		-1.0f,0.0f,		1.0f,	
		1.0f,0.0f,		1.0f,
		0.0f,-1.0f,		1.0f,
		0.0f,1.0f,		1.0f,

		-1.0f,-1.0f,	1.0f/64.0f,
		-1.0f,1.0f,		1.0f/64.0f,
		1.0f,-1.0f,		1.0f/64.0f,
		1.0f,1.0f,		1.0f/64.0f,

		-2.0f,0.0f,		1.0f/256.0f,
		2.0f,0.0f,		1.0f/256.0f,
		0.0f,-2.0f,		1.0f/256.0f,
		0.0f,2.0f,		1.0f/256.0f,
	};



	// fast dilation  
	float4 cSum = float4(0,0,0,0.001f);		//  0.001f to avoid division by zero

  for(int i=0;i<9+4;i++)
  {
		float4 val=tex2D(_tex0,IN.baseTC.xy+Kernel_WeightedNeighbors[i].xy*vPixelOffset.xy);
  
		cSum += float4(val.rgb,(val.a>0.05f)?1:0) * Kernel_WeightedNeighbors[i].z;
	}

	OUT.Color = float4(vDilateParams.x * cSum.rgb/cSum.a,tex2D(_tex0,IN.baseTC.xy).a);


	float4 cBase0 = tex2D(_tex0, IN.baseTC.xy);		                  // sun contribution
	float4 cBase1 = tex2D(_tex0, IN.baseTC.xy + vPixelOffset.zw);		// sky contribution
	
	OUT.Color = cBase0;

	half4 cColor0 = cBase0;		// sun contribution

	float2 vBestOffset = IN.baseTC.xy;
	//half2 vBestOffset = half2(0,0);

#ifdef D3D10
  [unroll]
#endif

	int iSampleCount=8;

  if( GetShaderQuality() > QUALITY_LOW )
  	iSampleCount=8+12;

	for(int i=0;i<iSampleCount;i++)	
	{
		float2 vLocalOffset = IN.baseTC.xy+Kernel_Neighbors[i].xy*vPixelOffset.xy;
		half4 cVal0 = tex2D(_tex0, vLocalOffset);		// sun contribution
		
		if (cVal0.a > 0.0f)
		{
			cColor0 = cVal0;
			vBestOffset = vLocalOffset;
		}
	}
	
	half4 cColor1 = tex2D(_tex0, vBestOffset + vPixelOffset.zw);		// sky contribution

	OUT.Color = cColor0+cColor1;

	half fContribution = max(cColor0.r,max(cColor0.g,cColor0.b)) / max(OUT.Color.r,max(OUT.Color.g,OUT.Color.b));		// Sun/(Sun+Sky)
	
	OUT.Color *= vDilateParams.x;		// adjust HDR values to LDR range

  const half SpriteAlphaRef=0.1;

	OUT.Color.a = (cBase0.a>0.0f) ? 1.0f-fContribution*(1.0-SpriteAlphaRef) : 0;
	//OUT.Color.a = cBase0.a;
	//OUT.Color = cBase1; //.a*0.3; // * 0.4;
//  OUT.Color.a = 1;
  return OUT;
}

////////////////// technique /////////////////////

technique Dilate
{
  pass p0
  {
    VertexShader = CompileVS DilateVS();            
    PixelShader = CompilePS DilatePS();
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Color correction technique /////////////////////////////////////////////////////////////////////

/// Constants ////////////////////////////

float4x4 mColorMatrix;

///////////////// pixel shader //////////////////

pixout ColorCorrectionPS(vtxOut IN)
{
  pixout OUT;
  
  half4 screenColor = half4(tex2D(_tex0, IN.baseTC.xy).xyz, 1);         
    
  // Apply color transformation matrix to ajust saturation/brightness/constrast
  screenColor.xyz=  float3( dot(screenColor.xyzw, mColorMatrix[0].xyzw),
						    dot(screenColor.xyzw, mColorMatrix[1].xyzw),
                            dot(screenColor.xyzw, mColorMatrix[2].xyzw) );
                         
  // Ajust image gamma                                    
  //screenColor.xyz=pow(screenColor.xyz, renderModeParamsPS.w);
    
  OUT.Color = screenColor;
    
  return OUT;
}

////////////////// technique /////////////////////

technique ColorCorrection
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS ColorCorrectionPS();    
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Image blurring techniques //////////////////////////////////////////////////////////////////////

///////////////// pixel shader //////////////////

pixout BlurInterpolationPS(vtxOut IN)
{
  pixout OUT;
  
  half4 screenColor = tex2D( _tex0, IN.baseTC.xy );
  half4 blurredColor = tex2D( _tex1, IN.baseTC.xy );
    
  OUT.Color = lerp(blurredColor, screenColor, psParams[0].w);
    
  return OUT;
}

////////////////// technique /////////////////////

technique BlurInterpolation
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS BlurInterpolationPS();    
    CullMode = None;        
  }
}


////////////////////////////////////////////////////////////////////////////////////////////////////
/// Masked Image blurring techniques //////////////////////////////////////////////////////////////////////

///////////////// pixel shader //////////////////

pixout MaskedBlurInterpolationPS(vtxOut IN)
{
  pixout OUT;
  
  half4 screenColor = tex2D( _tex0, IN.baseTC.xy );
  half4 blurredColor = tex2D( _tex1, IN.baseTC.xy );
  half mask = tex2D( _tex2, IN.baseTC.wz ).x;
  mask = sqrt( mask );
    
  OUT.Color = lerp(blurredColor, screenColor, mask * psParams[0].w);
    
  return OUT;
}

////////////////// technique /////////////////////

technique MaskedBlurInterpolation
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS MaskedBlurInterpolationPS();    
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Radial blurring technique //////////////////////////////////////////////////////////////////////

/// Constants ////////////////////////////

// xy = radial center screen space position, z = radius attenuation, w = blur strenght
float4 vRadialBlurParams;

///////////////// pixel shader //////////////////

pixout RadialBlurringPS(vtxOut IN)
{
  pixout OUT;
  
  float2 vScreenPos = vRadialBlurParams.xy;
  
  float2 vBlurVec = ( vScreenPos.xy - IN.baseTC.xy);
  
  float fInvRadius = vRadialBlurParams.z;
  float blurDist = saturate( 1- dot( vBlurVec.xy * fInvRadius, vBlurVec.xy * fInvRadius)) ;
  vRadialBlurParams.w *= blurDist*blurDist;
  
  const int nSamples = 8; 
  const float fWeight = 1.0 / (float) nSamples;
  
  half4 cAccum = 0;   
  for(int i=0; i < nSamples; i++)
  {
    half4 cCurr = tex2D(_tex0, (IN.baseTC.xy + vBlurVec.xy * i * vRadialBlurParams.w) );      
    cAccum += cCurr;// * (1.0-i * fWeight);
  }
    
  OUT.Color = cAccum * fWeight;
      
  return OUT;
}
////////////////// technique /////////////////////

technique RadialBlurring
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS RadialBlurringPS();    
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Motion Blur technique //////////////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

struct vtxOutMotionBlurDispl
{
  float4 HPosition  : POSITION;
  float4 tcProj     : TEXCOORDN;
  float4 vVelocity  : TEXCOORDN;
  float4 vVelocityPrev  : TEXCOORDN;
};

/// Constants ////////////////////////////

float4x4 mViewProj : PI_Composite;  // ( view projection matrix )
float4x4 mViewProjI : PB_UnProjMatrix;  // invert( view projection matrix )
float4x4 mViewProjPrev;

float4 PI_motionBlurParams;

float4 motionBlurParams;
float4 motionBlurChromaParams;
float4 motionBlurCamParams;
float4 vDirectionalBlur;

/// Samplers ////////////////////////////

sampler2D motionBlurMaskMap : register(s1);

///////////////// vertex shaders //////////////////

vtxOutMotionBlurDispl MotionBlurDisplVS(vtxIn IN)
{
  vtxOutMotionBlurDispl OUT = (vtxOutMotionBlurDispl)0; 

  float4 vPos = IN.Position;
  vPos.xyz = normalize(vPos.xyz) * 25; // * motionBlurCamParams.w; // sphere size needs to be tweakable for setting blur strenght
  vPos.xyz += g_VS_WorldViewPos.xyz;
  
  OUT.HPosition = mul(vpMatrix, vPos);  
      
  float4 vNewPos = OUT.HPosition;
  float4 vPrevPos =  mul(mViewProjPrev, vPos);
  
  OUT.vVelocity =  HPosToScreenTC( vNewPos );
  OUT.vVelocityPrev = HPosToScreenTC( vPrevPos );  

  OUT.tcProj = HPosToScreenTC( OUT.HPosition );

  return OUT;
}

///////////////// pixel shaders //////////////////

pixout MotionBlurdDepthMaskPS(vtxOut IN)
{
  pixout OUT = (pixout)0;  

  float fDepth = GetDepthMap(depthMapSampler, IN.baseTC);
  half mask_accum = exp(-fDepth * PS_NearFarClipDist.y);//exp(-fDepth* 25);
    //saturate( 1 - fDepth* 20.0 ); // 1 alu
  mask_accum *= mask_accum; //^2                // 1 alu 
  //mask_accum *= mask_accum; //^4               // 1 alu
  //mask_accum *= mask_accum; //^8               // 1 alu


  float fRotationAmount = (motionBlurParams.w * 5.0);

  half fNearestMask = ( fDepth * PS_NearFarClipDist.y );  // 1 alu
  fNearestMask = saturate( fNearestMask - 1.0 )*saturate(mask_accum + fRotationAmount);       // 2 alu
  //tcFinal +=  vVelocityLerp.xy * (s - s * fNearestMask);							// 2 alu

  OUT.Color.xyz = tex2D(screenMapSampler, IN.baseTC);
  OUT.Color.w = fNearestMask;//fNearestMask; // store mask in screen map alpha

  return OUT;
}

pixout MotionBlurDepthMaskHDRPS(vtxOut IN)
{
  pixout OUT = (pixout)0;  

  OUT.Color = tex2D(_tex0, IN.baseTC);

  float fDepth = GetDepthMap(_tex1, IN.baseTC);
  half mask_accum = exp(-fDepth * PS_NearFarClipDist.y);//exp(-fDepth* 25);
    //saturate( 1 - fDepth* 20.0 ); // 1 alu
  mask_accum *= mask_accum; //^2                // 1 alu 
  //mask_accum *= mask_accum; //^4               // 1 alu
  //mask_accum *= mask_accum; //^8               // 1 alu

  float fRotationAmount = (motionBlurParams.w * 5.0);

  half fNearestMask = ( fDepth * PS_NearFarClipDist.y );  // 1 alu
  fNearestMask = saturate( fNearestMask - 1.0 )*saturate(mask_accum + fRotationAmount);       // 2 alu
  //tcFinal +=  vVelocityLerp.xy * (s - s * fNearestMask);							// 2 alu

  OUT.Color.w = fNearestMask;//fNearestMask; // store mask in screen map alpha

  return OUT;
}

float2 GetVelocity( sampler2D sVelocity, float2 tc )
{
  float4 cVelocity = tex2Dlod(sVelocity, float4(tc.xy, 0, 0));
  float fDecodedLenght = cVelocity.z; //dot(cVelocity.zw, float2( 255.0 * 255.0 , 255.0 ) );

  return cVelocity.xy; //(cVelocity.xy*2-1) * fDecodedLenght;
}

pixout MotionBlurObjectPS(vtxOut IN)
{
  pixout OUT = (pixout)0;  

  float4 OriginalUV = IN.baseTC;

	float2 poisson[8] = {  
	  float2( 0.0,      0.0),
    float2( 0.527837,-0.085868),
	  float2(-0.040088, 0.536087),
	  float2(-0.670445,-0.179949),
	  float2(-0.419418,-0.616039),
	  float2( 0.440453,-0.639399),
	  float2(-0.757088, 0.349334),
	  float2( 0.574619, 0.685879)
	};
	
  float4 cOrig = tex2Dlod(_tex0, float4(IN.baseTC.xy, 0, 0));
  float4 cDummyFetchDx10 = tex2Dlod(_tex1, float4(IN.baseTC.xy, 0, 0)); // dummy fetch for dx10 samplers order declaration workaround
  float fOrigDepth = tex2Dlod(_tex2, float4(IN.baseTC.xy, 0, 0)).x;

  OUT.Color.xy = cOrig.xy*0.001 + GetVelocity(_tex1, IN.baseTC.xy);
  OUT.Color.wz = 0;

  return OUT;

  float4 Blurred = 0;  
  float2 pixelVelocity;
  
  int NumberOfPostProcessSamples = 8;           
  int nSamples = 8;
  float fUseAllSamples = 0;

  //bool bSingleSample = true;

  //{
  //  for(int n= 0; n<nSamples; n++)
  //  {	    
  //    float2 vOffset = poisson[n]* 0.0333;  // this must scale depending on camera distance
  //    // Sample neightboord pixels velocity
  //    float4 curFramePixelVelocity = tex2Dlod(_tex0, float4(OriginalUV + vOffset, 0, 0));
	 // 	if( !dot(curFramePixelVelocity, 1) )
  //    {
  //      fUseAllSamples = 1;
  //      break;
  //    }
  //  }
  //}

  int s= 0;

#if D3D10
  [unroll]
#endif
  for(int n= 0; n<nSamples; n++)
  {	    
    // todo: this must scale depending on camera distance or object size on screen
    float2 vOffset = poisson[n]* 0.0333 * saturate((1-fOrigDepth)*(1-fOrigDepth) );
    float  fCurrDepth = tex2Dlod(_tex2, float4(OriginalUV + vOffset, 0, 0)).x;
    if ( fCurrDepth > fOrigDepth )
      continue;

    // Sample neightboord pixels velocity
    float2 curFramePixelVelocity = GetVelocity(_tex1, OriginalUV + vOffset);
    pixelVelocity.xy =  curFramePixelVelocity;
        
    half fLen = dot(pixelVelocity.xy,pixelVelocity.xy);
		if( fLen )
		{	           
#if D3D10
  [unroll]
#endif
	    for(float i = 0; i < NumberOfPostProcessSamples; i++)
	    {   
	    	float2 lookup = pixelVelocity * ((i / NumberOfPostProcessSamples)-0.5) * PI_motionBlurParams.x + OriginalUV;
	      	      
	      // Lookup color/velocity at this new spot
	      float4 Current = tex2Dlod(_tex0, float4(lookup.xy, 0, 0));
	    	float4 curVelocity = tex2Dlod(_tex1, float4(lookup.xy, 0, 0));
	    	half fBlend = ( length(curVelocity)); 
	    	//float2 curVelocity = GetVelocity(_tex1, lookup.xy);
	    	//float fBlend = length(curVelocity); 
	    		    		      
	      Blurred.xyz += Current;
	      Blurred.w  += fBlend;	      
	      s++;
	    }            
    }

//    if( !fUseAllSamples )
  //    break;
  }

  OUT.Color = float4( cOrig.xyz, 1);
  if( s )
  {
    // Return the average color of all the samples
    float fLerp = Blurred.w/(float)s;     
    OUT.Color.xyz =float4(lerp(cOrig.xyz, Blurred.xyz/(float)s, saturate(fLerp*3)), 1);
  }

  return OUT;
}

pixout MotionBlurObjectMaskPS(vtxOut IN)
{
  pixout OUT = (pixout)0;  

  float4 OriginalUV = IN.baseTC;

	float2 poisson[7] = {  
    float2( 0.527837,-0.085868),
	  float2(-0.040088, 0.536087),
	  float2(-0.670445,-0.179949),
	  float2(-0.419418,-0.616039),
	  float2( 0.440453,-0.639399),
	  float2(-0.757088, 0.349334),
	  float2( 0.574619, 0.685879)
	};
	
  half2 cOrigVelocity = tex2Dlod(_tex0, float4(IN.baseTC.xy, 0, 0)).xy;
  float fOrigDepth = tex2Dlod(_tex1, float4(IN.baseTC.xy, 0, 0)).x;

  float4 Blurred = 0;  
  float2 pixelVelocity;
  
  int nSamples = 7;

  const half fOffsetRange = 100.0;
  
  PS_ScreenSize.zw *= fOffsetRange;
  const half2 vOffsetScale = PS_ScreenSize.zw; // 0.0333 old hardcoded scale

  const half fMinVelocityThreshold = 0.0001;

  half fCenterVelocity = dot( cOrigVelocity.xy, cOrigVelocity.xy);

  if(( fCenterVelocity ) ) // Inside case 
  {
    OUT.Color.x = 1;
    OUT.Color.w = fCenterVelocity > fMinVelocityThreshold.xx; // set second pass mask
    return OUT;
  }
  else 
  {
#if D3D10
  [unroll]
#endif
    for(int n= 0; n<nSamples; n++) // Borders case 
    {	    
      // todo: this must scale depending on camera distance or object size on screen
      float2 vOffset = poisson[n]* vOffsetScale;

      // Sample neightboord pixels velocity
      pixelVelocity.xy = tex2Dlod(_tex0, float4(OriginalUV + vOffset, 0, 0)).xy;

      half fLen = dot(pixelVelocity.xy,pixelVelocity.xy);
      OUT.Color.y += fLen;
    }
    

    OUT.Color.y = OUT.Color.y / (float) nSamples;
    OUT.Color.w = OUT.Color.yy > fMinVelocityThreshold.xx;
    OUT.Color.y = (OUT.Color.y > 0.0); // set second pass mask

    return OUT;
  }

//  OUT.Color = saturate( OUT.Color * 10000 );

  return OUT;
}

pixout MotionBlurObjectUsingMaskPS(vtxOut IN)
{
  // premiliary object motion blur optimization using motion mask

  pixout OUT = (pixout)0;  

  float4 OriginalUV = IN.baseTC;

	float2 poisson[7] = {  
    float2( 0.527837,-0.085868),
	  float2(-0.040088, 0.536087),
	  float2(-0.670445,-0.179949),
	  float2(-0.419418,-0.616039),
	  float2( 0.440453,-0.639399),
	  float2(-0.757088, 0.349334),
	  float2( 0.574619, 0.685879)
	};
	
  float4 cOrig = tex2Dlod(_tex0, float4(IN.baseTC.xy, 0, 0));
  float4 cDummyFetchDx10 = tex2Dlod(_tex1, float4(IN.baseTC.xy, 0, 0)); // dummy fetch for dx10 samplers order declaration workaround
  float fOrigDepth = tex2Dlod(_tex2, float4(IN.baseTC.xy, 0, 0)).x;
  half4 cMask = tex2Dlod(_tex3, float4(IN.baseTC.xy, 0, 0)).xyzw;

  // dx10 sampler binding workaround...
  //OUT.Color = (cOrig + cDummyFetchDx10 + fOrigDepth + cMask)*0.000001;

  OUT.Color = cOrig;//

  if( dot( cMask.xy, 1) == 0.0 ) 
    return OUT;

  float4 Blurred = 0;
  float2 pixelVelocity;

  int nSamples = 8;

  const int nSamplesEdges = 7;
  const float nRecipSamples = 1.0 / (float)nSamples;

  float s= 0;

  if( cMask.x ) // sample is inside mesh - do regular motion blurring
  {
    // get velocity
    pixelVelocity.xy = GetVelocity(_tex1, OriginalUV) * PI_motionBlurParams.x;
  #if D3D10
    [unroll]
  #endif
    for(float i = 0; i < nSamples; i++)
    {   
  	  float2 lookup = pixelVelocity * ((i * nRecipSamples)-0.5) + OriginalUV;
      Blurred.xyz += tex2Dlod(_tex0, float4(lookup.xy, 0, 0)).xyz;
    }

    OUT.Color = half4(Blurred.xyz * nRecipSamples, 1);
    return OUT;
  }  
  else // samples are in mesh edges
  {

  #if D3D10
    [unroll]
  #endif
    for(int n= 0; n<nSamplesEdges; n++)
    {	    
      // todo: this must scale depending on camera distance or object size on screen
      float2 vOffset = poisson[n]* 0.0333 * saturate((1-fOrigDepth)*(1-fOrigDepth) );
      float  fCurrDepth = tex2Dlod(_tex2, float4(OriginalUV + vOffset, 0, 0)).x;
      if ( fCurrDepth > fOrigDepth )
        continue;

      // Sample neightboord pixels velocity
      float2 curFramePixelVelocity = GetVelocity(_tex1, OriginalUV + vOffset);
      pixelVelocity.xy =  curFramePixelVelocity ;
          
      half fLen = dot(pixelVelocity.xy,pixelVelocity.xy);
		  if( fLen )
		  {
  #if D3D10
    [unroll]
  #endif
        for(float i = 0; i < nSamples; i++)
        {   
	    	  float2 lookup = pixelVelocity * ((i * nRecipSamples)-0.5)* PI_motionBlurParams.x + OriginalUV;

          // Lookup color/velocity at this new spot
	        float3 Current = tex2Dlod(_tex0, float4(lookup.xy, 0, 0));
	    	  float4 curVelocity = tex2Dlod(_tex1, float4(lookup.xy, 0, 0));
	    	  half fBlend = ( dot(curVelocity, curVelocity)); 

	        Blurred += half4(Current.xyz, fBlend);
	      }

	      s+= nSamples;
      }
    }

    if( s )
    {
      // Return the average color of all the samples
      half fLerp = Blurred.w/s;     
      OUT.Color.xyz =float4(lerp(cOrig.xyz, Blurred.xyz/s, saturate(fLerp*3)), 1);
    }
  }

  return OUT;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

pixout OMB_VelocityIDRescalePS(vtxOut IN)
{
  pixout OUT = (pixout)0;  

  float2 vScreenSizeRecip = PI_motionBlurParams.zw; //1.0 / PS_ScreenSize;
  float4 t0 = tex2D(_tex0, IN.baseTC.xy);
  float4 t1 = tex2D(_tex0, IN.baseTC.xy + float2(1,1) * vScreenSizeRecip);
  float4 t2 = tex2D(_tex0, IN.baseTC.xy - float2(1,1) * vScreenSizeRecip);
  float4 t3 = tex2D(_tex0, IN.baseTC.xy + float2(-1,1)* vScreenSizeRecip);
  float4 t4 = tex2D(_tex0, IN.baseTC.xy + float2(1,-1)* vScreenSizeRecip);

  // Use maximum depth
  t0 = (t0.z>t1.z)? t0: t1;
  t0 = (t0.z>t2.z)? t0: t2;
  t0 = (t0.z>t3.z)? t0: t3;
  t0 = (t0.z>t4.z)? t0: t4;
  
  OUT.Color = t0;

  return OUT;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

float GetResampledOrigDepth( float2 tc )
{
  float2 vScreenSizeRecip = PI_motionBlurParams.xy; //1.0 / PS_ScreenSize; //0.25*PI_motionBlurParams.zw;  // hardcoded half-texel size 
  float t0 = tex2Dlod(_tex1, float4(tc.xy, 0, 0)).x;
  t0 = max(t0, tex2Dlod(_tex1, float4(tc.xy + float2(1,1) * vScreenSizeRecip, 0, 0)).x );
  t0 = max(t0, tex2Dlod(_tex1, float4(tc.xy - float2(1,1) * vScreenSizeRecip, 0, 0)).x );
  t0 = max(t0, tex2Dlod(_tex1, float4(tc.xy + float2(-1,1)* vScreenSizeRecip, 0, 0)).x );
  
  t0 = max(t0, tex2Dlod(_tex1, float4(tc.xy + float2(1,-1)* vScreenSizeRecip, 0, 0)).x );

  return t0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

pixout OMB_OffsetMapPS(vtxOut IN)
{
  pixout OUT = (pixout)0;  

  float4 t0 = tex2D(_tex0, IN.baseTC);

  float fLen = length(t0.xy);
  float fSizeScale = 1 - saturate(t0.z * PS_NearFarClipDist.y / 200);
  fSizeScale *= fSizeScale;
  fSizeScale *= fSizeScale;
  fSizeScale *= fSizeScale;

  t0.xyz = min( fLen * 100.0 , 1) ; // *0.25; //

  OUT.Color = t0;
  return OUT;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

pixout OMB_CopyAlphaIDPS(vtxOut IN)
{
  pixout OUT = (pixout)0;  

  float4 t0 = tex2D(_tex0, IN.baseTC);
  //float4 t1 = tex2D(_tex1, IN.baseTC);

  OUT.Color = t0; //float4(t0.xyw, t1.w);
  return OUT;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

pixout OMB_VelocityDilationPS(vtxOut IN)
{
  pixout OUT = (pixout)0;  

  float4 OriginalUV = IN.baseTC;

  const int nOffsets = 8;

  float2 vOffsets[ nOffsets ] =
  {  
		-1.0f, 0.0f,
		 1.0f, 0.0f,

		-2.0f, 0.0f,
		 2.0f, 0.0f,

		-3.0f, 0.0f,
		 3.0f, 0.0f,

		-4.0f, 0.0f,
		 4.0f, 0.0f,
  };

  float2 vScrSizeRecip = PS_ScreenSize.zw * 2.0;//PI_motionBlurParams.zw;

  float4 vCenterVelocity = tex2Dlod(_tex0, float4(IN.baseTC.xy, 0, 0));
  float fCenterDepth = GetResampledOrigDepth(IN.baseTC.xy );
  float fOffsetScale = tex2Dlod(_tex2, float4(IN.baseTC.xy, 0, 0)).x;

  if( fOffsetScale == 0 || dot(vCenterVelocity.xy, vCenterVelocity.xy) )
  {
    // Inside
    OUT.Color = float4(vCenterVelocity.xyzw); 
    return OUT;
  }

  // Check edges
  float4 Blurred = 0;
  float nSamplesCount = 0;
 
#if D3D10
  [unroll]
#endif
  for(int n = 0; n < nOffsets; n++ )
  {  
    #if %_RT_SAMPLE0
		float4 vCurrVelocityDepthID = tex2Dlod(_tex0, float4(IN.baseTC.xy + vOffsets[n].yx *vScrSizeRecip, 0, 0));
	#else
		float4 vCurrVelocityDepthID = tex2Dlod(_tex0, float4(IN.baseTC.xy + vOffsets[n].xy *vScrSizeRecip, 0, 0));
	#endif

    float fDepthCmp = saturate( fCenterDepth - vCurrVelocityDepthID.z );
    fDepthCmp *= dot( vCurrVelocityDepthID.xy, vCurrVelocityDepthID.xy );
    fDepthCmp *= Blurred.z == 0;
    
    if(fDepthCmp)
    {
      //float weight = lerp(1, 0, (float)n / nOffsets);
      Blurred = vCurrVelocityDepthID;// * weight;
    }
  }

  OUT.Color = float4(Blurred);
  return OUT;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

pixout OMB_UsingVelocityDilationPS(vtxOut IN)
{
  pixout OUT = (pixout)0;  

  float4 OriginalUV = IN.baseTC;
  float4 cOrig = tex2Dlod(_tex0, float4(IN.baseTC.xy, 0, 0));
  float4 cOrigVelocity = tex2Dlod(_tex1, float4(IN.baseTC.xy, 0, 0));

  OUT.Color = cOrig;
  if( dot(cOrigVelocity.xy, cOrigVelocity.xy) == 0.0)
    return OUT;

  float4 Blurred = 0;
  float2 pixelVelocity;

  const int nSamples = 16;
  const float nRecipSamples = 1.0 / (float)nSamples;
  const float nRecipSamplesAcc = 1.0 / (float)(nSamples-1);

  // get velocity
  pixelVelocity.xy = cOrigVelocity;

  float fLen = length(pixelVelocity.xy);
  if( fLen )
    pixelVelocity.xy /= fLen;

  float2 vScrSizeRecip = 1.0 / PS_ScreenSize;
  const float2 vMaxRange = 48 * vScrSizeRecip.xy; //48.0

  pixelVelocity.xy *= min(fLen, vMaxRange)* PI_motionBlurParams.x;

  float nSamplesCount = 0;
#if D3D10
  [unroll]
#endif
  for(float i = 0; i < nSamples; i++)
  {   
	  float2 lookup = pixelVelocity * ((i * nRecipSamplesAcc)-0.5) + OriginalUV;
   
    float4 tcMB = tex2Dlod(_tex0, float4(lookup.xy, 0, 0));     
    Blurred.xyz += tcMB.xyz;

#if !%_RT_SAMPLE1
      Blurred.w += saturate(100000 * tcMB.w);
#else
      // reusing previous pass blending results
      Blurred.w += tcMB.w;
#endif
  }

  // Blend results with scene
  if( Blurred.w )
  {
    Blurred.xyz *= nRecipSamples;
#if !%_RT_SAMPLE1
    OUT.Color = lerp(cOrig, Blurred,saturate( saturate( Blurred.w*nRecipSamples)*2+ saturate(cOrig.w*1000)));
#else
    OUT.Color = lerp(cOrig, Blurred,saturate( saturate( Blurred.w*nRecipSamples)*2));
#endif
  }
  
  OUT.Color.w = Blurred.w * nRecipSamples;
    
  return OUT;
}

pixout MotionBlurDisplPS(vtxOutMotionBlurDispl IN)
{  
  pixout OUT = (pixout)0;  

  int nQuality = GetShaderQuality();

  half4 cMidCurr = tex2Dproj(screenMapSampler, IN.tcProj.xyzw);  
  half fDepth = GetDepthMapScaledProj(depthMapSampler, IN.tcProj.xyzw);               // 1 alu

  OUT.Color = cMidCurr;

  float fSamples = 8.0;

  const float fWeight = (1.0 / fSamples);  
  const float fWeightStep = (2.0 / fSamples);
  
  //motionBlurParams.w = 1.5;

  float2 vVelocityPrev = ( (IN.vVelocityPrev.xy/IN.vVelocityPrev.w))* PI_motionBlurParams.w;	// 1 div, 1 mul
  
  float2 vVelocity = (IN.vVelocity.xy/IN.vVelocity.w);									// 1 div
  float2 vVelocityDiv = vVelocity;
  vVelocity *= PI_motionBlurParams.w;

  float2 vVelocityLerp = vVelocityPrev - vVelocity;										// 1 sub							

  vVelocityDiv.xy += vDirectionalBlur.xy *  PI_motionBlurParams.w;
  vVelocityLerp.xy += vDirectionalBlur.xy *  PI_motionBlurParams.w;
      
  float4 accum = 0;

#if D3D10
  [unroll]
#endif
  for(float s = -1.0; s < 1.0 ; s += fWeightStep )										// 1 add
  {																						
	  float2 tcFinal =  vVelocityDiv.xy - vVelocityLerp.xy * s;							// 1 alu
    
    if( nQuality == QUALITY_HIGH )
    {
      half fDepthMask = tex2D(screenMapSampler, tcFinal).w;
      tcFinal +=  vVelocityLerp.xy * (s - s * fDepthMask);							// 2 alu
    }

    accum += tex2D(screenMapSampler, tcFinal ); // 1 alu
  }
  
  accum *= fWeight;                                                                                 // 1 alu
   
  // Remove scene bleeding from 1st player hands
  OUT.Color = lerp(cMidCurr, accum, saturate(fDepth-1.0) );                                        // 3 alu //fDepth*100; //
  
  return OUT;
}

*/



float MartyMcFly = 1.0;float xx=0.05;float4	tempF1;float4	tempF2; float4	tempF3; float4	Timer;float4	ScreenSize;float4 SunDirection;float xxx = 0.35;texture2D texColor;texture2D texNoise;texture2D texDepht < string ResourceName="Copyright_by_MartyMcFly.png"; >;float yy = 0.3;float yx = 0.5;sampler2D SamplerColor = sampler_state
{
Texture   = <texColor>; MinFilter = LINEAR; MagFilter = LINEAR; MipFilter = NONE; AddressU  = Clamp; AddressV  = Clamp; SRGBTexture=FALSE; MaxMipLevel=0; MipMapLodBias=0;}; sampler2D SamplerNoise = sampler_state {	Texture   = <texNoise>;	MinFilter = POINT;	MagFilter = POINT;	MipFilter = NONE;	AddressU  = Wrap;	AddressV  = Wrap;	SRGBTexture=FALSE;	MaxMipLevel=0;	MipMapLodBias=0;}; sampler2D SamplerDepth = sampler_state { 	Texture   = <texDepht>;	MinFilter = POINT;	MagFilter = POINT;	MipFilter = NONE;	AddressU  = Wrap;	AddressV  = Wrap;	SRGBTexture=FALSE;	MaxMipLevel=0;	MipMapLodBias=0; }; struct VS_OUTPUT_POST {	float4 vpos  : POSITION;	float2 txcoord : TEXCOORD0;}; struct VS_INPUT_POST {	float3 pos  : POSITION;	float2 txcoord : TEXCOORD0; };

VS_OUTPUT_POST VS_PostProcess(VS_INPUT_POST IN)
{
	VS_OUTPUT_POST OUT;

	float4 pos=float4(IN.pos.x,IN.pos.y,IN.pos.z,MartyMcFly);

	OUT.vpos=pos;
	OUT.txcoord.xy=IN.txcoord.xy;

	return OUT;
}
float4 PS_PostProcess(VS_OUTPUT_POST i) : COLOR
{
	#define FXAA_SUBPIX_SHIFT (MartyMcFly/8.0)
	#define FXAA_REDUCE_MIN   (MartyMcFly/32.0)
	#define FXAA_REDUCE_MUL   (MartyMcFly/16.0)
	#define FXAA_SPAN_MAX     8.0

	half2 rcpFrame = half2(1/ScreenSize.x, 1/(ScreenSize.x/ScreenSize.z));
	half4 posPos;	posPos.xy = i.txcoord.xy;	posPos.zw = posPos.xy - (rcpFrame.xy * (0.5 + FXAA_SUBPIX_SHIFT));
	half3 rgbNW = tex2D(SamplerColor, posPos.zw ).xyz;	half3 rgbNE = tex2D(SamplerColor, posPos.zw + half2(rcpFrame.x, 0.0) ).xyz;	half3 rgbSW = tex2D(SamplerColor, posPos.zw + half2(0.0, rcpFrame.y) ).xyz;	half3 rgbSE = tex2D(SamplerColor, posPos.zw +rcpFrame.xy ).xyz;	half3 rgbM  = tex2D(SamplerColor, posPos.xy).xyz;       
	half3 luma = half3(0.299, 0.587, 0.114);	half lumaNW = dot(rgbNW, luma);	half lumaNE = dot(rgbNE, luma);	half lumaSW = dot(rgbSW, luma);	half lumaSE = dot(rgbSE, luma);	half lumaM  = dot(rgbM,  luma);       
	half lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));	half lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));       
	half2 dir;       
	half lumaNWNE = lumaNW + lumaNE;	half lumaSWSE = lumaSW + lumaSE;       
	dir.x = -((lumaNWNE) - (lumaSWSE));	dir.y =  ((lumaNW + lumaSW) - (lumaNE + lumaSE));       
	half dirReduce = max( (lumaSWSE + lumaNWNE) * (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN);	half rcpDirMin = MartyMcFly/(min(abs(dir.x), abs(dir.y)) + dirReduce);	dir = min(half2( FXAA_SPAN_MAX,  FXAA_SPAN_MAX), max(half2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), dir * rcpDirMin)) * rcpFrame.xy;             
	half3 rgbA = (MartyMcFly/2.0) * (tex2D(SamplerColor, posPos.xy + dir * (MartyMcFly/3.0 - 0.5) ).xyz + tex2D(SamplerColor, posPos.xy + dir * (2.0/3.0 - 0.5) ).xyz);	half3 rgbB = rgbA * (MartyMcFly/2.0) + (MartyMcFly/4.0) * (tex2D(SamplerColor, posPos.xy + dir * (0.0/3.0 - 0.5) ).xyz + tex2D(SamplerColor, posPos.xy + dir * (3.0/3.0 - 0.5) ).xyz);	half lumaB = dot(rgbB, luma);     
	if((lumaB < lumaMin) || (lumaB > lumaMax))
 		return half4(rgbA, MartyMcFly);       
	return float4(rgbB, MartyMcFly);}

float4 PS_PostProcess_Sharp_Noise(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR { float4 res = 0;	float4 tex=0.0;	tex.xy=IN.txcoord.xy; float3 ori = tex2D(SamplerColor, tex).rgb;     float2 p;	p.x = MartyMcFly/ScreenSize.x;	p.y=p.x/ScreenSize.z; float3 blur_ori = tex2D(SamplerColor, tex + float2(0.5 * p.x,-p.y * xxx)).rgb;      blur_ori += tex2D(SamplerColor, tex + float2(xxx * -p.x,0.5 * -p.y)).rgb;    blur_ori += tex2D(SamplerColor, tex + float2(xxx * p.x,0.5 * p.y)).rgb;    blur_ori += tex2D(SamplerColor, tex + float2(0.5 * -p.x,p.y * xxx)).rgb;    blur_ori /= 4.0;  	float3 sharp = ori - blur_ori;  float sharp_luma = dot(sharp, yy);	sharp_luma = clamp(sharp_luma, -yx, yx);	float4 done = tex2D(SamplerColor, tex) + sharp_luma;   float origgray=dot(done.xyz, 0.333);	tex.xy=IN.txcoord.xy*16.0 + origgray;	float4 cnoi=tex2Dlod(SamplerNoise, tex);	done=lerp(done, (cnoi.x+0.5)*done, xx*saturate(MartyMcFly-origgray*1.8));done.w=MartyMcFly; return done*tex2D(SamplerDepth, float2(0.1,0.1)); } technique PostProcess {  pass P0  {	VertexShader = compile vs_3_0 VS_PostProcess();	PixelShader  = compile ps_3_0 PS_PostProcess_Sharp_Noise();	FogEnable=FALSE;	ALPHATESTENABLE=FALSE;	SEPARATEALPHABLENDENABLE=FALSE;	AlphaBlendEnable=FALSE;	FogEnable=FALSE;	SRGBWRITEENABLE=FALSE;  }}  technique PostProcess2 { pass P0 {VertexShader = compile vs_3_0 VS_PostProcess();PixelShader  = compile ps_3_0 PS_PostProcess();FogEnable=FALSE;ALPHATESTENABLE=FALSE;SEPARATEALPHABLENDENABLE=FALSE;AlphaBlendEnable=FALSE;FogEnable=FALSE;SRGBWRITEENABLE=FALSE;}} technique PostProcess3 { pass P0 {VertexShader = compile vs_3_0 VS_PostProcess();PixelShader  = compile ps_3_0 PS_PostProcess_Sharp_Noise();FogEnable=FALSE;ALPHATESTENABLE=FALSE;SEPARATEALPHABLENDENABLE=FALSE;AlphaBlendEnable=FALSE;FogEnable=FALSE;SRGBWRITEENABLE=FALSE;}} technique PostProcess4 {pass P0 {VertexShader = compile vs_3_0 VS_PostProcess();PixelShader  = compile ps_3_0 PS_PostProcess();FogEnable=FALSE;ALPHATESTENABLE=FALSE;SEPARATEALPHABLENDENABLE=FALSE;AlphaBlendEnable=FALSE;FogEnable=FALSE;SRGBWRITEENABLE=FALSE;}} technique PostProcess5{pass P0{VertexShader = compile vs_3_0 VS_PostProcess();PixelShader  = compile ps_3_0 PS_PostProcess();DitherEnable=TRUE;ZEnable=FALSE;CullMode=NONE;ALPHATESTENABLE=FALSE;SEPARATEALPHABLENDENABLE=FALSE;AlphaBlendEnable=FALSE;StencilEnable=FALSE;FogEnable=FALSE;SRGBWRITEENABLE=FALSE; }
}


/*
pixout MotionBlurDisplHDRPS(vtxOutMotionBlurDispl IN)
{  
  pixout OUT = (pixout)0;  
  
  int nQuality = GetShaderQuality();

  half4 cMidCurr = tex2Dproj(_tex0, IN.tcProj.xyzw);  
  float fDepth = tex2Dproj(_tex1, IN.tcProj.xyzw).x * PS_NearFarClipDist.y;               // 1 alu

  OUT.Color = cMidCurr;
  
  // skip bellow min threshold (usually sky and nearby geometry) with slow movement
#if %_RT_SAMPLE0
  const float fMinDepthMaskThreshold = 0.05;

  // this is not 100% correct since still needed to sample faraway pixels
  // but for 1st pass is ok - artefacts mostly noticable with fast camera movement
  if( cMidCurr.w < fMinDepthMaskThreshold )   // saves about 1 ms 
    return OUT;
#endif

  // skip nearby geometry with fast movement
  if( fDepth - 1.0f <= 0.0f)
    return OUT;

  half2 vVelocityPrev = ( (IN.vVelocityPrev.xy/IN.vVelocityPrev.w))* PI_motionBlurParams.w;	// 1 div, 1 mul
  
  half2 vVelocity = (IN.vVelocity.xy/IN.vVelocity.w);									// 1 div
  half2 vVelocityDiv = vVelocity;
  vVelocity *= PI_motionBlurParams.w;

  half2 vVelocityLerp = vVelocityPrev - vVelocity;										// 1 sub							

  vVelocityDiv.xy += vDirectionalBlur.xy *  PI_motionBlurParams.w;
  vVelocityLerp.xy += vDirectionalBlur.xy *  PI_motionBlurParams.w;
      
  half4 accum = 0;

  half fSamples = 8.0;

#if %_RT_SAMPLE1
  fSamples = 4.0;
#endif

#if %_RT_SAMPLE0

  // use-lower quality masking for first pass

  const half fWeight = (1.0 / fSamples);;  
  const half fWeightStep = (2.0 / fSamples);

#if D3D10
  [unroll]
#endif
  for(half s = -1.0; s < 1.0 ; s += fWeightStep )										// 1 add
  {																
    half2 tcFinal =  vVelocityDiv.xy - vVelocityLerp.xy * s;							// 1 alu
    half4 col = tex2Dlod(_tex0, float4(tcFinal.xy, 0, 0) ); // 1 alu
    accum += lerp(cMidCurr, col, col.w );
  }

  accum *= fWeight;                                                                                 // 1 alu
  // Remove scene bleeding from 1st player hands
  OUT.Color = accum; //lerp(cMidCurr, accum, saturate(fDepth-1.0) ); 
#else

  int scount = 0;

  const half fWeight = (1.0 / fSamples);;  
  const half fWeightStep = (2.0 / fSamples);

#if D3D10
  [unroll]
#endif
  for(half s = -1.0; s < 1.0 ; s += fWeightStep )										// 1 add
  {																
    half2 tcFinal =  vVelocityDiv.xy - vVelocityLerp.xy * s;							// 1 alu
    half fDepthMask = tex2Dlod(_tex0, float4(tcFinal.xy, 0, 0)).w;
    if( fDepthMask )
    {
      tcFinal +=  vVelocityLerp.xy * (s - s * fDepthMask);							// 2 alu
      accum += tex2Dlod(_tex0, float4(tcFinal.xy, 0, 0) ); // 1 alu
      scount++;
    }

  }

  // Remove scene bleeding from 1st player hands
  if( scount )
  {
    accum /= (half) scount ;
    // Remove scene bleeding from 1st player hands
    OUT.Color = accum; //lerp(cMidCurr, accum, saturate(fDepth-1.0) ); 
  }

#endif


 return OUT;
}

///////////////////////////////////////////////////
// Method with correct per-pixel reprojection.

struct vtxOutMotionBlurDisplHDR
{
  float4 HPosition  : POSITION;
  float4 baseTC     : TEXCOORDN;
  float4x4 viewProjPrev : TEXCOORDN;
};

vtxOutMotionBlurDisplHDR MotionBlurDisplHDRVS(vtxIn IN)
{
  vtxOutMotionBlurDisplHDR OUT = (vtxOutMotionBlurDisplHDR)0; 

  float4 vPos = IN.Position;
  vPos.xyz = normalize(vPos.xyz) * 25; // * motionBlurCamParams.w; // sphere size needs to be tweakable for setting blur strenght
  vPos.xyz += g_VS_WorldViewPos.xyz;
  
  OUT.HPosition = mul(vpMatrix, vPos);  
  OUT.baseTC = HPosToScreenTC( OUT.HPosition );
  
  // Output previous projection matrix for pixel shader use.
  OUT.viewProjPrev = mViewProjPrev;

  return OUT;
}

pixout MotionBlurDisplHDRPS(vtxOutMotionBlurDisplHDR IN)
{  
  pixout OUT = (pixout)0;  
  
  // Constants.
  static const half fSamples = 12.0;
  static const half fStepWeight = 1.0 / (fSamples - 1.0h);
  static const half fMotionBlurScale = PI_motionBlurParams.w * 0.15h;
  
  // Devide by W to get screen coordinates.
  IN.baseTC.xy /= IN.baseTC.w;
  
  // Initial screen sample.
  half4 cScreen = tex2D(_tex0, IN.baseTC.xy);  
  OUT.Color = cScreen;
  
  // Sample depth.
  float fDepth = GetDepthMap(_tex1, IN.baseTC.xy);
     
  // Get world space position. 
  float3 vPosVS = PositionFromDepth( fDepth, IN.baseTC.xy );
  float4 vPosWS = mul(mViewProjI, float4(vPosVS.xyz, 1.0f));
  vPosWS.xyz /= vPosWS.w;

  // Current position.
  half2 vCurrPos = vPosVS * float2(1,-1);

  // Get previous position.
  float4 vPrevPos = mul(IN.viewProjPrev, float4(vPosWS.xyz, 1.0f));
  vPrevPos.xyz /= vPrevPos.w;
  vPrevPos.xy *= float2(1,-1);
    
  // Compute velocity.
  half2 vVelocity = (vCurrPos-vPrevPos);
  vVelocity.xy += vDirectionalBlur.xy;
  vVelocity.xy *= fMotionBlurScale;
 	
  // Limit range.
  half fLen = length(vVelocity);
  vVelocity.xy /= (fLen+1e-6);
  const float2 vMaxRange = 16.0 * PS_ScreenSize.zw;
  vVelocity.xy *= min(fLen, vMaxRange);
    
  if( fLen < 0.001)
  {
	return OUT;
  }

  // Initial sample.
  half4 cSum = float4(cScreen.rgb, 1.0);
 
#if D3D10
  [unroll]
#endif  
  for(half i=0; i<fSamples; i+=4)
  {							
    half4 vStepWeights = fStepWeight * float4(i,i+1,i+2,i+3) * 2.0 - 1.0;
    half4 cColor0 = tex2Dlod(_tex0, float4(IN.baseTC.xy + vVelocity.xy * vStepWeights.x,0,0));
    half4 cColor1 = tex2Dlod(_tex0, float4(IN.baseTC.xy + vVelocity.xy * vStepWeights.y,0,0));
    half4 cColor2 = tex2Dlod(_tex0, float4(IN.baseTC.xy + vVelocity.xy * vStepWeights.z,0,0));
    half4 cColor3 = tex2Dlod(_tex0, float4(IN.baseTC.xy + vVelocity.xy * vStepWeights.w,0,0));
	
	cSum += half4(cColor0.rgb, 1.0) * cColor0.a;
 	cSum += half4(cColor1.rgb, 1.0) * cColor1.a;
	cSum += half4(cColor2.rgb, 1.0) * cColor2.a;
	cSum += half4(cColor3.rgb, 1.0) * cColor3.a;
 }
 cSum.rgb /= cSum.a ? cSum.a : 1.0;
  
 OUT.Color = half4(cSum.rgb, 1.0h);

 return OUT;
}

////////////////// technique /////////////////////

technique MotionBlurMaskGen
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS MotionBlurdDepthMaskPS();
    CullMode = None;        
  }
}

technique MotionBlurMaskGenHDR
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS MotionBlurDepthMaskHDRPS();
    CullMode = None;        
  }
}

technique MotionBlurDispl
{
  pass p0
  {
    VertexShader = CompileVS MotionBlurDisplVS();
    PixelShader = CompilePS MotionBlurDisplPS();
    CullMode = None;        
  }
}

technique OMB_OffsetMap
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS OMB_OffsetMapPS();
    CullMode = None;        
  }
}

technique OMB_CopyAlphaID
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS OMB_CopyAlphaIDPS();
    CullMode = None;        
  }
}


#if %DYN_BRANCHING_POSTPROCESS

technique MotionBlurDisplHDR
{
  pass p0
  {
    VertexShader = CompileVS MotionBlurDisplVS();//MotionBlurDisplHDRVS();
    PixelShader = CompilePS MotionBlurDisplHDRPS();
    CullMode = None;        
  }
}

technique MotionBlurObject
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS MotionBlurObjectPS();
    CullMode = None;      
  }
}

technique MotionBlurObjectUsingMask
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS MotionBlurObjectUsingMaskPS();
    CullMode = None;      
  }
}

technique MotionBlurObjectMask
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS MotionBlurObjectMaskPS();
    CullMode = None;      
  }
}

technique OMB_VelocityIDRescale
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS OMB_VelocityIDRescalePS();
    CullMode = None;      
  }
}

technique OMB_VelocityDilation
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS OMB_VelocityDilationPS();
    CullMode = None;      
  }
}

technique OMB_UsingVelocityDilation
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS OMB_UsingVelocityDilationPS();
    CullMode = None;      
  }
}

#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Depth of field technique ///////////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

#define DOF_ANAMORPHIC_LENS 0
#define DOF_OPTICAL_SIMULATION 1
#define DOF_USE_NOISE 0

/// Constants ////////////////////////////

float4 dofParamsFocus;
float4 dofParamsBlur;
float4 pixelSizes;
float radiusScale = 0.4;
float dofMinThreshold = 0.2;//0.5; // to ensure a smoother transition between near focus plane and focused area

/// Samplers /////////////////////////////

///////////////// vertex shader //////////////////

///////////////// pixel shader //////////////////
float GetDepthBlurred( sampler2D _tex0, half2 baseTC, float depthOrig, half blurAmount )
{  
	half2 pixelSizes = PS_ScreenSize.zw * 4.h * dofParamsFocus.w;
	float baseColor = depthOrig;
	float weightSum = 1.0;
		
	#if D3D10
	[unroll]
	#endif
	for(int i=1; i<8; i++)
	{
		float weight = lerp(1, 0, (float)i/8.f);
		float blurredDepth = GetDepthMapScaled(_tex0, baseTC.xy + i * pixelSizes);
		blurredDepth += GetDepthMapScaled(_tex0, baseTC.xy - i * pixelSizes);
		blurredDepth *= 0.5;
		blurredDepth = (blurredDepth < depthOrig) ? blurredDepth : depthOrig;
		baseColor += blurredDepth * weight;
		weightSum += weight;
	}
     
    float fDepth = baseColor / (weightSum + 1e-6); 
	return fDepth;
}

half GetDepthBlurinessBiased(half fDepth)
{
  half f=0; 

  // 0 - in focus
  // 1 or -1 - completely out of focus
    
  if(fDepth>(half)dofParamsFocus.y)
  {
    f=(fDepth-(half)dofParamsFocus.y)/(half)dofParamsFocus.z; // max range
    f=clamp(f, 0, 1-(half)dofMinThreshold);   
  }
  else
  if(fDepth<=(half)dofParamsFocus.x)
  {   
    f=(1-fDepth/dofParamsFocus.x)/dofParamsFocus.w;  // min range
  }
  
  return f;
}

pixout CopyDepthToAlphaBiasedNoMaskPS(vtxOut IN)
{
  pixout OUT;  

  half depthMap = GetDepthMap(_tex0, IN.baseTC.xy);        	
  half depthNormalized =depthMap.x*PS_NearFarClipDist.y;
  half depth = (GetDepthBlurinessBiased(depthNormalized))*dofParamsFocus.w;	  

  // Generate a blurred depth image.
  half blurred = GetDepthBlurred(_tex0, IN.baseTC.xy, depthNormalized, dofParamsFocus.w).x;
  blurred = (GetDepthBlurinessBiased(blurred))*dofParamsFocus.w;
			 	
  // Compare blurred depth and unblurred depth.		
  if( blurred >= depth )
	  depth = blurred;
	
  // Encode magnification mask into first pixel.  
  //if((IN.baseTC.x <= PS_ScreenSize.z) && (IN.baseTC.y <= PS_ScreenSize.w)) depth = 0.0;

#if %_RT_SAMPLE0
  half3 cScreen = max( tex2D(_tex1, IN.baseTC.xy).xyz, 0);

  // do same nan check as in hdr pass
  cScreen.rgb = (cScreen.rgb> 10000.0f)? half3(1, 1, 1): cScreen.rgb;
  //if(abs(dot(cScreen, 0.333)) > 10000.0f) cScreen = 1.0f; // more stable/less flicker

  OUT.Color.xyzw = half4( cScreen.xyz, (depth*0.5+0.5) );
#else
  OUT.Color = (depth*0.5+0.5);
#endif
  
  return OUT;
}

pixout CopyDepthToAlphaBiasedPS(vtxOut IN)
{
  pixout OUT;  
        
  half depthMap = GetDepthMap(_tex0, IN.baseTC.xy);  
  half depthMaskColor = tex2D(_tex1, IN.baseTC.xy).x;  
      	
  half depthNormalized =depthMap.x*PS_NearFarClipDist.y;
  half depth = (GetDepthBlurinessBiased(depthNormalized) * depthMaskColor)*dofParamsFocus.w;	  

  // Generate a blurred depth image.
  half blurred = GetDepthBlurred(_tex0, IN.baseTC.xy, depthNormalized, dofParamsFocus.w).x;
  blurred = (GetDepthBlurinessBiased(blurred) * depthMaskColor)*dofParamsFocus.w;
	 
  // Compare blurred depth and unblurred depth.				 				
  if( blurred >= depth )
	  depth = blurred;

  // Encode magnification mask into first pixel.
  //if((IN.baseTC.x <= PS_ScreenSize.z) && (IN.baseTC.y <= PS_ScreenSize.w)) depth = 0.0;

#if %_RT_SAMPLE0
  half3 cScreen = max( tex2D(_tex2, IN.baseTC.xy).xyz, 0);


  //cScreen = max( min( cScreen, (float3)10000000 ), 0 );
  // do same nan check as in hdr pass
  cScreen.rgb = (cScreen.rgb> 10000.0f)? half3(1, 1, 1): cScreen.rgb;
  //if(abs(dot(cScreen, 0.333)) > 10000.0f) cScreen = 1.0f; // more stable/less flicker

  OUT.Color.xyzw = half4( cScreen.xyz, (depth*0.5+0.5) );

#else
  OUT.Color = (depth*0.5+0.5);
#endif
  
  return OUT;
}

half GetDepthBluriness(half fDepth)
{  
  half f=fDepth-(half)dofParamsFocus.z;
  
  // 0 - in focus
  // 1 or -1 - completely out of focus
    
  float focalLength = 60.0;
  float A = dofParamsFocus.w * 0.01;
  float focalPlane = f;
  float zFar = PS_NearFarClipDist.y;
  float zNear = PS_NearFarClipDist.x;
  
  half discScale = (A * focalLength * focalPlane * (zFar-zNear)) / ((focalPlane-focalLength) * zNear * zFar);
  half discBias = (A * focalLength * (zNear-focalPlane)) / ((focalPlane * focalLength)*zNear);
  
  f = abs(fDepth * discScale + discBias);
    
  if(fDepth<(half)dofParamsFocus.z)
  {
    f/=(half)dofParamsFocus.x;   
  }
  else
  {
    f/=(half)dofParamsFocus.y;         
    f=clamp(f, 0, 1-(half)dofMinThreshold);   
  }
  
  return f;
}

pixout CopyDepthToAlphaNoMaskPS(vtxOut IN)
{
  pixout OUT;  
        
  half depthMap = GetDepthMap(_tex0, IN.baseTC.xy);        	
  half depthNormalized = depthMap.x*PS_NearFarClipDist.y;	  
  half depth = saturate(GetDepthBluriness(depthNormalized))*dofParamsFocus.w;	  

  // Generate a blurred depth image.
  half blurred = GetDepthBlurred(_tex0, IN.baseTC.xy, depthNormalized, dofParamsFocus.w).x;
  blurred = saturate(GetDepthBluriness(blurred))*dofParamsFocus.w;
  
  // Compare blurred depth and unblurred depth.				 				
  if( blurred >= depth )
	  depth = blurred;

  // Encode magnification mask into first pixel.
  //if((IN.baseTC.x <= PS_ScreenSize.z) && (IN.baseTC.y <= PS_ScreenSize.w)) depth = 1.0;

#if %_RT_SAMPLE0
  half3 cScreen = max( tex2D(_tex1, IN.baseTC.xy).xyz, 0);

  // do same nan check as in hdr pass
  cScreen.rgb = (cScreen.rgb> 10000.0f)? half3(1, 1, 1): cScreen.rgb;
  //if(abs(dot(cScreen, 0.333)) > 10000.0f) cScreen = 1.0f; // more stable/less flicker

  OUT.Color.xyzw = half4( cScreen.xyz, (depth*0.5+0.5) );

#else
  OUT.Color = (depth*0.5+0.5);
#endif
  
  return OUT;
}

pixout CopyDepthToAlphaPS(vtxOut IN)
{
  pixout OUT;  
   
  half depthMap = GetDepthMap(_tex0, IN.baseTC.xy);  
  half depthMaskColor = tex2D(_tex1, IN.baseTC.xy).x; 
      	
  half depthNormalized =depthMap.x*PS_NearFarClipDist.y;
  half depth = saturate((GetDepthBluriness(depthNormalized))*depthMaskColor + depthMaskColor)*dofParamsFocus.w;

  // Generate a blurred depth image.
  half blurred = GetDepthBlurred(_tex0, IN.baseTC.xy, depthNormalized, dofParamsFocus.w).x;
  blurred = saturate((GetDepthBluriness(blurred))*depthMaskColor + depthMaskColor)*dofParamsFocus.w;
  
  // Compare blurred depth and unblurred depth.				 				
  if( blurred >= depth )
	  depth = blurred;

  // Encode magnification mask into first pixel.
  //if((IN.baseTC.x <= PS_ScreenSize.z) && (IN.baseTC.y <= PS_ScreenSize.w)) depth = 1.0;

#if %_RT_SAMPLE0
  half3 cScreen = max( tex2D(_tex2, IN.baseTC.xy).xyz, 0);

  // do same nan check as in hdr pass
  cScreen.rgb = (cScreen.rgb> 10000.0f)? half3(1, 1, 1): cScreen.rgb;
  //if(abs(dot(cScreen, 0.333)) > 10000.0f) cScreen = 1.0f; // more stable/less flicker

  OUT.Color.xyzw = half4( cScreen.xyz, (depth*0.5+0.5) );

#else
  OUT.Color = (depth*0.5+0.5);
#endif
  
  return OUT;
}

half4 DOFMergeLayers(half4 tapLow, half4 tapMed, half4 tapHigh, half centerDepth)
{
	  half4 cOut = 0;
	  half4 weights = saturate( centerDepth * half4( -2, -4, -4, 4 ) + half4( 1, 3, 4, -3) );
	  weights.yz = min( weights.yz, 1 - weights.xy );
	  	
	  cOut.xyz = weights.y * tapHigh.xyz + weights.z * tapMed.xyz + weights.w * tapLow.xyz;
	  cOut.a = dot( weights.yzw, half3(16.0f / 17.0f, 1.0f, 1.0f) );
	  
	  return cOut;
}

pixout DofHDRPS(vtxOut IN)
{
  pixout OUT;
  
  int nQuality = GetShaderQuality();

  const int tapCount = 37;
  // xy = poisson coordinates, z = aberration intensity
  float3 poisson[37] =
  {		
		 0.0,   0.0,  1.0,		 
		-1.0,   0.0,  1.0,
		-2.0,   0.0,  1.0,
		-3.0,   0.0,  1.5,
		 3.0,   0.0,  1.5,
		 2.0,   0.0,  1.0,
		 1.0,   0.0,  1.0, // 7
		 0.0,   1.0,  1.0,
		 0.0,   2.0,  1.0,
		 0.0,   3.0,  8.0,
	 	 0.0,  -3.0,  1.5,
		 0.0,  -2.0,  1.0,
		 0.0,  -1.0,  1.0, // 13
		-0.75,  0.75, 1.0,
		-1.75,  1.0,  1.0,
		-2.75,  1.0,  2.0,
		 2.75,  1.0,  2.0,
		 1.75,  1.0,  1.0,
		 0.75,  0.75, 1.0, // 19
		-0.75, -0.75, 1.0,
		-1.75, -1.0,  1.0,
		-2.75, -1.0,  1.5,
		 2.75, -1.0,  1.5,
		 1.75, -1.0,  1.0,
		 0.75, -0.75, 1.0, // 25
		-2.0,   2.0,  6.0,	 
		-2.0,  -2.0,  1.5,
		-1.0,  -1.75, 1.0,
		 1.0,  -1.75, 1.0,
		 2.0,  -2.0,  1.5,
		 2.0,   2.0,  6.0, // 31
		-1.0,   1.75, 1.0,
		-1.0,   2.75, 8.0,
		 1.0,   2.75, 8.0,
		-1.0,  -2.75, 1.5,
		 1.0,  -2.75, 1.5,
		 1.0,   1.75, 1.0, // 37
  };
    
  // Magnify image based on focus distance.
  //float fMagMask = tex2D(_tex0, float2(0.0, 0.0)).a*2-1;
  //if(fMagMask)
	//IN.baseTC.xy = (IN.baseTC.xy - 0.5) * lerp(0.9875f, 1.0f, saturate(dofParamsFocus.z * 0.1)) + 0.5;
  
  // Initial scene.
  OUT.Color = tex2D(_tex0, IN.baseTC.xy);

  // fetch center tap from blured low res image
  float centerDepth = tex2D(_tex1, IN.baseTC.xy).a; 
  //float centerDepth = tex2D(_tex0, IN.baseTC.xy).a; 
    
  // Early out if there's no visual difference.
  if(centerDepth < 0.01)
  {		
	  return OUT;
  }
                   
  float2 vNoise = 0.0;
  if(DOF_USE_NOISE == 1)
  {
	  float2 vNoiseTC = IN.baseTC.xy * PS_ScreenSize.xy / 64.0;
	  vNoise = tex2Dlod(_tex2, float4(vNoiseTC, 0, 0)) + dot(IN.baseTC.xy, 1) * 65535;
	  vNoise = frac( vNoise );
	  vNoise = vNoise*2-1;
	  vNoise *= 0.05;
  }
      
  // Calculate aspect ratio.
  half2 fAspectRatio = 1.0f;
  if(DOF_ANAMORPHIC_LENS == 1)
	  fAspectRatio = half2(1.333f, 2.4f) / 2.4f;

  // Calculate radius.
  half discRadius=(centerDepth*(half)dofParamsBlur.y-(half)dofParamsBlur.x);
  
  half4 texSizes = pixelSizes.xyzw * discRadius * fAspectRatio.xyxy;
  texSizes.zw *= (half)radiusScale;

  // Calculate vignette.
  float2 coordN = IN.baseTC.xy * 2.0 - 1.0;
  float vignette = saturate(dot(coordN, coordN)-0.25);
    
  // Rotation masks.
  float2 vignetteMask = saturate(coordN) + saturate(-coordN);
  
  // Create a rotation matrix based on screen coordinates.
  float2x2 rotationMatrixX = RotationMatrix((-coordN.x * (PI*0.5)) * vignetteMask.x);
  float2x2 rotationMatrixY = RotationMatrix(((1-IN.baseTC.y) * PI) * vignetteMask.y);
  float2x2 rotationMatrix = mul(rotationMatrixY, rotationMatrixX);

  // Go through samples and sum.
  half4 cOut = 0;
  half4 cSumWeights = 0;
  
#if D3D10
  [unroll]
#endif
  for(int t=0; t<tapCount; t++)
  { 
	  //poisson[t].xy = float2( poisson[t].x * 0.866 - poisson[t].y * 0.5, poisson[t].x * 0.5 + poisson[t].y * 0.866 ); // 30 deg rot
	  //poisson[t].xy = 0.707 * poisson[t].xy + 0.707 * float2( - poisson[t].y, poisson[t].x); // 45 deg rot

	  // Rotate poisson using matrix.
	  poisson[t].xy = mul(rotationMatrix, poisson[t].xy);
				
	  // Scale aberration outwards of the screen for aberration vignetting.
	  poisson[t].z = lerp(1.0, poisson[t].z, vignette);
		  
	  float4 tapCoord = IN.baseTC.xyxy + (poisson[t].xyxy + vNoise.xyxy) * texSizes.xyzw;

	  half4 tapHigh = tex2Dlod(_tex0, float4(tapCoord.xy, 0, 0));
	  half4 tapLow = tex2Dlod(_tex1, float4(tapCoord.zw, 0, 0));
		 	      	  
	  //half tapLerp = (tapHigh.a * 2.0 - 1.0);        
	  //half4 tap = lerp(tapHigh, tapLow, saturate(tapLerp));    
	  half4 tap = DOFMergeLayers(tapLow, tapLow, tapHigh, centerDepth);
	  half tapA = tap.a;
		    
	  // Apply leak reduction. Make sure only to reduce on focused areas            
	  tap.a = (tapLow.a - centerDepth + (half)dofMinThreshold > 0.0) ? 1 : saturate(tap.a * 2.0 - 1.0);    
	  //tap.a = (tapHigh.a - centerDepth + (half)dofMinThreshold > 0.0) ? 1 : saturate(tapHigh.a * 2.0 - 1.0);    
   
   
	  // High-res only.
	  //float2 tapCoord = IN.baseTC.xy + (poisson[t].xy + vNoise.xy) * texSizes.xy;
	  //half4 tap = tex2Dlod(_tex0, float4(tapCoord.xy, 0, 0));
	      
	  //tap.a = (tap.a - centerDepth + (half)dofMinThreshold > 0.0) ? 1 : saturate(tap.a * 2.0 - 1.0);    
		     
	  half4 bokehColor = poisson[t].z;
	  if(bokehColor.x > 1.0)
		bokehColor *= half4(0.5, 1.0, 1.0, 1.0);
		             
	  cOut += tap.a * tap * bokehColor;
	  cSumWeights += tap.a * bokehColor;
  }
   
  OUT.Color = cOut/(cSumWeights + 1e-6);
		  		
  return OUT;
}

pixout DofPS(vtxOut IN)
{
  pixout OUT;

  int nQuality = GetShaderQuality();

  const int tapCount = 8;

  float2 poisson[8] =
  {
       0.0,    0.0,
     0.527, -0.085,
    -0.040,  0.536,
    -0.670, -0.179,
    -0.419, -0.616,
     0.440, -0.639,
    -0.757,  0.349,
     0.574,  0.685,
  };
   
  half4 cOut=0;
  half discRadius;
  half discRadiusLow;
  half centerDepth;
        
#if D3D10	
  // temporary workaround for d3d10 hlsl compiler bug
  OUT.Color = tex2D(_tex0, IN.baseTC.xy);
#endif
        
  // fetch center tap from blured low res image
  centerDepth=tex2D(_tex1, IN.baseTC.xy).w;    
  //centerDepth=tex2D(_tex0, IN.baseTC.xy).w;    

  discRadius=(centerDepth*(half)dofParamsBlur.y-(half)dofParamsBlur.x);
  discRadiusLow=discRadius*(half)radiusScale;
  
  pixelSizes.xy=(half2)pixelSizes.xy*discRadius;
  pixelSizes.wz=(half2)pixelSizes.zw*discRadiusLow;

#if D3D10
  [unroll]
#endif
  for(int t=0; t<tapCount; t++)
  { 
    half4 tapHigh=tex2D(_tex0, IN.baseTC.xy+ poisson[t]*(half2)pixelSizes.xy);                
    half4 tapLow=tex2D(_tex1, IN.baseTC.xy+ poisson[t]*(half2)pixelSizes.wz);        
    
    // Gamma correct (for linear-space blending)
	tapHigh.rgb *= tapHigh.rgb;
	tapLow.rgb *= tapLow.rgb;
        
    half tapLerp=(tapHigh.a*2.0-1.0);        
    half4 tap=lerp(tapHigh, tapLow, saturate(tapLerp));    
    
    // Apply leak reduction. Make sure only to reduce on focused areas            
    tap.a=(tapLow.a-centerDepth+(half)dofMinThreshold>0.0)? 1: saturate(tap.a*2.0-1.0);    
   
    //half4 tap=tex2D(_tex0, IN.baseTC.xy+ poisson[t]*(half2)pixelSizes.xy);                
   	//tap.rgb *= tap.rgb; // Gamma correct (for linear-space blending)

    cOut.xyz+=tap.a*tap.xyz;
    cOut.w+=tap.a;
  }
                            
  OUT.Color = cOut/cOut.w;
  
  // Gamma correct (for linear-space blending)
  OUT.Color.rgb = sqrt(OUT.Color.rgb);
  
  return OUT;
}

////////////////// technique /////////////////////

technique CopyDepthToAlphaNoMask
{
  pass p0
  {        
    CullMode = None;        

         
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS CopyDepthToAlphaNoMaskPS();    
  }
}

technique CopyDepthToAlphaBiasedNoMask
{
  pass p0
  {        
    CullMode = None;        
            
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS CopyDepthToAlphaBiasedNoMaskPS();    

  }
}

technique CopyDepthToAlpha
{
  pass p0
  {        
    CullMode = None;        

    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS CopyDepthToAlphaPS();    

  }
}

technique CopyDepthToAlphaBiased
{
  pass p0
  {        
    CullMode = None;        
            
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS CopyDepthToAlphaBiasedPS();    

  }
}

technique DepthOfField
{
  pass p0
  {        
    CullMode = None;        
    
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS DofPS();    
  }
}

#if %DYN_BRANCHING_POSTPROCESS

technique DepthOfFieldHDR
{
  pass p0
  {        
    CullMode = None;        
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS DofHDRPS();
  }
}

#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Perspective Warp      //////////////////////////////////////////////////////////////////////////

struct a2v_perspectiveWarp
{
  float4 pos : POSITION;
};

struct v2f_perspectiveWarp
{
  float4 pos : POSITION;
  float2 tex : TEXCOORDN;
};

v2f_perspectiveWarp PerspectiveWarpVS( a2v_perspectiveWarp IN )
{
  v2f_perspectiveWarp OUT = (v2f_perspectiveWarp) 0; 

	const float pi = 3.141592;

	//float aspectRatio = 1022.0 / 683.0;
	//float aspectRatio = g_VS_ScreenSize.x / g_VS_ScreenSize.y;
	float aspectRatio = 1.3333;

  float normFovX = 60.0;
  float normFovY = normFovX / aspectRatio;	
	
  //float newFovX = 110.0;
  float newFovX = 90.0;
  float newFovY = newFovX / aspectRatio;  

  float scaleX = 1.0- ( normFovX / newFovX ); 
  float scaleY = 1.0 - ( normFovY / newFovY ); 

  float ratioX = ( newFovX / normFovX ) / pi;
  float ratioY = ( newFovY / normFovY ) / pi;  

	float2 normalizedPos = IN.pos.xy;		
	normalizedPos.y = -normalizedPos.y;	

	float angX = normalizedPos.x * newFovX * 0.5;
  float angY = normalizedPos.y * newFovY * 0.5;
  
  float2 warpedPos;
  warpedPos.x = ratioX * asin( scaleX * normalizedPos.x );
  warpedPos.y = ratioY * asin( scaleY * normalizedPos.y );   
  
  warpedPos.x /= cos( angX * pi / 180.0 );
  warpedPos.y /= cos( angY * pi / 180.0 );

  //warpedPos.x += sin( scaleX * normalizedPos.x );                
  //warpedPos.y += sin( scaleY * normalizedPos.y );           

  warpedPos.x += (1.0-scaleX) * sin( angX * pi / 180.0 );                
  warpedPos.y += (1.0-scaleY) * sin( angY * pi / 180.0 );           

  OUT.pos = float4( IN.pos.xy, 0, 1 );        
  OUT.tex = warpedPos * 0.5 + 0.5;        
 

	float finalFOV = 60.0;
	float currentFOV = 110.0;
	
	float fovRatio =  ( currentFOV / finalFOV ) / 3.141592;
		
  OUT.pos = IN.pos ;        
  OUT.pos.zw = float2( 0, 1 );            

	float2 normalizedPos = IN.pos.xy;		
	normalizedPos.y = -normalizedPos.y;	
	
	float t = ( currentFOV / finalFOV ) / 2.0; 

  //OUT.tex.x = normalizedPos.x; 
  //OUT.tex.y = normalizedPos.y; 
	OUT.tex.x = fovRatio * asin( t * normalizedPos.x );	
	OUT.tex.y = fovRatio * asin( t * normalizedPos.y );			
	
	OUT.tex.xy = OUT.tex.xy * 0.5 + 0.5;		


  return OUT;
}

pixout PerspectiveWarpPS( v2f_perspectiveWarp IN )
{
  pixout OUT;
  
	OUT.Color = tex2D( screenMapSampler, IN.tex.xy );			
	
  return OUT;
}

technique PerspectiveWarp
{
  pass p0
  {
    VertexShader = CompileVS PerspectiveWarpVS();       
    PixelShader = CompilePS PerspectiveWarpPS();
    CullMode = None;
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Glittering techniques//////////////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

/// Constants ////////////////////////////

float4 glitterParams;
float4 glitterSprParams;

float4 camUpVector;
float4 camRightVector;

/// Samplers ////////////////////////////

sampler2D glitterScaledMap_d2 : register(s1);
sampler2D glitterScaledMap_d4 : register(s2);

sampler2D glitterSpriteSampler = sampler_state
{
  Texture = textures/defaults/glitter_sprite.dds;
  MinFilter = LINEAR;
  MagFilter = LINEAR;
  MipFilter = LINEAR; 
  AddressU = Clamp;
  AddressV = Clamp;
};

///////////////// vertex shader //////////////////

struct vtxInGlitterSprite
{
  IN_P    
  float3 baseTC : TEXCOORDN;
};

struct vtxOutGlitterSprite
{
  float4 HPosition  : POSITION;
  float3 baseTC     : TEXCOORDN;
  float4 glitCol    : TEXCOORDN;
  float4 screenPos  : TEXCOORDN;
};

///////////////// vertex shader //////////////////

vtxOutGlitterSprite glitterSpriteVS(vtxInGlitterSprite IN)
{

  vtxOutGlitterSprite OUT = (vtxOutGlitterSprite)0; 

  float4 vPos = float4(IN.Position.xyz, 1.0);
  
  // Get view vector  
  float3 viewVec = (vPos.xyz-g_VS_WorldViewPos.xyz);  
  
  // Compute sprite size
  float fDistToCam=length(viewVec);    
  float fSize=(fDistToCam/220.0)*clamp(glitterParams.w, 0.0, 2.0);  // 220.0f -> value tweaked by hand by MK...
        
  // Compute vertex coordinates based on camera right/up vector and texture coordinates
  float2 scale = fSize*2.0*(IN.baseTC.xy - 0.5);    
  
  vPos.z+=fSize*1.25; // try not to intersect with terrain
  vPos.xyz+=(camRightVector.xyz*scale.x + camUpVector.xyz*scale.y);
    
  OUT.HPosition = mul(vpMatrix, vPos);  
  OUT.baseTC.xy = float2(IN.baseTC.x, 1-IN.baseTC.y);

  // Generate a normal based on position
  float3 normalVec = normalize(frac(IN.Position.xyz*100.0)*2.0-1.0);      
  
  // Compute attenuation term
  float attenDist=sqrt(IN.baseTC.z);    
  float fAttenuation=saturate(1.0-fDistToCam/attenDist);
     
  // Compute view dependency
  float3 camDir=normalize(-vpMatrix[2].xyz);
  float NdotV=dot(normalVec.xyz, camDir.xyz);
  
  // Compute glint term:
  // - 1. use fractional part of distance to camera
  // - 2. modulate absolute result by visibility term powered by some factor 
  float glintTerm=abs(frac((attenDist-fDistToCam)*0.5*glitterParams.x)*2-1)*saturate(4*pow(NdotV*0.5+0.5, glitterParams.y));
    
  // Final term is glint*distance attenuation
  OUT.glitCol.xyz= fAttenuation*glintTerm;
  
  // Cull sprite (todo: check performance gains, if any at all)
  if(OUT.glitCol.z<0.01)
  {
    OUT.HPosition=0;  
  }
    
  OUT.glitCol.w= NdotV;
  OUT.baseTC.z = fAttenuation;
  
  // Output screen space position for alpha masking
  OUT.screenPos = HPosToScreenTC(OUT.HPosition);
    
  return OUT;
}

///////////////// pixel shader //////////////////

// Used for glitter particles
pixout glitterSpritePS(vtxOutGlitterSprite IN)
{
  pixout OUT;
  half4 baseColor = tex2D(glitterSpriteSampler, IN.baseTC.xy);      
  half  screenAlphaColor = pow(tex2D(screenMapSampler, IN.screenPos.xy/IN.screenPos.ww).w, 16);
  
  half4  screenColor = tex2D(screenMapSampler, IN.baseTC.xy);

  // Fake chromatic Aberration  
  half4 chromAb = IN.glitCol+IN.glitCol*tex2D(rainbowSampler, IN.glitCol.ww);
  
  half3 final=chromAb.xyz*baseColor.xyz;
  // mask out alpha stuff
  OUT.Color.xyz=final.xyz;/screenAlphaColor;
  
  half lum= dot(final.xyz, half3(0.33, 0.59, 0.11));
  OUT.Color.w= lum;
  
  return OUT;
}

// Glitering final pass (used if glitterGlare on)
pixout glitteringPassPS(vtxOut IN)
{
  pixout OUT;
  half4 baseColor = tex2D(_tex0, IN.baseTC.xy);      
    
  half4 glitterColor_d2 = tex2D(glitterScaledMap_d2, IN.baseTC.xy);      
  half4 glitterColor_d4 = tex2D(glitterScaledMap_d4, IN.baseTC.xy);        
  
  baseColor.xyz+=glitterColor_d2.w*glitterColor_d2.xyz*(1-baseColor.xyz)*2.0;    
  baseColor.xyz+=glitterColor_d4.w*glitterColor_d4.xyz*(1-baseColor.xyz)*2.0;    
  OUT.Color=baseColor;
  
  return OUT;
}

////////////////// technique /////////////////////

technique GlitterSprites
{
  pass p0
  {
    VertexShader = CompileVS glitterSpriteVS();
    PixelShader = CompilePS glitterSpritePS();      
    
    CullMode = None;   
    SrcBlend = ONE;
    DestBlend = ONE;
    AlphaBlendEnable = true;
    ZWriteEnable = false;
  }
}

technique GlitteringPass
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS glitteringPassPS();      
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Glow technique //////////////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

/// Constants ////////////////////////////

float4 glowParamsPS;

/// Samplers ////////////////////////////

sampler2D glowMap_RT1 : register(s1);
sampler2D glowMap_RT2 : register(s2);
sampler2D glowMap_RT3 : register(s3);

struct vtxInGlow
{
  IN_P
  IN_TBASE
  float3 CamVec    : TEXCOORD1;  
};

struct vtxOutGlow
{
  float4 HPosition  : POSITION; 
  float2 baseTC       : TEXCOORD0;
  float3 CamVec       : TEXCOORD1;  
};

vtxOutGlow GlowGenVS(vtxInGlow IN)
{
  vtxOutGlow OUT = (vtxOutGlow)0; 

  // Position in screen space.
  float4 vPos = IN.Position;
  OUT.HPosition = mul(vpMatrix, vPos);  
  
  OUT.baseTC.xy = IN.baseTC.xy;
  OUT.CamVec.xyz = IN.CamVec.xyz;

  return OUT;
}

///////////////// pixel shader //////////////////

pixout SceneLuminancePassPS(vtxOut IN)
{
  pixout OUT;
  
  half4 tex_screen = tex2D( _tex0, IN.baseTC.xy );
  
  half fLum = saturate( dot(tex_screen.xyz, float3(0.33, 0.59, 0.11))  ) ;
  
  OUT.Color = half4(fLum.xxx, 0.02);
  
  return OUT;
}

pixout GlowBrightPassPS(vtxOut IN)
{
  pixout OUT;
  
  half4 tex_screen = tex2D(_tex0, IN.baseTC.xy);
  half4 tex_glow = tex2D(_tex1, IN.baseTC.xy);
  half4 tex_eyeadjust = tex2D(_tex2, IN.baseTC.xy);
  
  tex_screen = max(tex_screen - glowParamsPS.z, 0.0)/(tex_screen+glowParamsPS.z);
  tex_screen *= (1 - tex_eyeadjust) * glowParamsPS.w;
  //tex_screen *= (1 - tex_eyeadjust);
  
  //OUT.Color = tex_screen;//1 - exp( - ( tex_screen  + tex_glow ) );
  OUT.Color =  ( tex_screen  + tex_glow )  ;
  
  return OUT;
}

////////////////////////////////////////////////////////
// Merged shader for screen-space SSS and non-HDR glow.

float3 SubsurfaceSample(sampler2D screenMap, float4 baseTC)
{
	float3 Sample = tex2Dlod( screenMap, baseTC );
	//return (Sample*Sample);
	return pow(Sample, 2.2f);
}

pixout MergeSkinAndGlowPS(vtxOut IN)
{
  pixout OUT = (pixout)0;
  
  // Sample scene.
  half4 cScreen = tex2D(_tex0, IN.baseTC.xy);
  OUT.Color = cScreen;

  //------------------------------------------------------------------------------------
  // Glow (holograms, etc.)
  //------------------------------------------------------------------------------------
  half4 tex_glow1 = tex2D(_tex1, IN.baseTC.xy);
  half4 tex_glow2 = tex2D(_tex2, IN.baseTC.xy);
  half4 tex_glow3 = tex2D(_tex3, IN.baseTC.xy);

  // Sum up results    
  half4 final_glow = (tex_glow1 + tex_glow2 + tex_glow3) * glowParamsPS.w;

  //------------------------------------------------------------------------------------
  // Screen-space SSS, 3 layer poisson (21-tap) apporimxation.
  //------------------------------------------------------------------------------------
  const float2 poisson[7] =
  {
     float2(0.527, -0.085), float2(-0.040,  0.536), float2(-0.670, -0.179), float2(-0.419, -0.616), 
     float2(0.440, -0.639), float2(-0.757,  0.349), float2(0.574,  0.685),
  };

  // Layer weights.
  const float3 cSkinWeights[4] =
  {
	   float3(0.333, 0.791, 0.993), float3(0.231, 0.205, 0.007),
	   float3(0.385, 0.004, 0.0), float3(0.078, 0.0, 0.0)
  };
  
  // Sample stretchmap/mask/blur weights from texture
  float fBlurStrength = (tex_glow1.a * tex_glow1.a);// * 2.0;//tex2D(_tex1, IN.baseTC.xy).a;
    
  // Only calculate SSS if the mask is positive (no skin, high-frequency, etc).
  if(fBlurStrength)
  {	 
	  // Calculate blur scale
  	  float2 vKernelScale = 16.0f * fBlurStrength * PS_ScreenSize.zw;// * 2.0f;
	  float3 cLayer0 = pow(cScreen, 2.2f);
 	  //float3 cLayer0 = (cScreen*cScreen);
 
	  // Second layer.
	  float3 cLayer1 = cLayer0;
	  cLayer1 += SubsurfaceSample(_tex0, float4( IN.baseTC.xy + poisson[0] * vKernelScale, 0.0, 0.0));
  	  cLayer1 += SubsurfaceSample(_tex0, float4( IN.baseTC.xy + poisson[1] * vKernelScale, 0.0, 0.0));
  	  cLayer1 += SubsurfaceSample(_tex0, float4( IN.baseTC.xy + poisson[2] * vKernelScale, 0.0, 0.0));
  	  cLayer1 += SubsurfaceSample(_tex0, float4( IN.baseTC.xy + poisson[3] * vKernelScale, 0.0, 0.0));
  	  cLayer1 += SubsurfaceSample(_tex0, float4( IN.baseTC.xy + poisson[4] * vKernelScale, 0.0, 0.0));
  	  cLayer1 += SubsurfaceSample(_tex0, float4( IN.baseTC.xy + poisson[5] * vKernelScale, 0.0, 0.0));
  	  cLayer1 += SubsurfaceSample(_tex0, float4( IN.baseTC.xy + poisson[6] * vKernelScale, 0.0, 0.0));
	  cLayer1 *= 0.125f;

	  // Scale kernel for next layer.
	  vKernelScale *= float2(2.0, -2.0);

	  // Third layer.
	  float3 cLayer2 = cLayer1;
	  cLayer2 += SubsurfaceSample(_tex0, float4( IN.baseTC.xy + poisson[0] * vKernelScale, 0.0, 0.0));
  	  cLayer2 += SubsurfaceSample(_tex0, float4( IN.baseTC.xy + poisson[1] * vKernelScale, 0.0, 0.0));
  	  cLayer2 += SubsurfaceSample(_tex0, float4( IN.baseTC.xy + poisson[2] * vKernelScale, 0.0, 0.0));
  	  cLayer2 += SubsurfaceSample(_tex0, float4( IN.baseTC.xy + poisson[3] * vKernelScale, 0.0, 0.0));
  	  cLayer2 += SubsurfaceSample(_tex0, float4( IN.baseTC.xy + poisson[4] * vKernelScale, 0.0, 0.0));
  	  cLayer2 += SubsurfaceSample(_tex0, float4( IN.baseTC.xy + poisson[5] * vKernelScale, 0.0, 0.0));
  	  cLayer2 += SubsurfaceSample(_tex0, float4( IN.baseTC.xy + poisson[6] * vKernelScale, 0.0, 0.0));
	  cLayer2 *= 0.125f;
	  
	  // Scale kernel for next layer.
	  vKernelScale *= float2(-4.0, -4.0);
	  
	  // Fourth layer.
	  float3 cLayer3 = cLayer2;
	  cLayer3 += SubsurfaceSample(_tex0, float4( IN.baseTC.xy + poisson[0] * vKernelScale, 0.0, 0.0));
  	  cLayer3 += SubsurfaceSample(_tex0, float4( IN.baseTC.xy + poisson[1] * vKernelScale, 0.0, 0.0));
  	  cLayer3 += SubsurfaceSample(_tex0, float4( IN.baseTC.xy + poisson[2] * vKernelScale, 0.0, 0.0));
  	  cLayer3 += SubsurfaceSample(_tex0, float4( IN.baseTC.xy + poisson[3] * vKernelScale, 0.0, 0.0));
  	  cLayer3 += SubsurfaceSample(_tex0, float4( IN.baseTC.xy + poisson[4] * vKernelScale, 0.0, 0.0));
  	  cLayer3 += SubsurfaceSample(_tex0, float4( IN.baseTC.xy + poisson[5] * vKernelScale, 0.0, 0.0));
  	  cLayer3 += SubsurfaceSample(_tex0, float4( IN.baseTC.xy + poisson[6] * vKernelScale, 0.0, 0.0));
	  cLayer3 *= 0.125f;
	  	  	  	  
	  // Sum each layer with respective weights.
      float3 cSkinDiffusion = cLayer0 * cSkinWeights[0];
      cSkinDiffusion += cLayer1 * cSkinWeights[1];			
	  cSkinDiffusion += cLayer2 * cSkinWeights[2];		
	  cSkinDiffusion += cLayer3 * cSkinWeights[3];		
	              
	  // Back to gamma space.     
  	  OUT.Color.rgb = pow(cSkinDiffusion, 1.0f/2.2f);
  	  //OUT.Color.rgb = sqrt(cSkinDiffusion);
  }
   
  //------------------------------------------------------------------------------------
  // Glow output (holograms, etc.)
  //------------------------------------------------------------------------------------
              
  // Apply glow at the very end.
  OUT.Color.rgb += final_glow; 

  return OUT;
}

////////////////// technique /////////////////////

technique SceneLuminancePass
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS SceneLuminancePassPS();    
    CullMode = None;        
  }
}

technique GlowBrightPass
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS GlowBrightPassPS();    
    CullMode = None;        
  }
}

technique MergeSkinAndGlow
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS MergeSkinAndGlowPS();    
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// GlowScene: copies glow into backbuffer /////////////////////////////////////////////////////////

/// Specific data ////////////////////////

/// Constants ////////////////////////////

////////////////// samplers /////////////////////

/////////////////////////////////////////////////
pixout GlowScenePS(vtxOut IN)
{
  pixout OUT;
  
  half4 cGlow = tex2D(_tex0, IN.baseTC.xy);
  OUT.Color = float4(cGlow.rgb, 1.0);
  
  return OUT;
}

////////////////// technique /////////////////////
technique GlowScene
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();            
    PixelShader = CompilePS GlowScenePS();
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// EncodeHDRGlow: encodes HDR glow into LDR glow texture //////////////////////////////////////////

/// Specific data ////////////////////////

/// Constants ////////////////////////////

////////////////// samplers /////////////////////

pixout EncodeHDRtoLDRPS(vtxOut IN)
{
  pixout OUT;
  
  OUT.Color = EncodeRGBS( tex2D( _tex0, IN.baseTC.xy) );
  
  return OUT;
}

////////////////// technique /////////////////////
technique EncodeHDRtoLDR
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();            
    PixelShader = CompilePS EncodeHDRtoLDRPS();
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// SunShafts technique //////////////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

/// Constants ////////////////////////////

float4 PI_sunShaftsParams;
float4 sunShaftsParams;
float4x4 SunShafts_ViewProj;
float4 SunShafts_SunPos;

struct vtxOutSunShaftsGen
{
  float4 HPosition  : POSITION; 
  float2 baseTC       : TEXCOORD0;
  float4 sunPos       : TEXCOORD1;  
};

/// Samplers ////////////////////////////

vtxOutSunShaftsGen SunShaftsGenVS(vtxIn IN)
{
  vtxOutSunShaftsGen OUT = (vtxOutSunShaftsGen)0; 

  // Position in screen space.
  float4 vPos = IN.Position;
  OUT.HPosition = mul(vpMatrix, vPos);  
  
  OUT.baseTC.xy = IN.baseTC.xy;
  
  float4 SunPosH = mul(SunShafts_ViewProj, SunShafts_SunPos);
  OUT.sunPos.x = (SunPosH.x + SunPosH.w) * 0.5 ;
  OUT.sunPos.y = (-SunPosH.y + SunPosH.w) * 0.5 ;
  OUT.sunPos.z = SunPosH.w;
  
  OUT.sunPos.w = (dot(normalize(SunShafts_SunPos).xyz, SunShafts_ViewProj[2].xyz));

  return OUT;
}

///////////////// pixel shader //////////////////

pixout SunShaftsMaskGenPS(vtxOutTexToTex IN)
{
  pixout OUT;
  
  int nQuality = GetShaderQuality();
  
  half4 scene = 0;
  half sceneDepth = 0;
  if( nQuality == QUALITY_HIGH )
  {
    half sceneDepth0 = tex2D(_tex0, IN.baseTC0.xy).r;
    half sceneDepth1 = tex2D(_tex0, IN.baseTC1.xy).r;
    half sceneDepth2 = tex2D(_tex0, IN.baseTC2.xy).r;
    half sceneDepth3 = tex2D(_tex0, IN.baseTC3.xy).r;
    half sceneDepth4 = tex2D(_tex0, IN.baseTC4.xy).r;    
    sceneDepth = (sceneDepth0 + sceneDepth1 + sceneDepth2 + sceneDepth3 + sceneDepth4) * 0.2;
    
    half4 scene0 = tex2D(_tex1, IN.baseTC0.xy);
    half4 scene1 = tex2D(_tex1, IN.baseTC1.xy);
    half4 scene2 = tex2D(_tex1, IN.baseTC2.xy);
    half4 scene3 = tex2D(_tex1, IN.baseTC3.xy);
    half4 scene4 = tex2D(_tex1, IN.baseTC4.xy);
    scene = (scene0 + scene1 + scene2 + scene3 + scene4) * 0.2;
  }
  else
  {
    sceneDepth = tex2D(_tex0, IN.baseTC0.xy).r;
    scene = tex2D(_tex1, IN.baseTC0.xy);
  }

  //half fMask = saturate( 8*(1-abs(sceneDepth*2-1)) ); 
  ///half fCloudsMask = 1 - saturate(tex2D(_tex1, IN.baseTC.xy).w*2-1);  
  half fShaftsMask = (1 - sceneDepth); /fCloudsMask;  
  
  OUT.Color = half4( scene.xyz * saturate(sceneDepth), fShaftsMask );

  return OUT;
}

pixout SunShaftsGenPS(vtxOutSunShaftsGen IN)
{
  pixout OUT;
  
  float2 sunPosProj = ((IN.sunPos.xy / IN.sunPos.z));
  
  float fSign = (IN.sunPos.w);
  
  float2 sunVec = ( sunPosProj.xy - IN.baseTC.xy);
  
  float fAspectRatio =  1.333 * PS_ScreenSize.y /PS_ScreenSize.x;
  
  float sunDist = saturate(fSign) * saturate( 1 - saturate(length(sunVec * float2(1, fAspectRatio))*PI_sunShaftsParams.y));// * 
                            //saturate(saturate(fSign)*0.6+0.4  ) );
                            // *(1.0 - 0.2*(1- sin(AnimGenParams) ) pass variation per constant
  float2 sunDir =  ( sunPosProj.xy - IN.baseTC.xy);
   
  
  half4 accum = 0; 
  sunDir.xy *= PI_sunShaftsParams.x * fSign;
  
  const float numSamples = 8;
  
#if D3D10
  [unroll]
#endif
  for(int i=0; i<numSamples; i++)
  {
    half4 depth = tex2D(_tex0, (IN.baseTC.xy + sunDir.xy * i) );      
    accum += depth * (1.0-i/numSamples);
  }
  
  accum /= numSamples;
  
  OUT.Color = accum * 2  * float4(sunDist.xxx, 1);
  OUT.Color.w += 1-saturate(saturate(fSign*0.1+0.9));
  //OUT.Color.xyz *=1- saturate(0.5-0.5* fSign);
    
  return OUT;
}

pixout SunShaftsDisplayPS(vtxOut IN)
{
  pixout OUT;

  // Gamma correct input colors.
  HDRGammaCorrectInputColor(g_PS_SunColor);

  half4 cScreen = tex2D(_tex0, IN.baseTC.xy);      
  half4 cSunShafts = tex2D(_tex1, IN.baseTC.xy);

  half fShaftsMask = saturate(1.00001- cSunShafts.w) *sunShaftsParams.x * 2.0;
  //fShaftsMask -= saturate(0.00001 + cSunShafts.w) * sunShaftsParams.x;
      
  // Apply "very" subtle (but always visible) sun shafts mask 
  float fBlend = cSunShafts.w;
  
  // normalize sun color (dont wanna huge values in here)
  float4 sunColor = 1;
  sunColor.xyz = normalize(g_PS_SunColor.xyz);
  
  // 
  OUT.Color =  cScreen + cSunShafts.xyzz * sunShaftsParams.y * sunColor * ( 1 - cScreen );
  OUT.Color = BlendSoftLight(OUT.Color, sunColor * fShaftsMask *0.5+0.5);
      
  return OUT;
}

////////////////// technique /////////////////////

technique SunShaftsMaskGen
{
  pass p0
  {
    VertexShader = CompileVS TexToTexVS();
    PixelShader = CompilePS SunShaftsMaskGenPS();    
    CullMode = None;        
  }
}

technique SunShaftsGen
{
  pass p0
  {
    VertexShader = CompileVS SunShaftsGenVS();
    PixelShader = CompilePS SunShaftsGenPS();    
    CullMode = None;        
  }
}

technique SunShaftsDisplay
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS SunShaftsDisplayPS();    
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Depth Enhancement technique ////////////////////////////////////////////////////////////////////

/// Constants ////////////////////////////

float4 vDepthEnhancementParams;

///////////////// pixel shader //////////////////

pixout DepthEnhancementPS(vtxOut IN)
{
  pixout OUT;
      
  half4 cScreen = tex2D(_tex0, IN.baseTC.xy );      
  
  float2 vSamples[8] =
  {
    -float2(0, 1),
    -float2(1, 0),
    float2(0, 1),
    float2(1, 0),
    
    float2(0.5, 0.85),
    float2(0.85, 0.5),
    -float2(0.5, 0.85),
    -float2(0.85, 0.5),
  };
  
  float fDepth = GetDepthMapScaled(_tex1, IN.baseTC.xy );  
  
  
  float fDepthBlur = 0;
  fDepthBlur += max( min( ( fDepth - GetDepthMapScaled(_tex1, IN.baseTC.xy + 2 * vSamples[0] / ScrSize.xy) ), 1.0) , -1.0) ;  
  fDepthBlur += max( min( ( fDepth - GetDepthMapScaled(_tex1, IN.baseTC.xy + 2 *vSamples[1] / ScrSize.xy) ), 1.0) , -1.0) ;  
  fDepthBlur += max( min( ( fDepth - GetDepthMapScaled(_tex1, IN.baseTC.xy + 2 *vSamples[2] / ScrSize.xy) ), 1.0) , -1.0) ;  
  fDepthBlur += max( min( ( fDepth - GetDepthMapScaled(_tex1, IN.baseTC.xy + 2 *vSamples[3] / ScrSize.xy) ), 1.0) , -1.0) ;  
  
  fDepthBlur += max( min( ( fDepth - GetDepthMapScaled(_tex1, IN.baseTC.xy + 2 * vSamples[4] / ScrSize.xy) ), 1.0) , -1.0) ;  
  fDepthBlur += max( min( ( fDepth - GetDepthMapScaled(_tex1, IN.baseTC.xy + 2 *vSamples[5] / ScrSize.xy) ), 1.0) , -1.0) ;  
  fDepthBlur += max( min( ( fDepth - GetDepthMapScaled(_tex1, IN.baseTC.xy + 2 *vSamples[6] / ScrSize.xy) ), 1.0) , -1.0) ;  
  fDepthBlur += max( min( ( fDepth - GetDepthMapScaled(_tex1, IN.baseTC.xy + 2 *vSamples[7] / ScrSize.xy) ), 1.0) , -1.0) ;    
  
  fDepthBlur /= 8.0;
  
  fDepth *= PS_NearFarClipDist.y;
  //fDepthBlur *= PS_NearFarClipDist.y;    
  
  //OUT.Color = lerp(0.5, cScreen, max( 1-abs( fDepthLow - fDepth + 0.01)), 0) ); //1 - cScreen;
  
  //OUT.Color = lerp(0.5, cScreen,  1 + 0.5 * saturate( 100 * max( abs( fDepthLow - fDepth), 0) ));
  //OUT.Color =  cScreen * (1 - abs(fDepthBlur)*0.5);//lerp(dot(cScreen, float4(0.33, 0.59, 0.11, 0)), cScreen, 1.0 - fDepthBlur ); //max( min( ( fDepth - fDepthBlur ), 1.0) , -1.0) ;
  
  //OUT.Color =  lerp(0.5, cScreen, 1 + min( abs(fDepthBlur), 1.5) ); //max( min( ( fDepth - fDepthBlur ), 1.0) , -1.0) ;  
    
  OUT.Color = saturate(1- abs(fDepthBlur) )* cScreen;
  //OUT.Color = cScreen;
  
  //saturate( max( abs( fDepth - fDepthLow), 0) ); //saturate(fDepthLow > fDepth + 1.0 );
      
  return OUT;
}

////////////////// technique /////////////////////

technique DepthEnhancement
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS DepthEnhancementPS();    
    CullMode = None;        
  }
}


////////////////////////////////////////////////////////////////////////////////////////////////////
/// Chroma Shift technique /////////////////////////////////////////////////////////////////////////

/// Constants ////////////////////////////

///////////////// pixel shader //////////////////

pixout ChromaShiftPS(vtxOut IN)
{
  pixout OUT;
      
  half4 cScreen = 0;
  
  cScreen.x = tex2D(_tex0, (IN.baseTC.xy-0.5) * (1.0 - psParams[0].x) + 0.5).x;      
  cScreen.y = tex2D(_tex0, (IN.baseTC.xy-0.5) * (1.0 - psParams[0].y) + 0.5).y;      
  cScreen.z = tex2D(_tex0, (IN.baseTC.xy-0.5) * (1.0 - psParams[0].z) + 0.5).z;      
    
  OUT.Color = cScreen;

  return OUT;
}

////////////////// technique /////////////////////

technique ChromaShift
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS ChromaShiftPS();    
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// UnderwaterView technique /////////////////////////////////////////////////////////////////////////

/// Constants ////////////////////////////

sampler2D underwaterBumpSampler = sampler_state
{
  Texture = textures/defaults/screen_noisy_bump.dds;
  MinFilter = LINEAR;  
  MagFilter = LINEAR;
  MipFilter = LINEAR; 
  AddressU = Wrap;
  AddressV = Wrap;
};

///////////////// pixel shader //////////////////

pixout UnderwaterViewPS(vtxOut IN)
{
  pixout OUT;
    
#if D3D10	
  // temporary workaround for d3d10 hlsl compiler bug
  OUT.Color = tex2D(screenMapSampler, IN.baseTC.xy);
#endif

  float anim = frac(AnimGenParams*0.01);  
  float3 vec = normalize(float3(IN.baseTC.xy *2-1, 1));
  half4 cBumpy = tex2D(underwaterBumpSampler, IN.baseTC.xy*0.025 + anim )*2-1;
  cBumpy += tex2D(underwaterBumpSampler, IN.baseTC.yx*0.033 - anim )*2-1;
  cBumpy.xyz = normalize( cBumpy ).xyz;
      
  half4 cScreen = tex2D(screenMapSampler, IN.baseTC.xy + cBumpy.xy*0.01);
  
  OUT.Color = cScreen;

  return OUT;
}

////////////////// technique /////////////////////

technique UnderwaterView
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS UnderwaterViewPS();    
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// UnderwaterGodRays technique /////////////////////////////////////////////////////////////////////////

/// Constants ////////////////////////////

float4x4 vpGodMatrix  : PI_Composite; // View*Projection
float4x4 vpGodMatrixI : PB_UnProjMatrix; // invert( View * projection )

float4 CausticsAmbient  : PI_Ambient;
float4 CausticParams	  : PB_CausticsParams;  // xy: caustics distance, zw: 1 / caustics distance


float4 PI_GodRaysParamsVS;
float4 PI_GodRaysParamsPS;
float4 PI_GodRaysSunDirVS;
float4 CausticSmoothSunDir	: PB_CausticsSmoothSunDirection; 


sampler2D wavesSampler = sampler_state
{
  Texture = textures/defaults/oceanwaves_ddn.dds;
  MinFilter = LINEAR;
  MagFilter = LINEAR;
  MipFilter = LINEAR;
  AddressU = Wrap;
  AddressV = Wrap;	
};

sampler2D causticsSampler = sampler_state
{
  Texture = textures/defaults/caustics_sampler.dds;
  MinFilter = LINEAR;
  MagFilter = LINEAR;
  MipFilter = NONE;
  AddressU = Clamp;
  AddressV = Clamp;	
};

float g_fWaterLevel
<
  Position;
> = {PB_WaterLevel};

struct vtxOutGodRays
{
  float4 HPosition  : POSITION; 
  float4 baseTC    : TEXCOORDN; // zw unused
  
  float4 waveTC      : TEXCOORDN;
  float4 causticTC0  : TEXCOORDN;
  float4 causticTC1  : TEXCOORDN;
  
  float4 vPosition : TEXCOORDN;  // w unused   
};

/// Samplers ////////////////////////////

vtxOutGodRays UnderwaterGodRaysVS(vtxIn IN)
{
  vtxOutGodRays OUT = (vtxOutGodRays)0; 

  // Position in screen space.
  float4 vPos = IN.Position;
  vPos.xy = (vPos.xy *2 - 1);
  
  vPos.xy *= 1.2; // hack: make sure to cover entire screen
  
  // Increase each slice distance
  vPos.z = 0.1+ 0.88 * saturate(PI_GodRaysParamsVS.z * PI_GodRaysParamsVS.w);
  //vPos.z = 0.4+ 0. * saturate(vsParams[0].z * vsParams[0].w);
  vPos.w = 1;
  
  // Project back to world space
  vPos = mul(vpGodMatrixI, vPos );
  vPos /= vPos.w;
 
  OUT.HPosition = mul(vpGodMatrix, vPos);  
  
  OUT.baseTC.xy = IN.baseTC.xy;
  OUT.baseTC.y =  1 - OUT.baseTC.y;

  OUT.vPosition.xyz = vPos;
  OUT.vPosition.w = 1;
    
  // Generate projection matrix based on sun direction  
  float3 dirZ = CausticSmoothSunDir.xyz;
  float3 up = float3(0,0,1);
  float3 dirX = normalize(cross(up, dirZ));
  float3 dirY = normalize(cross(dirZ, dirX));

  float3x3 mLightView;
  mLightView[0] = dirX.xyz;
  mLightView[1] = dirY.xyz;
  mLightView[2] = dirZ.xyz;
   
  // Output caustics procedural texture generation 
  float2 uv = mul(mLightView, OUT.vPosition.xyz).xy*0.5;
  
  // half tilling used to avoid annoying aliasing when swimming fast
  OUT.waveTC.xy =  uv * 2 * 0.01 * 0.012 + g_VS_AnimGenParams.w * 0.06;
  OUT.waveTC.wz =  uv * 2 * 0.01 * 0.01 + g_VS_AnimGenParams.w * 0.05;

  OUT.causticTC0.xy =  uv * 0.01 * 0.5 *2+ g_VS_AnimGenParams.w * 0.1;
  OUT.causticTC0.wz =  uv.yx * 0.01 * 0.5 *2- g_VS_AnimGenParams.w * 0.11;  

  OUT.causticTC1.xy =  uv * 0.01 * 2.0 *2+ g_VS_AnimGenParams.w * 0.1;
  OUT.causticTC1.wz =  uv.yx * 0.01 * 2.0 *2- g_VS_AnimGenParams.w * 0.11;  

  return OUT;
}

///////////////// pixel shader //////////////////

pixout UnderwaterGodRaysPS(vtxOutGodRays IN)
{
  pixout OUT;
    
  half4 cScreen =  tex2D(screenMapSampler, IN.baseTC.xy);
      
  // break movement, with random patterns
  float3 wave = 0;
  wave.xy = FetchNormalMap( wavesSampler, IN.waveTC.xy).xy;                                                  // 1 tex
  wave.xy += FetchNormalMap( wavesSampler, IN.waveTC.wz).xy;                                                 // 1 tex, 1 alu

  // Normalization optimization:
  //  - Instead of using GetNormalMap everywhere, which costs 3 alu per lookup, merge both
  //  bumps together, do single normalize after  
  
  // fast normalize
  wave.xy = wave.xy - 1.0;                                                                          // 1 alu
  wave.z = sqrt(1.0 - dot(wave.xy, wave.xy));                                                       // 2 alu    

  wave *= 0.02;                                                                                     // 1 alu  

  half3 causticMapR = 0;
  causticMapR.xy = FetchNormalMap( wavesSampler, IN.causticTC0.xy + wave.xy).xy;     // 1 tex + 2 alu
  causticMapR.xy += FetchNormalMap(wavesSampler, IN.causticTC0.wz + wave.xy).xy;     // 1 tex + 3 alu
   
  // fast normalize  
  causticMapR.xy = causticMapR.xy - 1.0;                                                            // 1 alu
  causticMapR.z = sqrt(1.0 - dot(causticMapR.xy, causticMapR.xy));                                  // 2 alu    
  
  half2 causticHighFreq = 0;
  causticHighFreq = FetchNormalMap( wavesSampler, IN.causticTC1.xy + wave.xy ).xy;   // 1 tex  + 1 alu
  causticHighFreq += FetchNormalMap( wavesSampler, IN.causticTC1.wz + wave.xy ).xy;   // 1 tex  + 2 alu
  causticHighFreq = causticHighFreq * 2.0 - 2.0;                                                    // 1 alu

  causticMapR.xy += causticHighFreq;  

  // Caustics sampler contains function: abs( 1-(abs( a) + abs(b))*0.5 ), which generates nice sharp pattern  
  half3 cCaustic;
  cCaustic.x = tex2D(causticsSampler, causticMapR.xy*0.55+0.55).x;
  cCaustic.y = tex2D(causticsSampler, causticMapR.xy*0.525+0.525).x;
  cCaustic.z = tex2D(causticsSampler, causticMapR.xy*0.5+0.5).x;
  
  float slice_pos = PI_GodRaysParamsPS.z * PI_GodRaysParamsPS.w;    
  
  // sharpen up a bit
  cCaustic *= cCaustic;
  
  // add very sharp highlight
  const half cMaxHightVis = 10.0;
  half fHighlightAtten =  1;//cMaxHightVis / (CausticParams.x - IN.vPosition.z);                         // 2 alu    
  fHighlightAtten = saturate( fHighlightAtten ) * min( abs( fHighlightAtten ), 2);  
  
  half fAtten =1;// saturate( (CausticParams.x - IN.vPosition.z)*4 );                                          // 2 alu  
  
  cCaustic += pow( cCaustic, 8 );
  
  //half4 cScreen =  tex2D(screenMapSampler, IN.baseTC.xy);
  cScreen.xyz = cCaustic * PI_GodRaysParamsPS.w  * PI_GodRaysParamsPS.y * saturate( CausticParams.y  )* 0.25;
  
  
  half fDistToCam = length( WorldViewPos.xyz - IN.vPosition.xyz );                                      // 2 alu
  
  // 4 alu
    
  fAtten *= ( slice_pos );
  
  cScreen.xyz *= fAtten *fHighlightAtten;
  
  OUT.Color = cScreen;

  return OUT;
}

pixout UnderwaterGodRaysFinalPS(vtxOut IN)
{
  pixout OUT;

  half4 c0 = tex2D(screenMapSampler, IN.baseTC.xy);
  float anim = frac(AnimGenParams*0.01);  
  float3 vec = normalize(float3(IN.baseTC.xy *2-1, 1));
  half4 cBumpy = tex2D(underwaterBumpSampler, IN.baseTC.xy*0.025 + anim )*2-1;
  cBumpy += tex2D(underwaterBumpSampler, IN.baseTC.yx*0.033 - anim )*2-1;
  cBumpy.xyz = normalize( cBumpy ).xyz;
    
  half4 cScreen = tex2D(screenMapSampler, IN.baseTC.xy + cBumpy.xy*0.0125); 
  half4 cCaustics = tex2D(screenMapScaledSampler_d4, IN.baseTC.xy + cBumpy.xy*0.01);
          
  OUT.Color = cScreen + cCaustics;

  return OUT;
}
 
////////////////// technique /////////////////////

technique UnderwaterGodRays
{
  pass p0
  {
    VertexShader = CompileVS UnderwaterGodRaysVS();
    PixelShader = CompilePS UnderwaterGodRaysPS();    
    CullMode = None;        
  }
}

technique UnderwaterGodRaysFinal
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS UnderwaterGodRaysFinalPS();    
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Volumetric scattering technique ////////////////////////////////////////////////////////////////

/// Constants ////////////////////////////

float4 PI_volScatterParamsVS;
float4 PI_volScatterParamsPS;
float4 VolumetricScattering;  // x: tilling, y: speed
float4 VolumetricScatteringColor; 

sampler3D volumeMapSampler = sampler_state
{  
  Texture = textures/defaults/Noise3D.dds;
  MinFilter = LINEAR;
  MagFilter = LINEAR;
  MipFilter = LINEAR; 
  AddressU = Wrap;
  AddressV = Wrap;
  AddressW = Wrap;
};


struct vtxOutVolumetricScattering
{
  float4 HPosition  : POSITION; 
  float4 baseTC    : TEXCOORDN; // zw unused
  
  float4 vPosition0 : TEXCOORDN;  // w unused   
  float4 vPosition1 : TEXCOORDN;  // w unused   
};

/// Samplers ////////////////////////////

vtxOutVolumetricScattering VolumetricScatteringVS(vtxIn IN)
{
  vtxOutVolumetricScattering OUT = (vtxOutVolumetricScattering)0; 

  // Position in screen space.
  float4 vPos = IN.Position;
  vPos.xy = (vPos.xy + g_VS_ScreenSize.zw * 0.5 )*2 - 1 ; 
  
  // Increase each slice distance
  vPos.z = 0.5 + 0.5*saturate(PI_volScatterParamsVS.z * PI_volScatterParamsVS.w);;
  vPos.w = 1;
  
  // Project back to world space
  vPos = mul(vpGodMatrixI, vPos );
  vPos /= vPos.w;
 
  OUT.HPosition = mul(vpGodMatrix, vPos);  
  
  OUT.baseTC.xy = IN.baseTC.xy;
  OUT.baseTC.y =  1 - OUT.baseTC.y;
  
  vPos *= VolumetricScattering.x;
  g_VS_AnimGenParams.w *= VolumetricScattering.y;
  
  OUT.vPosition0.xyz = vPos*0.1 + g_VS_AnimGenParams.w *0.2;
  OUT.vPosition1.xyz = vPos*0.11 - g_VS_AnimGenParams.w *0.3;
    
  return OUT;
}

///////////////// pixel shader //////////////////

pixout VolumetricScatteringPS(vtxOutVolumetricScattering IN)
{
  pixout OUT;
  
  half4 cScreen;
  float fVolume = 1 - abs(tex3D(volumeMapSampler, IN.vPosition0 ).w*2-1);
  fVolume += 1 - abs(tex3D(volumeMapSampler, IN.vPosition1).w*2-1);
  fVolume *=0.5;
    
  fVolume *= fVolume;
  fVolume *= fVolume;
  fVolume *= fVolume;
  //fVolume *= fVolume;
  
  OUT.Color = fVolume * PI_volScatterParamsPS.w  * PI_volScatterParamsPS.y * CausticParams.y * VolumetricScatteringColor;

  return OUT;
}

pixout VolumetricScatteringFinalPS(vtxOut IN)
{
  pixout OUT;
  
  half4 cScreen = tex2D(screenMapSampler, IN.baseTC.xy);  
  half4 cVolume = tex2D(screenMapScaledSampler_d4, IN.baseTC.xy);

  OUT.Color = cScreen + cVolume;

  return OUT;
}

////////////////// technique /////////////////////

technique VolumetricScattering
{
  pass p0
  {
    VertexShader = CompileVS VolumetricScatteringVS();
    PixelShader = CompilePS VolumetricScatteringPS();    
    CullMode = None;        
  }
}

technique VolumetricScatteringFinal
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS VolumetricScatteringFinalPS();    
    CullMode = None;        
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Distant rain technique /////////////////////////////////////////////////////////////////////////

/// Constants ////////////////////////////

float4x4 mComposite  : PI_Composite; // View*Projection
float4x4 mUnproject  : PB_UnProjMatrix; // invert( View * projection )
float4 cRainColor;
float4 PI_RainParamsVS;
float4 PI_RainParamsPS;

struct vtxOutDistantRain
{
  float4 HPosition  : POSITION; 
  float4 vPosition : TEXCOORDN;  // w unused   
  float4 vPosition2 : TEXCOORDN;  // w unused   
  float4 tcProj     : TEXCOORDN;
};

/// Samplers ////////////////////////////

vtxOutDistantRain DistantRainVS(vtxIn IN)
{
  vtxOutDistantRain OUT = (vtxOutDistantRain)0; 

  // Position in screen space.
  float4 vPos = IN.Position;
  vPos.xy = (vPos.xy *2 - 1);
  
  vPos.xy *= 1.2; // hack: make sure to cover entire screen
  
  // Increase each slice distance
  //vPos.z = 0.1+ 0.88 * saturate(vsParams[0].z * vsParams[0].w);
  
  //vPos.z = 0.99+ 0.0025 * saturate(vsParams[0].z * vsParams[0].w);
  vPos.z = 0.005+0.99+ 0.0025 *  saturate((PI_RainParamsVS.z * PI_RainParamsVS.w ));/saturate(vsParams[0].z * vsParams[0].w);
  vPos.w = 1;
  
  // Project back to world space
  vPos = mul(mUnproject, vPos );
  vPos /= vPos.w;
  vPos.w = 1.0;

 
  OUT.HPosition = mul(mComposite, vPos);  
  //OUT.HPosition.z = 0;
  

  OUT.tcProj = HPosToScreenTC( OUT.HPosition );

  OUT.vPosition.xyz = vPos + PI_RainParamsVS.x * float3(0, 0, 100*g_VS_AnimGenParams.x* ((PI_RainParamsVS.w*0.5+0.5)));
  OUT.vPosition2.xyz = vPos+ PI_RainParamsVS.x * float3(0, 0, 500*g_VS_AnimGenParams.x* ((PI_RainParamsVS.w*0.5+0.5)));
  OUT.vPosition.w = 1;
  OUT.vPosition2.w = 1;
    
  // Generate projection matrix based on sun direction  
  float3 dirZ = -g_VS_SunLightDir;
  float3 up = float3(0,0,1);
  float3 dirX = normalize(cross(up, dirZ));
  float3 dirY = normalize(cross(dirZ, dirX));

  float3x3 mLightView;
  mLightView[0] = dirX.xyz;
  mLightView[1] = dirY.xyz;
  mLightView[2] = dirZ.xyz;
   
  // Output caustics procedural texture generation 
  float2 uv = OUT.vPosition.xy; //mul(mLightView, OUT.vPosition.xyz).xy*0.5;

  OUT.vPosition.w =  vPos.z;//uv * 0.01 * 0.5 *2+ g_VS_AnimGenParams.w * 0.1;


  return OUT;
}

///////////////// pixel shader //////////////////

pixout DistantRainPS(vtxOutDistantRain IN)
{
  pixout OUT;
            
  //////////////////////////////////////////////////////////////////////////////////////////////////
  // Simulate distant rain with 3 noisy layers

  OUT.Color = saturate(tex3D( volumeMapSampler, IN.vPosition.xyz*0.45*float3(1,1,0.05)*0.1).w)*0.025*4;
  OUT.Color += saturate(tex3D( volumeMapSampler, IN.vPosition.xyz*0.3*float3(1.1,2.09,0.34)*0.1).w*2-0.8)*0.05;

  // Store current value - will be used for hits look variation
  half fHitMask = OUT.Color.x;  

  OUT.Color *= 0.5;
  OUT.Color *= saturate(tex3D( volumeMapSampler, IN.vPosition2.xyz*0.245*float3(1,1,0.1)*0.0005).w*0.5+0.5);

  //////////////////////////////////////////////////////////////////////////////////////////////////
  // Compute softintersection coeficients with surfaces and water plane

  half fSceneDepth = GetDepthMap(depthMapSampler, IN.tcProj.xy / IN.tcProj.w);
  fSceneDepth += GetDepthMap(depthMapSampler, (IN.tcProj.xy / IN.tcProj.w) + texToTexParams0.xy);
  fSceneDepth += GetDepthMap(depthMapSampler, (IN.tcProj.xy / IN.tcProj.w) + texToTexParams0.zw);
  fSceneDepth += GetDepthMap(depthMapSampler, (IN.tcProj.xy / IN.tcProj.w) + texToTexParams1.xy);
  fSceneDepth += GetDepthMap(depthMapSampler, (IN.tcProj.xy / IN.tcProj.w) + texToTexParams1.zw);
  fSceneDepth *= PS_NearFarClipDist.y *0.2f;
  
  float fRainDepth = IN.tcProj.w; 	

 	half softIntersect = saturate( 0.25* ( fSceneDepth - fRainDepth ));
  float fWaterSoftIsec = saturate(0.25 * (IN.vPosition.w - g_fWaterLevel));

  //////////////////////////////////////////////////////////////////////////////////////////////////
  // Simulate surface hits/splashes
  
  // Compute ground and water plane intersection
  half fGroundHit = (1-saturate( 0.05* ( fSceneDepth - fRainDepth) ))*0.5;
  half fWaterHit = 1-saturate( 0.5* (IN.vPosition.w - g_fWaterLevel));

  // Sum up hits
  fGroundHit += fWaterHit;  

  // Apply hit mask to simulate water splashes
  fHitMask = saturate(saturate(fHitMask)*4-0.2);    
  fGroundHit *= fHitMask;


  OUT.Color += fGroundHit;

  // Apply soft-intersection with surfaces and water plane
  OUT.Color *=  (1-PI_RainParamsPS.w) *0.5 *softIntersect*fWaterSoftIsec * PI_RainParamsPS.y * cRainColor;

  return OUT;
}

pixout DistantRainFinalPS(vtxOut IN)
{
  pixout OUT;

  half4 cScreen = tex2D(screenMapSampler, IN.baseTC.xy);
  half4 cRain = tex2D(screenMapScaledSampler_d2, IN.baseTC.xy);
  OUT.Color = cScreen + cRain;

  return OUT;
}

////////////////// technique /////////////////////

technique DistantRain
{
  pass p0
  {
    VertexShader = CompileVS DistantRainVS();
    PixelShader = CompilePS DistantRainPS();    
    CullMode = None;        
  }
}

technique DistantRainFinal
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS DistantRainFinalPS();    
    CullMode = None;        
  }
}


////////////////////////////////////////////////////////////////////////////////////////////////////
/// Water puddles texgen technique //////////////////////////////////////////////////////////////////////////

/// Specific data ////////////////////////

/// Constants ////////////////////////////

float4 waterPuddlesParams;

///////////////// vertex shader //////////////////

struct vtxOutWaterPuddles
{
  float4 HPosition  : POSITION;
  float2 baseTC    : TEXCOORDN;
  float4 noiseTC    : TEXCOORDN;  
};

vtxOutWaterPuddles waterPuddlesVS(vtxIn IN)
{
  vtxOutWaterPuddles OUT = (vtxOutWaterPuddles)0; 

  float4 vPos = IN.Position;
  OUT.HPosition = mul(vpMatrix, vPos);  
  OUT.baseTC.xy = IN.baseTC.xy;
 
  return OUT;
}

float gaussian(float d2, float radius)
{
  return exp(-d2 / radius);
  //return saturate( 1- (d2*d2/radius) );
  
}

///////////////// pixel shader //////////////////
pixout waterPuddlesPS(vtxOutWaterPuddles IN)
{
  pixout OUT;
  
  float fvar = 0;
  //float2 vDropPos = 0.5;
  float2 vDropPos = (waterPuddlesParams.xy*2-1); //0.25 * float2(cos(AnimGenParams*4 + fvar), sin(AnimGenParams*4 + fvar));
  //(frac(AnimGenParams)>=0.5) *
  
   

   float2 offsets[4] = 
   {
      1,  0,
      -1, 0,         
      0,  1,
      0, -1,
   };

   float4 c = tex2D(_tex0,  IN.baseTC).x;
   float4 d = tex2D(_tex1,  IN.baseTC).x;
   float fDilateRatio = 1.0;
   float fSpeedFactor = 0.3333;
   float2 fPixSize = 1.0 / 256.0;
   float fDamping = 0.9985;//5;//95;//8;
      
   
   float4 l, r, t, b;
   l = tex2D(_tex0,  IN.baseTC + 1*fDilateRatio*fPixSize * offsets[0]).x;
   r = tex2D(_tex0,  IN.baseTC + 1*fDilateRatio*fPixSize * offsets[1]).x;
   t = tex2D(_tex0,  IN.baseTC + 1*fDilateRatio*fPixSize * offsets[2]).x;
   b = tex2D(_tex0,  IN.baseTC + 1*fDilateRatio*fPixSize * offsets[3]).x; 

   float fA = fSpeedFactor;
   float fB = 2.0 - 4.0 * fSpeedFactor;
  
   float sum = (r.x + l.x + t.x + b.x) * fA + fB * c.x - d.x;
   //float sum = (r.x + l.x + t.x + b.x) * 0.5 - d.x;
             
   OUT.Color = ( float4(sum.xxx, 1) *fDamping);  
   
   //(frac(AnimGenParams)>=0.5) *
   OUT.Color +=  waterPuddlesParams.w * gaussian( length(abs( frac(IN.baseTC.xy-vDropPos)*2-1 ) ) ,2.0/256.0 );// tex2D( _tex0, IN.baseTC.xy);

   //OUT.Color.xyz = 1-exp(-1.05*OUT.Color.x);
  
  return OUT;
}

pixout waterPuddlesDisplayPS(vtxOut IN)
{
  pixout OUT;

  float3 vWeights = 0;    
  vWeights.x = (tex2D( _tex0, IN.baseTC.xy ).x);
  vWeights.y = (tex2D( _tex0, IN.baseTC.xy + float2(1,0)/waterPuddlesParams.w).x);
  vWeights.z = (tex2D( _tex0, IN.baseTC.xy + float2(0,1)/waterPuddlesParams.w).x);
  
  // make it a bit sharper (maybe add a sharpening control)
  vWeights = ( vWeights *2 - 1 );
      
  float3 vNormal = float3( vWeights.x - vWeights.y, vWeights.x - vWeights.z,1);                  // 2 inst
  vNormal = normalize(vNormal.xyz);                                                              // 3 inst
 
  OUT.Color.xyz =vNormal*0.5+0.5;// tex2D( _tex0, IN.baseTC.xy);
  OUT.Color.w = vWeights.x*0.5+0.5;

  return OUT;
}

////////////////// technique /////////////////////

technique WaterPuddlesGen
{
  pass p0
  {
    VertexShader = CompileVS waterPuddlesVS();
    PixelShader = CompilePS waterPuddlesPS();    
    CullMode = None;    
  }
}

technique WaterPuddlesDisplay
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();
    PixelShader = CompilePS waterPuddlesDisplayPS();    
    CullMode = None;    
  }
}

#if %DYN_BRANCHING_POSTPROCESS

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Fillrate Profile technique /////////////////////////////////////////////////////////////////////////

pixout FilrateProfilePS(vtxOut IN)
{
  pixout OUT;
  
  const int nSamples = 32;
  float fRecipSamples = 1.0 / (float) nSamples ;
  
  half4 acc = 0;
#if D3D10
  [unroll]
#endif
  for(int n = 0; n < nSamples; n++)
  {
    acc += tex2D(_tex0, IN.baseTC.xy) + (frac(n * fRecipSamples*10)*2-1)*4;
  }

  OUT.Color = acc * fRecipSamples;

  return OUT;
}

////////////////// technique /////////////////////

technique FillrateProfile
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();            
    PixelShader = CompilePS FilrateProfilePS();
    CullMode = None;        
  }
}

#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Grain filter technique /////////////////////////////////////////////////////////////////////////

sampler2D grainNoiseSampler = sampler_state
{
  Texture = textures/defaults/vector_noise.dds;
  MinFilter = POINT;  
  MagFilter = POINT;
  MipFilter = POINT; 
  AddressU = Wrap;
  AddressV = Wrap;
};


pixout GrainFilterPS(vtxOut IN)
{
  pixout OUT;
  
  
  half4 acc = 0;

  float2 vNoiseTC = (IN.baseTC.xy ) * (PS_ScreenSize.xy/64.0) +  (psParams[0].xy/PS_ScreenSize.xy);
  float2 vNoise = tex2D(grainNoiseSampler, vNoiseTC)+ dot(IN.baseTC.xy, 1) * 65535;
  vNoise = frac( vNoise );

  vNoise = vNoise*2-1;
  //vNoise *= 0.05;

  half4 cScreen = tex2D(screenMapSampler, IN.baseTC);

  OUT.Color = cScreen + dot(vNoise.xy, 0.5)*psParams[0].w;


  return OUT;
}

////////////////// technique /////////////////////

technique GrainFilter
{
  pass p0
  {
    VertexShader = CompileVS BaseVS();            
    PixelShader = CompilePS GrainFilterPS();
    CullMode = None;        
  }
}

/////////////////////// eof ///    
*/
