//Water pixel shader - performs the water distortion via DUDV, applies specular, applies normal map highlights and performs the Fresnel effect

//Texture and sampler registers
Texture2D reflectionTexture : register(t0);
Texture2D refractionTexture : register(t1);
Texture2D dudvTexture : register(t2);
Texture2D normalTexture : register(t3);
SamplerState Sampler0: register(s0);

cbuffer WaterPixelBuffer : register(b0)
{
	float moveFactor;	//The factor in which to move the water
	float3 sunColour;
}

struct InputType
{
	float4 position : SV_POSITION;
	float2 tex : TEXCOORD0;
	float3 cameraForwardVector : TEXCOORD1;
	float3 lightVector : TEXCOORD2;
	float4 reflectionPosition : TEXCOORD3;
};

float4 main(InputType input) : SV_TARGET
{
	//Calculate the reflection and refraction texture coordinates
	float2 normalizedDeviceSpace = ((float2(input.reflectionPosition.x, input.reflectionPosition.y) / input.reflectionPosition.w) / 2.0f) + 0.5f;
	float2 reflectionTexCoords = ((float2(input.reflectionPosition.x, -input.reflectionPosition.y) / input.reflectionPosition.w) / 2.0f) + 0.5f;
	float2 refractionTexCoords = normalizedDeviceSpace;

	//Calculate the total distortion in which to apply to the water via sampling the DUDV texture
	float distortionStrength = 0.02f;
	float2 distortionTexCoords = dudvTexture.Sample(Sampler0, float2(input.tex.x + moveFactor, input.tex.y)).rg * 0.1f;
	distortionTexCoords = input.tex + float2(distortionTexCoords.x, distortionTexCoords.y + moveFactor);
	float2 totalDistortion = (dudvTexture.Sample(Sampler0, distortionTexCoords).rg * 2.0 - 1.0) * distortionStrength;

	//Apply the distortion to the reflection and refraction
	reflectionTexCoords += totalDistortion;
	reflectionTexCoords = clamp(reflectionTexCoords, 0.001f, 0.999f);
	refractionTexCoords += totalDistortion;
	refractionTexCoords = clamp(refractionTexCoords, 0.001f, 0.999f);
	reflectionTexCoords.y = (reflectionTexCoords.y - 1.0f) * -1.0f;

	//Now sample the reflection and refraction after distortion applied
	float4 reflectionColour = reflectionTexture.Sample(Sampler0, reflectionTexCoords);
	float4 refractionColour = refractionTexture.Sample(Sampler0, refractionTexCoords);

	//Apply reflectivity by determining the angle between the camera and applying the reflectivity power
	float4 reflectivePower = 10.0f;
	float3 cameraVec = normalize(input.cameraForwardVector);
	float refractiveFactor = dot(cameraVec, float3(0.0f, 1.0f, 0.0f));
	refractiveFactor = pow(refractiveFactor, reflectivePower);

	//Now apply reflectivity to produce the Fresnel effect
	float4 retColour = lerp(reflectionColour, refractionColour, refractiveFactor);
	retColour = lerp(retColour, float4(0.0f, 0.3f, 0.5f, 1.0f), 0.2f);

	//Sample the normal map
	float4 normalMapColour = normalTexture.Sample(Sampler0, distortionTexCoords * 2.0f);
	float3 normal = float3((normalMapColour.r * 2.0f) - 1.0f, normalMapColour.b, (normalMapColour.g * 2.0f) - 1.0f);
	normal = normalize(normal);

	//Now apply the specular highlights using the normal from the normal map
	float shineDamper = 2.5f;
	float3 reflection = -reflect(normalize(input.lightVector), normal);
	float specular = dot(normalize(reflection), normalize(input.lightVector));
	if (specular > 0.0f)
	{
		//Specular highlight is valid, apply it
		specular = pow(specular, shineDamper);
		retColour = saturate(retColour + specular);
	}

	return retColour;
}
