/*
 * fragment shader for heightmap rendering
 *
 * calculates the pixel color by using the given detail textures
 * and the information in the heightmap-texture, which texture has which opacity
 *
 * written by:
 * christian moellinger <ch.moellinger@gmail.com>
 * 01/2011
 */

#version 330 core
precision highp float;

uniform sampler2D detailTexture1;
uniform sampler2D detailTexture1_normal;
uniform sampler2D detailTexture1_bump;
uniform sampler2D detailTexture2;
uniform sampler2D detailTexture2_normal;
uniform sampler2D detailTexture2_bump;
uniform sampler2D detailTexture3;
uniform sampler2D detailTexture3_normal;
uniform sampler2D detailTexture3_bump;
uniform sampler2D baseTexture;
uniform sampler2D heightmap;
uniform sampler2D shadowmap;

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

out vec4 FragColor;
in vec2 texcoords;
in vec3 my_ObjPosition;
in float fog;
in vec3 my_Normal;
in vec3 my_LightDir;
in vec3 my_EyeDir;
in mat3 NormalMatrix2;
in vec4 my_WorldPosition;
in vec2 my_ShadowMapCoords;
in vec4 finalPosition;

float factor_detail3 = (1.0 - texture(heightmap, texcoords).a);
float factor_detail1 = texture(heightmap, texcoords).g * (1 - factor_detail3);
float factor_detail2 = texture(heightmap, texcoords).b * (1 - factor_detail3);


vec4 detail1 = texture(detailTexture1, texcoords * 20);
vec4 detail2 = texture(detailTexture2, texcoords * 20);

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

//these things should set per uniforms
float MaterialShininess = 100.0;
float att = 1.0;

const vec4 Light0Ambient = vec4(0.0);
const vec4 Light0Diffuse = vec4(0.8);
const vec4 Light0Specular = vec4(1.0);

const vec4 MaterialAmbient = vec4(1.0);
const vec4 MaterialDiffuse = vec4(1.0);
const vec4 MaterialSpecular = vec4(1.0);
//end

const float invRadius = 0.1;



const float scale = 0.006;

vec4 doParallax1()
{
    float distSqr = dot(my_LightDir, my_LightDir);

    float att = 1.0;//clamp(1.0 - invRadius * sqrt(distSqr), 0.0, 1.0);

    vec3 lVec = my_LightDir * inversesqrt(distSqr);

    vec3 vVec = normalize(my_EyeDir);
    vec3 vVec2 = vec3(-vVec.y, -vVec.x, vVec.z); //dont know why this is needed - maybe a bug in viewvector or tangent calculation?

   // vVec2.x = -vVec2.x;	//dont know why this is needed - maybe a bug in viewvector calculation?
   // vVec2.y = -vVec2.y;	//dont know why this is needed - maybe a bug in viewvector calculation?

    float height = texture(detailTexture1_bump, texcoords * 5).r;
    float offset = scale * (2.0 * height - 1.0);

    vec2 texcoord_offset = (offset * vVec2.xy);// / vVec2.z;

    vec4 bump_value = vec4(texture(detailTexture1_normal, 5 * texcoords + texcoord_offset).rgb, 1.0);
    vec4 texture_value = texture(detailTexture1, 5 * texcoords + texcoord_offset);

    vec4 base = texture_value;

    vec3 bump = normalize(bump_value.rgb * 2.0 - 1.0);

    vec4 vAmbient = Light0Ambient * MaterialAmbient;

    float diffuse = max( dot(lVec, bump), 0.0 );

    vec4 vDiffuse = Light0Diffuse * MaterialDiffuse * diffuse;

    float specular = pow(clamp(dot(reflect(-lVec, bump), vVec), 0.0, 1.0), 10.0);

    vec4 vSpecular = Light0Specular * MaterialSpecular * specular;

    vec4 light_value = (vAmbient*base + vDiffuse*base + vSpecular) * att;

    return (light_value * texture_value);
}

vec4 doParallax2()
{
    float distSqr = dot(my_LightDir, my_LightDir);

    vec3 lVec = my_LightDir * inversesqrt(distSqr);

    vec3 vVec = normalize(my_EyeDir);
    vec3 vVec2 = vec3(-vVec.y, -vVec.x, vVec.z); //dont know why this is needed - maybe a bug in viewvector or tangent calculation?

    float height = texture(detailTexture2_bump, texcoords * 5).r;
    float offset = scale * (2.0 * height - 1.0);

    vec2 texcoord_offset = (offset * vVec2.xy);// / vVec2.z;

    vec4 bump_value = vec4(texture(detailTexture2_normal, 5 * texcoords + texcoord_offset).rgb, 1.0);
    vec4 texture_value = texture(detailTexture2, 5 * texcoords + texcoord_offset);

    vec4 base = texture_value;

    vec3 bump = normalize(bump_value.rgb * 2.0 - 1.0);

    vec4 vAmbient = Light0Ambient * MaterialAmbient;

    float diffuse = max( dot(lVec, bump), 0.0 );

    vec4 vDiffuse = Light0Diffuse * MaterialDiffuse * diffuse;

    float specular = pow(clamp(dot(reflect(-lVec, bump), vVec), 0.0, 1.0), 10.0);

    vec4 vSpecular = Light0Specular * MaterialSpecular * specular;

    vec4 light_value = (vAmbient*base + vDiffuse*base + vSpecular);

    return (light_value * texture_value);
}

vec4 doParallax3()
{
    float distSqr = dot(my_LightDir, my_LightDir);

    vec3 lVec = my_LightDir * inversesqrt(distSqr);

    vec3 vVec = normalize(my_EyeDir);
    vec3 vVec2 = vec3(-vVec.y, -vVec.x, vVec.z); //dont know why this is needed - maybe a bug in viewvector or tangent calculation?

    float height = texture(detailTexture3_bump, texcoords * 5).r;
    float offset = scale * 2 * (2.0 * height - 1.0);

    vec2 texcoord_offset = (offset * vVec2.xy);// / vVec2.z;

    vec4 bump_value = vec4(texture(detailTexture3_normal, 5 * texcoords + texcoord_offset).rgb, 1.0);
    vec4 texture_value = texture(detailTexture3, 5 * texcoords + texcoord_offset);

    vec4 base = texture_value;

    vec3 bump = normalize(bump_value.rgb * 2.0 - 1.0);

    vec4 vAmbient = Light0Ambient * MaterialAmbient;

    float diffuse = max( dot(lVec, bump), 0.0 );

    vec4 vDiffuse = Light0Diffuse * MaterialDiffuse * diffuse;

    float specular = pow(clamp(dot(reflect(-lVec, bump), vVec), 0.0, 1.0), 10.0);

    vec4 vSpecular = Light0Specular * MaterialSpecular * specular;

    vec4 light_value = (vAmbient*base + vDiffuse*base + vSpecular);

    return (light_value * texture_value);
}

vec4 doPhong()
{
    vec3 N = normalize(NormalMatrix2 * normalize(my_Normal));

    vec3 L = normalize(my_LightDir);

    float lambertTerm = dot(N,L);

    if(lambertTerm > 0.0)
    {
	    light_value += Light0Diffuse * MaterialDiffuse * lambertTerm * att;

	    vec3 E = normalize(my_EyeDir);
	    vec3 R = reflect(-L, N);

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

	    light_value += Light0Specular * MaterialSpecular * specular * att;
    }

    return vec4((1.0 - fog) * vec3(factor_detail1 * detail1 + factor_detail2 * detail2) * light_value.rgb, -my_ObjPosition.y * 10);
}

vec4 doNormalMapping1()
{
    float distSqr = dot(my_LightDir, my_LightDir);

    vec3 lVec = my_LightDir * inversesqrt(distSqr);

    vec3 vVec = normalize(my_EyeDir);
    vec3 vVec2 = vec3(-vVec.y, -vVec.x, vVec.z); //dont know why this is needed - maybe a bug in viewvector or tangent calculation?

    vec4 bump_value = vec4(texture(detailTexture1_normal, 5 * texcoords).rgb, 1.0);
    vec4 texture_value = texture(detailTexture1, 5 * texcoords);

    vec3 bump = normalize(bump_value.rgb * 2.0 - 1.0);

    vec4 vAmbient = Light0Ambient * MaterialAmbient;

    float diffuse = max( dot(lVec, bump), 0.0 );

    vec4 vDiffuse = Light0Diffuse * MaterialDiffuse * diffuse;

    float specular = pow(clamp(dot(reflect(-lVec, bump), vVec), 0.0, 1.0), 10.0);

    vec4 vSpecular = Light0Specular * MaterialSpecular * specular;

    vec4 light_value = (vAmbient*texture_value + vDiffuse*texture_value + vSpecular);

    return (light_value * texture_value);
}

vec4 doNormalMapping2()
{
    float distSqr = dot(my_LightDir, my_LightDir);

    vec3 lVec = my_LightDir * inversesqrt(distSqr);

    vec3 vVec = normalize(my_EyeDir);
    vec3 vVec2 = vec3(-vVec.y, -vVec.x, vVec.z); //dont know why this is needed - maybe a bug in viewvector or tangent calculation?

    vec4 bump_value = vec4(texture(detailTexture2_normal, 5 * texcoords).rgb, 1.0);
    vec4 texture_value = texture(detailTexture2, 5 * texcoords);

    vec3 bump = normalize(bump_value.rgb * 2.0 - 1.0);

    vec4 vAmbient = Light0Ambient * MaterialAmbient;

    float diffuse = max( dot(lVec, bump), 0.0 );

    vec4 vDiffuse = Light0Diffuse * MaterialDiffuse * diffuse;

    float specular = pow(clamp(dot(reflect(-lVec, bump), vVec), 0.0, 1.0), 10.0);

    vec4 vSpecular = Light0Specular * MaterialSpecular * specular;

    vec4 light_value = (vAmbient*texture_value + vDiffuse*texture_value + vSpecular);

    return (light_value * texture_value);
}

vec4 doNormalMapping3()
{
    float distSqr = dot(my_LightDir, my_LightDir);

    vec3 lVec = my_LightDir * inversesqrt(distSqr);

    vec3 vVec = normalize(my_EyeDir);
    vec3 vVec2 = vec3(-vVec.y, -vVec.x, vVec.z); //dont know why this is needed - maybe a bug in viewvector or tangent calculation?

    vec4 bump_value = vec4(texture(detailTexture3_normal, 5 * texcoords).rgb, 1.0);
    vec4 texture_value = texture(detailTexture3, 5 * texcoords);

    vec3 bump = normalize(bump_value.rgb * 2.0 - 1.0);

    vec4 vAmbient = Light0Ambient * MaterialAmbient;

    float diffuse = max( dot(lVec, bump), 0.0 );

    vec4 vDiffuse = Light0Diffuse * MaterialDiffuse * diffuse;

    float specular = pow(clamp(dot(reflect(-lVec, bump), vVec), 0.0, 1.0), 10.0);

    vec4 vSpecular = Light0Specular * MaterialSpecular * specular;

    vec4 light_value = (vAmbient*texture_value + vDiffuse*texture_value + vSpecular);

    return (light_value * texture_value);
}

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


    int x,y;
    const int steps = 5;
    float light = 1.0;

    for (x=-steps/2; x < steps/2; x++)
    {
    for (y=-steps/2; y < steps/2; y++)
	{
	    vec2 new_shadowcoords = vec2(shadowcoords.x + x / 4096.0, shadowcoords.y + y / 4096.0);
	    float ShadowMapValue = texture(shadowmap, new_shadowcoords).r;

	    float ComparedZ = shadowcoords_f.z / shadowcoords_f.w;

	    if (ComparedZ > (ShadowMapValue - 0.0001))
		light -= 1.0 / steps;
	}
    }

    return clamp(light, 0.2, 1.0);
    //return 1.0;
}

void main()
{
    float light = calcLight();

   /* if (factor_detail3 > 0.0 && factor_detail3 < 1.0)
	factor_detail3 *= clamp(texture(detailTexture2_bump, texcoords * 5).r * 10, 0.0, 1.0);*/

    /*factor_detail2 = 1.0;
    factor_detail1 = 0.0;*/

    if (my_ObjPosition.y < 0.0)// || (finalPosition.z / finalPosition.w > 0.98))
	FragColor = vec4((light * (1.0 - fog) * (factor_detail1 * doNormalMapping1() + factor_detail2 * doNormalMapping2() + factor_detail3 * doNormalMapping3())).rgb, -my_ObjPosition.y * 10);
    else
    {
	/*float depth = (finalPosition.z / finalPosition.w);
	if (depth > 0.95)
	{
	    vec4 phong_result = doPhong();
	    vec4 parallax_result = factor_detail1 * doParallax1() + factor_detail2 * doParallax2();
	    float factor = (0.98 - depth) * 100;
	    FragColor = light * ((1-factor) * phong_result + factor * parallax_result);
	}
	else*/
	    FragColor = vec4((light * (1.0 - fog) * (factor_detail1 * doParallax1() + factor_detail2 * doParallax2() + factor_detail3 * doParallax3())).rgb, -my_ObjPosition.y * 10);
    }

}

