//====================================================
// water Shader
//====================================================
// By EVOLVED
// www.evolved-software.com
//====================================================

//--------------
// un-tweaks
//--------------
   matrix WorldVP:WorldViewProjection; 
   matrix World:World;   
   matrix ViewInv:ViewInverse; 
   float time:Time; 

//--------------
// tweaks
//--------------
   float BlurOffset
<
	string UIWidget = "slider";
	float UIMax = 0.01;
	float UIMin = 0.0001;
	float UIStep = 0.00001;
> = 0.000;

   float2 ViewVec;
   float WaterHeight=280.0;
   float WaterBump=0.05f;
   float2 WaterScale={1800,1800};
   float4 WaterSpeed={-0.0225f,-0.025f,0.005f,-0.005f};
   float FresBias=100.0f;
   float FresPow=2.5f;
   float3 FogColor;
   float FogRange;
   float FogPow;
   float3 WaterFogColor;
   float WaterFogRange;
   float DetailScale=4.0;
   float DetailBump=0.6;
   float3 RefractColor={1.0f,1.0f,1.0f};
   float3 ReflectColor={1.0f,1.0f,1.0f};   
  

//   float BlurOffset=0.002f;
   float2 samplesoffset[12]=
    {
     float2(-0.5,-1.5),
     float2(0.5,-1.5),
     float2(-1.5,-0.5),
     float2(-0.5,-0.5),
     float2(0.5,-0.5),
     float2(1.5,-0.5),
     float2(-1.5,0.5),
     float2(-0.5,0.5),
     float2(0.5,0.5),
     float2(1.5,0.5),
     float2(-0.5,1.5),
     float2(0.5,1.5)
    };   

//--------------
// Textures
//--------------
   texture WaterRefractTX <string Name=""; >;	
   sampler WaterRefract=sampler_state
     {
	Texture=<WaterRefractTX>;
   	ADDRESSU=CLAMP;
   	ADDRESSV=CLAMP;
   	ADDRESSW=CLAMP;
	MagFilter=Linear;	
	MinFilter=Point;
	MipFilter=None;
     };
   texture WaterReflectTX <string Name=""; >;	
   sampler WaterReflect=sampler_state
     {
	Texture=<WaterReflectTX>;
   	ADDRESSU=CLAMP;
   	ADDRESSV=CLAMP;
   	ADDRESSW=CLAMP;
	MagFilter=Linear;	
	MinFilter=Point;
	MipFilter=None;
     };
   texture WaterbumpTX <string Name=""; >; 
   sampler Waterbump=sampler_state 
     {
	Texture=<WaterbumpTX>;
	MagFilter=Linear;	
	MinFilter=Point;
	MipFilter=None;
     };

//--------------
// structs 
//--------------
   struct In_AboveWater
     {
 	float4 Pos:POSITION;
     };
   struct Out_AboveWater
     {
	float4 OPos:POSITION; 
 	float4 Tex1:TEXCOORD0; 
 	float2 Tex2:TEXCOORD1; 
    	float4 RefrProj:TEXCOORD2;
    	float4 ReflProj:TEXCOORD3;
	float3 WaterFog:TEXCOORD6; 
	float3 FresVec:TEXCOORD7; 
     };
   struct In_UnderWater
     {
 	float4 Pos:POSITION; 
     };
   struct Out_UnderWater
     {
	float4 OPos:POSITION; 
 	float4 Tex1:TEXCOORD0; 
 	float2 Tex2:TEXCOORD1; 
    	float4 RefrProj:TEXCOORD2;
    	float4 ReflProj:TEXCOORD3;
	float3 WaterFog:TEXCOORD6; 
	float3 FresVec:TEXCOORD7;   
     };

//--------------
// vertex shader
//--------------
   float3x3 TBN={float3(1,0,0),float3(0,0,1),float3(0,1,0)};
   Out_AboveWater VS_AboveWater(In_AboveWater IN) 
    {
 	Out_AboveWater OUT;
	OUT.OPos=mul(IN.Pos,WorldVP); 
	float3 WPos=mul(IN.Pos,World);
	float2 Uv=(WPos.xz/WaterScale);
	float4 WaterUv;
	       WaterUv.xy=Uv+(time*WaterSpeed.xy);
	       WaterUv.zw=(Uv*1.25)+(time*WaterSpeed.zw);
	float3 ViewPos=ViewInv[3].xyz-WPos;
	OUT.Tex1=WaterUv;
	OUT.Tex2=Uv;
	OUT.RefrProj=float4(OUT.OPos.x*0.5+0.5*OUT.OPos.w,0.5*OUT.OPos.w-OUT.OPos.y*0.5,OUT.OPos.w,OUT.OPos.w);
  	OUT.ReflProj=float4(OUT.OPos.x*0.5+0.5*OUT.OPos.w,0.5*OUT.OPos.w+OUT.OPos.y*0.5,OUT.OPos.w,OUT.OPos.w);
 	OUT.ReflProj.y=OUT.ReflProj.y-1.0f;
	OUT.WaterFog=ViewPos/FogRange;
	ViewPos.y=(ViewPos.y+FresBias)*FresPow;
	OUT.FresVec=mul(ViewPos,TBN); 
	return OUT;
    }
   Out_UnderWater VS_UnderWater(In_UnderWater IN) 
     {
 	Out_UnderWater OUT;
	OUT.OPos=mul(IN.Pos,WorldVP); 
	float3 WPos=mul(IN.Pos,World);
	float2 Uv=(WPos.xz/WaterScale);
	float4 WaterUv;
	       WaterUv.xy=Uv+(time*WaterSpeed.xy);
	       WaterUv.zw=(Uv*1.25)+(time*WaterSpeed.zw);
	float3 ViewPos=ViewInv[3].xyz-WPos;
	OUT.Tex1=WaterUv;
	OUT.Tex2=Uv;
	OUT.RefrProj=float4(OUT.OPos.x*0.5+0.5*OUT.OPos.w,0.5*OUT.OPos.w-OUT.OPos.y*0.5,OUT.OPos.w,OUT.OPos.w);
  	OUT.ReflProj=float4(OUT.OPos.x*0.5+0.5*OUT.OPos.w,0.5*OUT.OPos.w+OUT.OPos.y*0.5,OUT.OPos.w,OUT.OPos.w);
 	OUT.ReflProj.y=OUT.ReflProj.y-1.0f;
	OUT.WaterFog=ViewPos/FogRange;
	ViewPos.y=(ViewPos.y+FresBias)*FresPow;
	OUT.FresVec=mul(ViewPos,TBN); 
	return OUT;
    }

//--------------
// pixel shader
//--------------
    float4 PS_AboveWater(Out_AboveWater IN)  : COLOR
     {	
        //float HightMask=saturate((tex2D(WorldPos,(IN.RefrProj.xy/IN.RefrProj.z)+ViewVec).y+ViewInv[3].y)/WaterHeight);
        float3 NormalMap=(tex2D(Waterbump,IN.Tex1.xy*DetailScale)+tex2D(Waterbump,IN.Tex1.zw*DetailScale))-1.0f; 
	float3 Reflection=tex2D(WaterReflect,(IN.ReflProj.xy/IN.RefrProj.z)+(NormalMap.xy*WaterBump))*ReflectColor;
	float3 Refraction=0;//tex2D(WaterRefract,(IN.RefrProj.xy/IN.RefrProj.z)+(NormalMap.xy*WaterBump))*RefractColor;
	
	for (int i = 0; i < 12; i++) Refraction +=tex2D(WaterRefract,(IN.RefrProj.xy/IN.RefrProj.z)+(NormalMap.xy*WaterBump)+samplesoffset[i]*BlurOffset)*RefractColor;;	
	Refraction=Refraction/12;
	//Reflection=Reflection*0.4;
	float Fresnel=dot(NormalMap,normalize(IN.FresVec));
	float3 Water=lerp(Reflection,Refraction,Fresnel);
	float WaterFog=pow(saturate(length(IN.WaterFog)),FogPow);
	return float4(lerp(Water,0,0.0f),1.0f);
     }
   float4 PS_UnderWater(Out_UnderWater IN) : COLOR 
    {
        //float HightMask=saturate((tex2D(WorldPos,(IN.RefrProj.xy/IN.RefrProj.z)+ViewVec).y+ViewInv[3].y)/WaterHeight);
        float3 NormalMap=(tex2D(Waterbump,IN.Tex1.xy*DetailScale)+tex2D(Waterbump,IN.Tex1.zw*DetailScale))-1.0f; 
	float3 Reflection=0;//tex2D(WaterReflect,(IN.ReflProj.xy/IN.RefrProj.z)+(NormalMap.xy*WaterBump));
	float3 Refraction=tex2D(WaterRefract,(IN.RefrProj.xy/IN.RefrProj.z)+(NormalMap.xy*WaterBump))*RefractColor;
	float Fresnel=1;//dot(NormalMap,normalize(IN.FresVec));
	float3 Water=lerp(Reflection,Refraction,Fresnel);
	float WaterFog=pow(saturate(length(IN.WaterFog)),FogPow);
	return float4(lerp(Water,0,0.0f),1.0f);
    }     


//--------------
// techniques   
//--------------   
    technique ReflectRefract
      {
 	pass p1
      {		
 	vertexShader = compile vs_2_0 VS_AboveWater(); 
 	pixelShader  = compile ps_2_0 PS_AboveWater();
      }
      }
    technique Refract
      {
 	pass p1
      {		
 	vertexShader = compile vs_2_0 VS_UnderWater(); 
 	pixelShader  = compile ps_2_0 PS_UnderWater();
	//CullMode=CW;
      }
      }   