//
// Generated by Microsoft (R) D3DX9 Shader Compiler 9.08.299.0000
//
// Parameters:
//
float4 Scroll : register(c0);
float4 EyePos : register(c1);
float4 SunDir : register(c2);
float4 SunColor : register(c3);
float4 ShallowColor : register(c5);
float4 DeepColor : register(c6);
float4 ReflectionColor : register(c7);
float4 VarAmounts : register(c8);
float4 FogParam : register(c9);
float4 FogColor : register(c10);
float4 FresnelRI : register(c11);
float4 BlendRadius : register(c12);
float4 TESR_SunColor : register(c13);
float4 TESR_WaterCoefficients : register(c14);
float4 TESR_WaveParams : register(c15);
float4 TESR_WaterVolume : register(c16);
float4 TESR_ReciprocalResolution : register(c17);
float4 TESR_WaterShorelineParams : register(c18);
float4x4 TESR_ViewTransform : register(c19);
float4x4 TESR_ProjectionTransform : register(c23);
float4 TESR_WaterSettings : register(c27);

sampler2D ReflectionMap : register(s0);
sampler2D NormalMap : register(s1);
sampler2D DetailMap : register(s2);
sampler2D DepthMap : register(s3);
sampler2D DisplacementMap : register(s4);
sampler2D TESR_RenderedBuffer : register(s5) = sampler_state { };
sampler2D TESR_DepthBuffer : register(s6) = sampler_state { };

static const float nearZ = TESR_ProjectionTransform._34 / TESR_ProjectionTransform._33;
static const float farZ = (TESR_ProjectionTransform._33 * nearZ) / (TESR_ProjectionTransform._33 - 1.0f);
static const float Zmul = nearZ * farZ;
static const float Zdiff = farZ - nearZ;
static const float depthRange = nearZ - farZ;

static const float4x4 ditherMat = { 0.0588, 0.5294, 0.1765, 0.6471,
									0.7647, 0.2941, 0.8824, 0.4118,
									0.2353, 0.7059, 0.1176, 0.5882,
									0.9412, 0.4706, 0.8235, 0.3259 };

//
//
// Registers:
//
//   Name            Reg   Size
//   --------------- ----- ----
//   Scroll          const_0       1
//   EyePos          const_1       1
//   SunDir          const_2       1
//   SunColor        const_3       1
//   ShallowColor    const_5       1
//   DeepColor       const_6       1
//   ReflectionColor const_7       1
//   VarAmounts      const_8       1
//   FogParam        const_9       1
//   FogColor        const_10      1
//   FresnelRI       const_11      1
//   BlendRadius     const_12      1
//   ReflectionMap   texture_0       1
//   NormalMap       texture_1       1
//   DetailMap       texture_2       1
//   DepthMap        texture_3       1
//   DisplacementMap texture_4       1
//


// Structures:

struct VS_OUTPUT {
    float4 texcoord_0 : TEXCOORD0;
    float4 texcoord_1 : TEXCOORD1_centroid;
    float4 texcoord_2 : TEXCOORD2_centroid;
};

struct PS_OUTPUT {
    float4 color_0 : COLOR0;
};

// Code:
float3 toWorld(float2 tex) {
	
    float3 v = float3(TESR_ViewTransform[2][0], TESR_ViewTransform[2][1], TESR_ViewTransform[2][2]);
    v += (1/TESR_ProjectionTransform[0][0] * (2*tex.x-1)).xxx * float3(TESR_ViewTransform[0][0], TESR_ViewTransform[0][1], TESR_ViewTransform[0][2]);
    v += (-1/TESR_ProjectionTransform[1][1] * (2*tex.y-1)).xxx * float3(TESR_ViewTransform[1][0], TESR_ViewTransform[1][1], TESR_ViewTransform[1][2]);
    return v;
	
}

float readDepth(in float2 coord : TEXCOORD0) {
	
	float posZ = tex2D(TESR_DepthBuffer, coord).x;
	posZ = Zmul / ((posZ * Zdiff) - farZ);
	return posZ;
	
}

float3 getWaterNorm(float2 pos, float2 dispPos, float blend) {
	
	float choppiness = TESR_WaveParams.x;
	float waveWidth = TESR_WaveParams.y;

	float4 sampledResult = tex2D(NormalMap, pos.xy / (1248 * waveWidth));
	float2 temp_norm = sampledResult.rg * 2 - 1;
	float2 temp_norm2 = sampledResult.rg * 2 - 1;
	temp_norm.xy += temp_norm2.xy;
	float3 displacementNormal = tex2D(DisplacementMap, dispPos.xy).rgb * 1.2 - 0.6;
	temp_norm.xy += displacementNormal.xy * blend;
	return normalize(float3(temp_norm * choppiness, 1));
	
}

float getFresnelAboveWater(float3 ray, float3 norm) {
	
	float temp_cos = dot(-ray, norm);
	float2 vec = float2(temp_cos, sqrt(1 - temp_cos * temp_cos));
	float fresnel = vec.x - 1.33 * sqrt(1 - 0.565 * vec.y * vec.y);
	
	fresnel /= vec.x + 1.33 * sqrt(1 - 0.565 * vec.y * vec.y);
	fresnel = saturate(fresnel * fresnel);
	return fresnel;
	
}

PS_OUTPUT main(VS_OUTPUT IN, float2 PixelPos : VPOS){
    PS_OUTPUT OUT;

	float2 UVCoord = (PixelPos + 0.5) * TESR_ReciprocalResolution.xy;
	float3 eyepos = IN.texcoord_2.xyz;
	eyepos.z = -IN.texcoord_1.z;

    float4 color = tex2D(TESR_RenderedBuffer, UVCoord);
    float depth = readDepth(UVCoord);
    float3 camera_vector = toWorld(UVCoord);
	float3 norm_camera_vector = normalize(camera_vector);
    
	float causticsStrength = TESR_WaterVolume.x;
	float shoreFactor = TESR_WaterVolume.y;
	float turbidity = TESR_WaterVolume.z;
	float3 extCoeff = TESR_WaterCoefficients.xyz * turbidity;
	float scattCoeff = TESR_WaterCoefficients.w * turbidity;
	float reflectivity = TESR_WaveParams.w;
	float waveWidth = TESR_WaveParams.y;

	
	float3 world_pos = eyepos + camera_vector * depth;
	float uw_pos = world_pos.z / camera_vector.z;
	float2 surfPos = world_pos.xy - camera_vector.xy * uw_pos;
	float blend = saturate(4 * (BlendRadius.x - (2 * length(IN.texcoord_0.xy - 0.5))));
	
	float3 normal = getWaterNorm(surfPos, IN.texcoord_0.xy, blend);
	
	world_pos = eyepos + camera_vector * depth;
	uw_pos = world_pos.z / camera_vector.z;
	
	float4 refract_color = color;  
   float4 reflection;
  float4 water_result;

	//Caustics
//	float3 dx = ddx(world_pos);
 //   float3 dy = ddy(world_pos);
//    float3 waterfloorNorm = normalize(cross(dx,dy));
//	float3 causticsPos = world_pos - SunDir.xyz * (world_pos.z / SunDir.z);
//	float caustics = causticsStrength * tex2D(NormalMap, causticsPos.xy / (624 * waveWidth)).b;
//	caustics += causticsStrength * 0.6 * tex2D(NormalMap, causticsPos.xy / (1248 * waveWidth)).b;
//	float causticsAngle = saturate(dot(-waterfloorNorm, SunDir.xyz));
//	refract_color.rgb *= 1 + caustics * causticsAngle * TESR_SunColor.xyz;

	//Refraction
    refract_color.rgb *= exp(-extCoeff * (uw_pos - world_pos.z) / 70);
	float SinBoverSinA = -norm_camera_vector.z;
	float3 waterVolColor = scattCoeff * FogColor.xyz / (extCoeff * (1 + SinBoverSinA));
	waterVolColor *= 1 - exp(-extCoeff * (1 + SinBoverSinA) * uw_pos / 70);
	refract_color.rgb += waterVolColor;

	  //Reflection
	float2 refPos = UVCoord + 0.05 * normal.yx; 
 
   if (TESR_WaterSettings.z == 2.0f){
   
     reflection = tex2D(ReflectionMap, float2(refPos.x, 1 - refPos.y));
   }
   else if (TESR_WaterSettings.z == 1.0f){
   
     reflection = tex2D(DetailMap, 0.1 * normal.xy + IN.texcoord_0.xy);
      
   }
	
	//Fresnel 
     if (TESR_WaterSettings.z > 0){
	float fresnel = saturate(getFresnelAboveWater(norm_camera_vector, normal) * reflectivity);
  water_result = lerp(refract_color, reflection, fresnel);
	}
  
	//Specular
//	float specular = saturate(dot(norm_camera_vector, reflect(SunDir.xyz, normal)));
//	water_result.xyz += (1 - TESR_SunColor.a) * pow(specular, (depth - uw_pos) * 0.3) * TESR_SunColor.rgb;

	//Fog
    float fog = 1 - saturate((FogParam.x - length(IN.texcoord_1.xyz)) / FogParam.y);
	water_result.rgb = (fog * (FogColor.rgb - water_result.rgb)) + water_result.rgb;

	water_result.rgb += ditherMat[ PixelPos.x%4 ][ PixelPos.y%4 ] / 255;

	OUT.color_0.rgb = water_result.rgb;
	OUT.color_0.a = (blend > 0.0 ? 1 : 0);
    return OUT;
	
};

// approximately 84 instruction slots used (4 texture, 80 arithmetic)
