#version 400 core

//in vec2 fTexcoord;
in vec3 fPosition;
in vec4 fLocalPosition;
in vec2 fWave1TexLookup;
in vec2 fWave2TexLookup;
in vec3 fCamPosition;
in float fWave1Ratio;
in float fWave2Ratio;
//in vec4 shadowCoord1;

in vec4 fRefractionMapLookup;

struct Light {
	vec3 position;
	vec3 intensity;
	vec4 direction;
	float angle;
};

out vec4 outColor;

uniform mat4 model;
uniform mat4 view;
uniform mat4 proj;

uniform sampler2D wave1;
uniform sampler2D wave2;
uniform sampler2D reflectionTex;
uniform sampler2D underwaterTex;

uniform Light light1;
uniform Light light2;

vec3 calcDirectionalLight(Light dLight, vec3 normals) {
	vec4 lightDirection = dLight.direction;
	vec3 toLightDir = normalize(-lightDirection).xyz;
	vec3 norm = normalize(normals);
	float diff = max(dot(norm, toLightDir), 0.0);
	vec3 diffuse = vec3(diff);
	float shadow = 1; //calcShadowPCSSPCFPoisson(shadowCoord, shadowMap);
	diffuse = shadow * diffuse;
	return diffuse;
}

vec3 calcSpotLight(Light spotLight, vec3 normals) {
	vec4 lightDirection = spotLight.direction;
	vec3 lightPosition = spotLight.position;
	float lightCutOff = cos(radians(spotLight.angle));
	float lightCutOffInner = cos(radians(spotLight.angle - 5.0f));
	float lightDiffuse = 0.5f;
	float lightConstant = 1.0f;
	float lightLinear =  0.007f;
	float lightQuadratic = 0.0002f;

	vec3 toLightDir = normalize(lightPosition - fPosition);
	float theta = dot(toLightDir, normalize(-lightDirection).xyz);
	float cutOffDiff = lightCutOffInner - lightCutOff;
	float intensity = clamp((theta - lightCutOff) / cutOffDiff, 0.0, 1.0);
	//float shadow = calcShadowSAVSM(shadowCoord, shadowMap, satFilterSize);
    float shadow = 1; //calcShadowPCSSSAVSM(shadowCoord, shadowMap3, shadowMap);
	//float shadow = calcShadowVSM(shadowCoord, shadowMap3);
	//float shadow = calcShadowPCSSPCFPoisson(shadowCoord, shadowMap3);
	//float shadow = 1;

	if(theta >= lightCutOff) {
		// Diffuse
		vec3 norm = normalize(normals);
		float diff = max(dot(norm, toLightDir), 0.0);
		vec3 diffuse = vec3(lightDiffuse * diff);

		// Attenuation
		float distance = length(lightPosition - fPosition);
		float attenuation = 1.0f / (lightConstant + lightLinear * distance + lightQuadratic * (distance * distance));
		diffuse = shadow * (diffuse * attenuation);

		return diffuse * intensity;
	} else {
		return vec3(0.0f, 0.0f, 0.0f);
	}
}

float fresnelFunc(vec3 direction, vec3 normal, bool invert) {
    vec3 nDirection = normalize( direction );
    vec3 nNormal = normalize( normal );
    vec3 halfDirection = normalize( nNormal + nDirection );

    float cosine = dot( halfDirection, nDirection );
    float product = max( cosine, 0.0 );
    float factor = invert ? 1.0 - pow( product, 5.0 ) : pow( product, 5.0 );

    return factor;
}

void main(void) {

	vec3 ambient = vec3(0.4f, 0.4f, 0.4f);
	vec3 waterColor = vec3(0, 0.15f, 0.115f);

	vec3 normal = fWave1Ratio * texture2D(wave1, fWave1TexLookup).rgb;
	normal = normal + fWave2Ratio * texture2D(wave2, fWave2TexLookup).rgb;

	normal = normal + 1.0 * texture2D(wave2, fWave2TexLookup * 3.6).rgb;
	normal = normal + 1.0 * texture2D(wave2, fWave1TexLookup * 2.9).rgb;

	normal = normalize(normal).xzy * 2.0f - 1.0f;

	//outColor = vec4(normal, 1.0f);
	//return;

	vec3 diffuse = vec3(0);

	vec4 lightDirection = light1.direction;
	if (lightDirection.w == 1.0) {
		diffuse = calcSpotLight(light1, normal.xyz);
	} else { //directional light
		diffuse = calcDirectionalLight(light1, normal.xyz);
	}
	//diffuse = vec3(1.0f);
	//vec3 diffuse = calcLight(spotLight1, normal);


	vec3 viewDir = normalize(view[1].xyz);

	/* --------------- Reflection ---------------- */
	vec3 I = viewDir;
  vec3 R = reflect(I, normal);
  //vec3 reflectionColor = texture(skybox, R).xyz;
	vec4 projectedCoords = proj * view * model * vec4(fLocalPosition.x, 0, fLocalPosition.z, 1);
	vec2 lookup = projectedCoords.xy / projectedCoords.w;
	lookup =  vec2(0.5, 0.5) + 0.5 * lookup;
	vec3 reflection = texture(reflectionTex, lookup).xyz;

	/* --------------- Refraction ---------------- */
	float distToIsland = (length(abs(fPosition.xyz)) -110);
	float depth = smoothstep(0.0f, 1.0f, distToIsland/140.0f);
	//depth = 0;
	float invDepth = 1 - depth;
	vec3 refrlookup = fPosition.xyz;
	refrlookup.xz = refrlookup.xz - (normal.xz - 0.5f) * 2.0f;
	refrlookup.xz = refrlookup.xz * 0.05f;
	refrlookup.xz = refrlookup.xz * mix(1f, 1.6f, depth);
	vec3 underwaterColor = texture(underwaterTex, (refrlookup.xz)).rgb;
	vec3 refraction = underwaterColor * invDepth + waterColor;

	float fresnel = fresnelFunc(I, normal, false);
	vec3 finalColor = mix(refraction, reflection, fresnel) * diffuse;

	// set the specular term to black
    float specular = 0.0f;

    // normalize both input vectors
    vec3 n = normalize(normal.xyz);
    vec3 e = normalize(viewDir.xyz);

    float intensity = max(dot(n,-light1.direction.xyz), 0.0);

    // if the vertex is lit compute the specular color
    if (intensity > 0.0) {
        // compute the half vector
        vec3 h = normalize(-light1.direction.xyz + e);
        // compute the specular term into spec
        float intSpec = max(dot(h,n), 0.0);
        specular = pow(intSpec,40);
    }
	//finalColor = vec3(specular);
	finalColor = clamp(finalColor + vec3(specular), 0.0f, 1.0f);
	//finalColor = normal; //vec3(light);
	outColor = vec4(finalColor.rgb, 1.0f);

	//outColor = vec4(1.0, 0.0, 0.0, 1.0);
}
