#version 330 core

in vec2 fragmentUV;
in vec3 worldNormal;
in vec3 worldPosition;

uniform vec3 worldCameraPosition;

uniform sampler2D sampler;
uniform samplerCube shadowMap;

uniform float farPlane;
uniform bool hasShadows;

uniform struct Light{
	vec3 position;
	vec3 intensity;
	float attenuation;
} light;

uniform struct Material
{
	vec3 ambientMaterial;
	vec3 diffuseMaterial;
	vec3 specularMaterial;
} material;

layout(location=0) out vec4 outColor;

vec3 gridSamplingDisk[20] = vec3[]
(
   vec3(1, 1,  1), vec3( 1, -1,  1), vec3(-1, -1,  1), vec3(-1, 1,  1), 
   vec3(1, 1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1),
   vec3(1, 1,  0), vec3( 1, -1,  0), vec3(-1, -1,  0), vec3(-1, 1,  0),
   vec3(1, 0,  1), vec3(-1,  0,  1), vec3( 1,  0, -1), vec3(-1, 0, -1),
   vec3(0, 1,  1), vec3( 0, -1,  1), vec3( 0, -1, -1), vec3( 0, 1, -1)
);

float calcShadowContribution(vec3 worldPos)
{
	vec3 lookupVector = worldPos - light.position;
	float depth_current = length(lookupVector);

	float shadow = 0.0;
    float bias = 0.15;
    int samples = 1;
    float viewDistance = length(worldCameraPosition - worldPos);
    float diskRadius = (1.0 + (viewDistance / farPlane)) / 25.0;
	float depth_closest;
    for(int i = 0; i < samples; ++i)
    {
        depth_closest = texture(shadowMap, lookupVector + gridSamplingDisk[i] * diskRadius).r;
        depth_closest *= farPlane;   // Undo mapping [0;1]
        if(depth_current - bias > depth_closest)
            shadow += 1.0;
    }
	shadow /= float(samples);
	

	//outColor = vec4(vec3(depth_closest / farPlane), 1.0);  

	return shadow;
}

void main(void){

	vec3 textureColor = texture(sampler, fragmentUV).rgb;
	vec3 ambientColor = material.ambientMaterial * textureColor;

	vec3 colorSum = vec3(0);

	//normalize world normal to get the angle from the dot product
	vec3 n = normalize(worldNormal);

	//Calculate intensity based on Blinn model
	//light and camera direction
	vec3 viewVector = normalize(worldCameraPosition - worldPosition);
	vec3 lightDirection = normalize(light.position - worldPosition);

	//calculate dot product and get angle
	//clamp result to make sure we don't have negative colors
	float nDotL = clamp(dot(n, lightDirection), 0, 1);
	vec3 diffuseComponent = material.diffuseMaterial * nDotL;

	float specularCoeff = 0.0;
	if(nDotL > 0.0)
        specularCoeff = pow(clamp(dot(viewVector, reflect(-lightDirection, n)), 0, 1), 20);

	vec3 specularComponent = material.specularMaterial * specularCoeff;

    float lightToPosition = length(light.position - worldPosition);
    float attenuation = 1.0 / (1.0 + light.attenuation * pow(lightToPosition, 2));

	float shadowMult = calcShadowContribution(worldPosition);

	colorSum = (ambientColor * light.attenuation + (1-shadowMult) * light.intensity * (diffuseComponent + specularComponent)) * textureColor;

	outColor = vec4(colorSum, 1);
}
