/*
 * fragment shader for rendering the water surface
 *
 * this shader renders the water surface. therfore it uses
 * the given texture with the reflected objects
 * and the texture with the refracted objects.
 * which texture is used with which weight is given by
 * a fresnel-calculation. furthermore, the normal of each pixel is
 * "calculated" by using the value of the color texture which simply bends
 * the vec3(0,1,0) a little bit.
 *
 * the height of the water surface (=orthogonal distance to object under water)
 * is read out from the alpha-channel of the refraction-texture, where the shader
 * used when drawing the refracted texture writes the value "-y" in the alpha channel.
 * the water height is used to limit the shifting of these texture (which should simulate
 * the water turbulence) because otherwise artefacts will apear on the borders of the
 * water (where the water hits the other objects)
 *
 * written by:
 * christian moellinger <ch.moellinger@gmail.com>
 * 11/2010 - 01/2011
 */

#version 330 core

out vec4 out_Color;
in vec4 my_Position;
in vec3 my_WorldSpacePosition;
in vec3 my_Texcoord;
in vec3 my_EyeDir;
in vec3 my_LightDir;

uniform sampler2D reflection_texture;
uniform sampler2D refraction_texture;
uniform sampler2D water_texture;
uniform sampler2D shadowmap;

uniform mat4 Camera_TempTransformMatrix;
uniform mat4 Camera_ProjectionMatrix;
uniform mat4 Camera_TransformMatrix;
uniform mat4 Model_TransformMatrix;
uniform mat3 NormalMatrix;

float calcLight()
{
    float light = 1.0;
    vec4 shadowcoords_f = Camera_TempTransformMatrix * Model_TransformMatrix * vec4(my_WorldSpacePosition, 1.0);
    vec2 shadowcoords = (shadowcoords_f / shadowcoords_f.w).xy;
    shadowcoords += 1.0;
    shadowcoords *= 0.5;


    float ShadowMapValue = texture(shadowmap, shadowcoords).r;

    float ComparedZ = shadowcoords_f.z / shadowcoords_f.w;

    if (ComparedZ > (ShadowMapValue - 0.0001))
	return 0.2;
    else
	return 1.0;
}

void main(void)
{

    vec3 texcoord = ((my_Position.xyz / my_Position.w) * 0.5 + vec3(0.5)).xyz;

    vec4 water_texture_value = texture(water_texture, my_Texcoord.xy);

    float x_left = (texture(water_texture, vec2(my_Texcoord.x - 0.01, my_Texcoord.y)).r - 0.5);
    float x_right = (texture(water_texture, vec2(my_Texcoord.x + 0.01, my_Texcoord.y)).r - 0.5);

    float z_left = (texture(water_texture, vec2(my_Texcoord.x, my_Texcoord.y - 0.01)).r - 0.5);
    float z_right = (texture(water_texture, vec2(my_Texcoord.x, my_Texcoord.y + 0.01)).r - 0.5);

    float x_diff = x_left - x_right;
    float z_diff = z_left - z_right;
    vec3 my_Normal2 = vec3(x_diff * 15, 1.0, z_diff * 15);

    float water_height = min(pow(texture(refraction_texture, texcoord.xy).a * 32.0, 4.0) / 64.0, 1.0);
    float distance_to_eye = 1.0 - clamp(pow(length(my_EyeDir / 50), 0.3), 0.0, 1.0);

    vec4 reflection_value = texture(reflection_texture, texcoord.xy + water_height * distance_to_eye * (water_texture_value.xy / 4));

    vec4 refraction_value = texture(refraction_texture, texcoord.xy + water_height * distance_to_eye * (water_texture_value.xy / 4));


    vec3 E = normalize(my_EyeDir);
    vec3 N_straight = NormalMatrix * vec3(0.0, 1.0, 0.0);
    vec3 R_straight = reflect(E, N_straight);

    vec3 N = normalize(NormalMatrix * my_Normal2);

    vec3 R = reflect(E, N);

    float refract_factor = min(pow(max(dot(R_straight, N_straight), 0.2), 0.8), 0.93);

    vec4 light_value = vec4(0.0, 0.0, 0.0, 1.0);

    //these things should set per uniforms
    float MaterialShininess = 100.0;
    vec3 MaterialSpecular = vec3(1.0);
    vec3 MaterialDiffuse = vec3(0.2);
    vec3 LightSpecular = vec3(1.0);
    vec3 LightDiffuse = vec3(0.1);
    float att = 1.0;
    //end

    vec3 L = normalize(my_LightDir);

    float lambertTerm = dot(N,L);

    if (calcLight() > 0.5)
    {
	    vec3 E = normalize(my_EyeDir);
	    vec3 R = reflect(-L, N);

	    float specular = pow(max(dot(R, E), 0.0), MaterialShininess);

	    light_value += vec4(LightDiffuse * MaterialDiffuse * abs(lambertTerm) * att, 1.0);
	    light_value += vec4(LightSpecular * MaterialSpecular * specular * att, 1.0);
    }

    const float LOG2 = 0.442695;
    float z = length(my_EyeDir);
    const float fog_density = 0.004;
    vec4 fogColor = vec4(0.4, 0.4, 0.6, 1.0);
    float fogFactor = exp( -fog_density * fog_density * z * z * LOG2 );
    fogFactor = clamp(fogFactor, 0.0, 1.0);

    vec4 out_Color_without_Fog = 0.8 * ((water_texture_value * 0.6 + 0.4 * reflection_value + light_value*2.0) * (1.0 - refract_factor) + refraction_value * (refract_factor) ) + light_value*0.5;


   out_Color = out_Color_without_Fog;

}
