if( GetShaderQuality() > QUALITY_LOW )
{
bumpNormal.z = 1;//sqrt(1 - dot(bumpNormal.xy, bumpNormal.xy));

bumpNormal.xyz += vVertexNormal.xyz;
}



bumpNormal.xyz = normalize( bumpNormal );
//bumpNormal.xyz += ;
//bumpNormal.xyz = normalize( vVertexNormal.xyz + float3(bumpNormal.xy, 0) );

return bumpNormal;
}


pixout WaterLowQualityPS( v2fWater IN )
{
pixout OUT = (pixout) 0;

half3 vVertexNormal = IN.normalVec.xyz;
half3 bumpNormal = BumpGen( IN );

half3 vFinalNormal = bumpNormal;//vVertexNormal.xyz ;//( vVertexNormal.xyz + float3(bumpNormal.xy, 0) ); // opt: no normalize
bumpNormal = vFinalNormal;

// Water edge softness
half3 viewVec = normalize(IN.viewVec.xyz);
float sceneDepth = DecodeSceneDepth( sceneDepthSampler, IN.screenProj );

float waterDepth = IN.screenProj.w;
float depth = ( sceneDepth - waterDepth ) * IN.normalVec.w;
half softIntersect = saturate( SoftIntersectionFactor * depth );

// Get abs( NdotI ) and fresnel term

half NdotI = 1-abs( dot( viewVec.xyz, vFinalNormal.xyz ) );
half fFresnel= saturate( 0.5 + NdotI*NdotI*0.5);// FresnelBias + GetFresnelTex( NdotI, 0).z*FresnelScale;
//half fFresnel= 0.25 + NdotI *NdotI*0.8;// FresnelBias + GetFresnelTex( NdotI, 0).z*FresnelScale;

// Get reflection color
half2 reflNewst = (IN.envTC.xy/IN.envTC.w) + vFinalNormal.xy * 0.33;

// Should do bilinear filtering, but artefacts not much visible due to bump mapping
half4 reflectColor = tex2D(envMapSamplerRefl, reflNewst);
reflectColor += saturate(tex2D(waterGlossMapSampler,IN.Wave0.xy + vFinalNormal.xy * 0.33)-0.25)*0.125;
/*
// Get refraction
float2 refrNewst = ( IN.screenProj.xy / IN.screenProj.w );
float2 refrTC = bumpNormal.xy * 0.1;

// apply refraction masking
{
float depthRefr = tex2D( sceneDepthSampler, refrNewst + refrTC.xy * 1.15 ).r;
half fRefractionMask = (IN.viewVec.w <depthRefr );
// Apply refraction mask to bump offsets
refrTC *= fRefractionMask;
}*/

// half3 refractColor = tex2D(envMapSamplerRefr, refrNewst + refrTC * 1.15 ).xyz;

#if %SUN_SHINE
// half3 mirrorEye = ( 2 * dot( viewVec, bumpNormal) * bumpNormal - viewVec );
// half dotSpec = saturate(dot( mirrorEye.xyz, g_PS_SunLightDir ) * 0.6 + 0.4);
// half3 vSunGlow = saturate(g_PS_SunLightDir.z) *( ( pow( dotSpec, SunShinePow ) ) *SunMultiplier) * g_PS_SunColor.xyz ;
#endif

fFresnel = ( fFresnel ); //* ReflectionAmount);

half3 final= reflectColor;

#if %SUN_SHINE
// Add sun specular term
//final.xyz += vSunGlow.xyz;
#endif

//final.xyz = lerp( IN.localFogColor.xyz, final, saturate( IN.localFogColor.w / softIntersect) );
#if %_RT_FOG
final.xyz = lerp( IN.localFogColor.xyz, final, saturate( IN.localFogColor.w) );
#endif

OUT.Color.xyz = final;
OUT.Color.w = saturate(fFresnel*softIntersect);

return OUT;
}


pixout WaterPS(v2fWater IN)
{
pixout OUT = (pixout) 0;

int nQuality = GetShaderQuality(); // shader quality level

#ifdef D3D10

// workaround for usual dx10 incorrect order sampler binding

half4 c0 = 0;
c0 += tex2D(envMapSamplerRefl, IN.screenProj.xy);
c0 += tex2D(envMapSamplerRefr, IN.screenProj.xy);
c0 += tex2D(oceanBumpMapSampler, IN.screenProj.xy);
c0 += tex2D(sceneDepthSampler, IN.screenProj.xy);
c0 += tex2D(foamSampler, IN.screenProj.xy);
c0 += tex2D(waterGlossMapSampler, IN.screenProj.xy);
c0 += tex2D(foamSamplerSec, IN.screenProj.xy);

#endif

// envMapSamplerRefl sampler NA NA 0 1
// envMapSamplerRefr sampler NA NA 1 1
// oceanBumpMapSampler sampler NA NA 2 1
// sceneDepthSampler sampler NA NA 3 1
// foamSampler sampler NA NA 4 1
// waterGlossMapSampler sampler NA NA 5 1
// foamSamplerSec sampler NA NA 6 1

//OUT.Color = 1;
//return OUT;

if( !nQuality )
return WaterLowQualityPS( IN );

OUT.Color = IN.cColor *4;
OUT.Color.w = 1;


//return OUT;

#if %_RT_DEBUG0 || %_RT_DEBUG1 || %_RT_DEBUG2 || %_RT_DEBUG3
DebugOutput(OUT.Color, IN.baseTC);
return OUT;
#endif

//get shadow from sun
half fShadowOccl = 1; //1.0f - tex2Dproj(shadowOccludeMapSampler, IN.screenProj.xyzw).x;


/* Begin:: Generate normal map from 4 normal map layers */

half3 vVertexNormal = IN.normalVec.xyz;
half3 bumpNormal = BumpGen( IN );

// bumpNormal = float3(0,0,1);

half3 vFinalNormal = ( vVertexNormal.xyz + float3(bumpNormal.xy, 0) ); // opt: no normalize

// opt: - 15 alu

/* End:: Generate normal map from 4 normal map layers */
/*
// Get glossy color (used for adding detail to sun specular, and fake big waves foam) = 5 alu
half fFoamGloss = tex2D(waterGlossMapSampler, IN.Wave0.wz*0.5*2 + vFinalNormal.xy*0.1).x; // 1 alu
fFoamGloss *= tex2D(waterGlossMapSampler, -IN.Wave0.xy*0.33*2 + vFinalNormal.xy*0.1).x; // 2 alu, 1 mov
fFoamGloss *= 2; // 1 alu

// Get foam = 5 alu
half fFoam = tex2D(foamSampler, IN.baseTC.xy*2 + vFinalNormal.xy*0.3).x; // 1 alu
fFoam += tex2D(foamSampler, IN.baseTC.wz*2 + vFinalNormal.xy*0.3).x; // 2 alu
*/

half fFoamGloss = tex2D(waterGlossMapSampler, IN.Wave0.wz*0.5*2 + vFinalNormal.xy*0.1).x; // 1 alu
fFoamGloss *= tex2D(waterGlossMapSampler, -IN.Wave0.xy*0.33*2 + vFinalNormal.xy*0.1).x; // 2 alu, 1 mov
fFoamGloss *= 2; // 1 alu

// Get foam = 5 alu
half fFoam = saturate(tex2D(foamSamplerSec, IN.baseTC.xy - vFinalNormal.xy*0.1).x); // 1 alu
fFoam += tex2D(foamSampler, IN.baseTC.wz + vFinalNormal.xy*0.4).x; // 2 alu

half fFoamLuminance = saturate( fFoam -0.85 ); // 1 alu

//////////////////////////////////////////////////////////////////////////////////////////////////
// Water edge and foam softness

half3 viewVec = normalize(IN.viewVec.xyz);
float sceneDepth = DecodeSceneDepth( sceneDepthSampler, IN.screenProj );

float waterDepth = IN.screenProj.w;
float depth = ( sceneDepth - waterDepth ) * IN.normalVec.w;
half softIntersect = saturate( SoftIntersectionFactor * depth );

// soften camera intersections (and foam also) - test - using alpha blending now to save some instructions
// softIntersect *= saturate( (IN.viewVec.w - PS_NearFarClipDist.x) * 1.5);
// foamSoftIntersect *= saturate( (IN.viewVec.w - PS_NearFarClipDist.x) * 0.75);

//////////////////////////////////////////////////////////////////////////////////////////////////
// Get abs( NdotI ) and fresnel term

half NdotI = (dot( viewVec.xyz, vFinalNormal.xyz ) ); // need detail textures rendering for underwater reflection
//half fInsideReflection = (1 - saturate(1000.0 * (NdotI+0.1)));
half fInsideReflection = 0;
if( nQuality >= QUALITY_HIGH )
fInsideReflection = saturate(-viewVec.z*1000);

NdotI = abs( NdotI ) ;
half fInternalRefl = 0;
//if( nQuality >= QUALITY_HIGH )
// fInternalRefl = saturate(1 - (saturate(NdotI-0.25))) * fInsideReflection;

half fFresnel= GetFresnel( NdotI , 0, 5) * FresnelScale;

//////////////////////////////////////////////////////////////////////////////////////////////////
// Get reflection color
half2 reflNewst = (IN.envTC.xy/IN.envTC.w) + bumpNormal.xy * (0.33 )*0.5;

// Should do bilinear filtering, but artefacts not much visible due to bump mapping
half4 reflectColor = tex2D(envMapSamplerRefl, reflNewst);

// OUT.Color = reflectColor;
//OUT.Color.w = 1;

// foam soft isec, also add a bit of foam nearby camera intersections
half foamSoftIntersect = saturate( (0.1 / saturate(fFoamLuminance)) * (depth) );

//////////////////////////////////////////////////////////////////////////////////////////////////
// Get refraction ( using chroma dispersion )

// Compute refraction mask
float2 refrNewst = ( IN.screenProj.xy / IN.screenProj.w );
float2 refrTC = bumpNormal.xy *(0.1+ 0.1*fInsideReflection)*saturate( softIntersect*4); // Difraction amount always 0.1

//if( nQuality == QUALITY_HIGH )
{
// only hi-specs get refraction masking

// Add small bias to avoid leaking when extremelly nearby camera/water plane
const float fRefrMaskBias = 0.0001;
IN.viewVec.w += fRefrMaskBias;
#if !%NO_REFRACTION_BUMP
#if !%_RT_SAMPLE4
float depthRefr = tex2D( sceneDepthSampler, refrNewst + refrTC.xy * 1.15 ).r;
half fRefractionMask = (IN.viewVec.w <depthRefr );
// Apply refraction mask to bump offsets
refrTC *= fRefractionMask;
#else
float3 depthRefr = tex2D( sceneDepthSampler, refrNewst + refrTC.xy * 1.15 ).r;
depthRefr.y = tex2D( sceneDepthSampler, refrNewst + refrTC.xy ).r;
depthRefr.z = tex2D( sceneDepthSampler, refrNewst + refrTC.xy * 0.85 ).r;

half3 fRefractionMask = (IN.viewVec.www < depthRefr.xyz );

// Apply refraction mask to bump offsets
refrTC *= fRefractionMask.x * fRefractionMask.y * fRefractionMask.z;
#endif
#endif

}

#ifdef OPENGL
refrNewst.y = 1.0 - refrNewst.y;
#endif

half3 refractColor = 0;
#if !%NO_REFRACTION_BUMP
// Achromatic aberration taking about 2 ms. Only enable on very high specs (>=g0
#if %_RT_SAMPLE4
// since we need bilinear filtering in HDR anyway, use 3 lookups instead and get chroma dispersion for free
// 6 instructions extra for chroma dispersion
refractColor.x = tex2D(envMapSamplerRefr, refrNewst + refrTC * 1.15 ).x;;
refractColor.y = tex2D(envMapSamplerRefr, refrNewst + refrTC ).y;
refractColor.z = tex2D(envMapSamplerRefr, refrNewst + refrTC * 0.85 ).z;
#else
// no color dispersion for lower specs
refractColor.xyz = tex2D(envMapSamplerRefr, refrNewst + refrTC * 1.15 ).xyz;
#endif
#else
// no color dispersion for lower specs
refractColor.xyz = tex2D(envMapSamplerRefr, refrNewst ).xyz;
#endif

#if %SUN_SHINE
half3 mirrorEye = ( 2 * dot( viewVec, bumpNormal) * bumpNormal - viewVec );
half dotSpec = saturate(dot( mirrorEye.xyz, g_PS_SunLightDir ) * 0.5 + 0.5);

half3 vSunGlow = fFresnel*saturate(g_PS_SunLightDir.z) *( ( pow( dotSpec, 512 ) )*(fFoamGloss*1.8+0.2))* g_PS_SunColor.xyz ;
vSunGlow += vSunGlow *25 *saturate(fFoamGloss-0.05)* g_PS_SunColor.xyz;
#endif

fFresnel = saturate( fFresnel * ReflectionAmount*(fFoamGloss*0.2+0.);
float fA = 1;

#if !%WAVE_DECAL
half3 final= lerp(refractColor,reflectColor,saturate(fFresnel +saturate(1-NdotI*2)*fInsideReflection));
#else
half3 final= lerp(refractColor,reflectColor,saturate(fFresnel +saturate(1-NdotI*2)*fInsideReflection));
#endif

// no foam for low-specs
if( nQuality == QUALITY_HIGH )
{
// procedural foam
half foam = smoothstep(0.4, 0.8, 1-foamSoftIntersect ) *0.5* softIntersect;
half3 cFoamFinal = foam;

half fCrestFoam = 0.5 * (fFoamLuminance * fFoamGloss * (IN.cColor.z + IN.screenProj.z));
half3 cWavesFoam =fFoamGloss*0.3;
cWavesFoam *= WhiteCapsAmount; // 2 alu
cFoamFinal = (fFoamGloss*0.5+0.5) * saturate( (cFoamFinal + cWavesFoam)*fFoamLuminance +fCrestFoam *WhiteCapsAmount); // 2 alu

// Add foam
final += (g_PS_SkyColor.xyz + g_PS_SunColor.xyz ) * cFoamFinal ; // 2 alu

// 6 alu
}

#if %SUN_SHINE
// Add sun specular term
final.xyz += vSunGlow.xyz * fShadowOccl * SunMultiplier;
#endif

#if !%WAVE_DECAL
fA = 1;
// soft intersection with camera
if( nQuality == QUALITY_HIGH )
fA *= saturate((IN.screenProj.w- PS_NearFarClipDist.x) * 50);
#endif

#if %_RT_FOG
half4 localFogColor = IN.localFogColor;
if( nQuality >= QUALITY_HIGH ) // compute per-pixel instead for hi specs
localFogColor = GetVolumetricFogColor( IN.localFogColor.xyz );

final.xyz = lerp( localFogColor.xyz, final, localFogColor.w );
#endif

final.xyz = lerp( refractColor, final.xyz, softIntersect * saturate(IN.screenProj.w));

// Add global fog - make sure fog doens't affect refraction on shore
// Soften camera intersections

// maybe 4 hi-spec
#if %WAVE_DECAL
//final = fA ;
//fA =1;
//fA *= saturate( (IN.viewVec.w - PS_NearFarClipDist.x) *100);
//fA *= saturate( (IN.viewVec.w/PS_NearFarClipDist.w - PS_NearFarClipDist.x) * 100);
#endif

//fA *= IN.screenProj.z;//*IN.screenProj.z*IN.screenProj.z;

#if !%WAVE_DECAL
// fA *= IN.cColor.w;
#endif

#if WHITE_OUTPUT
final = 1;
#endif

//OUT.Color = float4(IN.cColor.xxx, 1); //;max( half4(final.xyz, fA), 0);
OUT.Color = max( half4(final.xyz, fA), 0);

return OUT;
}

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

technique Water
<
string Script =
"TechniqueShadowPass=ShadowPassWater;"
>
{
pass p0
{

ZEnable = true;
ZFunc = LEqual;
ZWriteEnable = true;
CullMode = None;

SrcBlend = SRC_ALPHA;
DestBlend = ONE_MINUS_SRC_ALPHA;
AlphaBlendEnable = true;
IgnoreMaterialState = true;

#if %WAVE_DECAL
SrcBlend = SRC_ALPHA;
DestBlend = ONE_MINUS_SRC_ALPHA;
AlphaBlendEnable = true;

CullMode = None;

ZEnable = false;
ZWriteEnable = false;
#endif

VertexShader = compile vs_Auto WaterVS() GeneralVS;
PixelShader = compile ps_Auto WaterPS() GeneralPS;
}
}

technique WaterFFT
<
string Script =
"TechniqueShadowPass=ShadowPassWaterFFT;"
>
{
pass p0
{

ZEnable = true;
ZFunc = LEqual;

ZWriteEnable = true;
CullMode = None;

SrcBlend = SRC_ALPHA;
DestBlend = ONE_MINUS_SRC_ALPHA;
AlphaBlendEnable = true;
IgnoreMaterialState = true;

#if %WAVE_DECAL
SrcBlend = SRC_ALPHA;
DestBlend = ONE_MINUS_SRC_ALPHA;
AlphaBlendEnable = true;

CullMode = None;

ZEnable = false;
ZWriteEnable = false;
#endif

VertexShader = compile vs_3_0 WaterVS() GeneralVS;
PixelShader = compile ps_3_0 WaterPS() GeneralPS;
}
}

/////////////// Shadow Pass ////////////////////////
#include "ShadowCommon.cfi"
#include "CommonShadowPass.cfi"
vert2fragShadow Water_ShadowVS(a2vWater IN)
{
vert2fragShadow OUT;
#ifndef OPENGL
OUT = (vert2fragShadow)0;
#endif
// Position in screen space.
float4 vPos = IN.Position;
float4 vPosOrig = IN.Position;

float2 FlowDir = OceanParams1.yz;

float fVertexDist = 0;

#if !%WAVE_DECAL

GetGridVertexPos( vPos, fVertexDist);

#else

vPos.z = (vPos.z < OceanParams1.w)? OceanParams1.w: vPos.z;

#endif

vPosOrig.xyz = vPos.xyz;
float viewAngle = abs( normalize(g_VS_WorldViewPos.xyz-vPosOrig.xyz).z *10);

float3 vPos0 = vPosOrig.xyz;
GetWave( vPos0.xyz, FlowDir, IN);

// todo: Store previous frame position,transformation - use for interpolating. Might help hiding some artefacts
float3 vDisp = vPos0 - vPos.xyz;


float fDistToCam = length(g_VS_WorldViewPos.xyz - vPos.xyz);
float fDispLen = length( vDisp.xyz );
// Attenuate wave strength nearby camera
float fNearbyCameraAtten = (saturate( fDistToCam / 5));

vPos.xyz += vDisp.xyz * fNearbyCameraAtten;

// Add small waves nearby camera
#if !%WAVE_DECAL

float fNearCamWaves = sin( - g_VS_AnimGenParams.z * 11 + fDistToCam * 10 )*0.6;
fNearCamWaves += sin( - g_VS_AnimGenParams.z * 5 + fDistToCam * 15)*0.4;
float fDispAmount = saturate( 1 / (fDistToCam) );
vPos.z += (fNearCamWaves )* fDispAmount*0.025;

#endif


OUT.HPosition = mul(mViewProj, vPos);


OUT.RandDirTC.xy = mul(vPos.xyz, (float3x3) TexGen0).xy / 800;

// compute shadow tex coords and depth
GenShadowTC(vPos, OUT.shadowTC);

return OUT;
}


pixout_cl Water_ShadowPS(vert2fragShadow IN)
{
pixout_cl OUT;

float4 vCompare = (float4)0;

#ifndef %_RT_GSM_COMBINED
//non-combined GSM

vCompare = ShadowDepthTest(IN.shadowTC, IN.RandDirTC.xy);

#else
//GSM ATLAS

vCompare = ShadowDepthTestAtlas(IN.shadowTC, IN.RandDirTC.xy);

//GSM ATLAS
#endif

//shadow fading - is not supported currently
//vCompare *= IN.RandDirTC.z;

OUT.Color = 1 - vCompare;

return OUT;
}


technique ShadowPassWater
{
pass p0
{
VertexShader = compile vs_Auto Water_ShadowVS();
PixelShader = compile ps_Auto Water_ShadowPS();

ZEnable = true;
ZFunc = LEqual;
ZWriteEnable = false;
CullMode = None;
ZEnable = true;
ZWriteEnable = true;
CullMode = None;
}
}

technique ShadowPassWaterFFT
{
pass p0
{
VertexShader = compile vs_Auto Water_ShadowVS();
PixelShader = compile ps_Auto Water_ShadowPS();

ZEnable = true;
ZFunc = LEqual;
ZWriteEnable = false;
CullMode = None;
ZEnable = true;
ZWriteEnable = true;
CullMode = None;
}
}

/////////////////////// eof ///