#version 330 core

in vec2 fragmentUV;
in vec4 smCoords;
in vec3 worldNormal;
in vec3 worldPosition;
in vec4 fragmentPositionInLightSpace;

uniform vec3 worldCameraPosition;
uniform bool hasShadows;
uniform bool hasPCF;
uniform sampler2D sampler;
uniform sampler2D shadowMap;
uniform sampler2DShadow shadowMap2;

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;

float calculatePCF(vec4 fragPosLightSpace)
{
    vec3 smCoordsLocal = fragPosLightSpace.xyz / fragPosLightSpace.w;
    
    smCoordsLocal = smCoordsLocal * 0.5 + 0.5;

    float closestDepth = texture(shadowMap, smCoordsLocal.xy).r; 
    float currentDepth = smCoordsLocal.z;

    vec3 normal = normalize(worldNormal);
    vec3 lightDir = normalize(light.position - worldPosition);
    float bias = max(0.001 * (1.0 - dot(normal, lightDir)), 0.001);
    
    float shadowMult = 0.0;
    vec2 texelSize = 1.0 / textureSize(shadowMap, 0);
    for(int x = -1; x <= 1; ++x)
    {
        for(int y = -1; y <= 1; ++y)
        {
            float pcfDepth = texture(shadowMap, smCoordsLocal.xy + vec2(x, y) * texelSize).r; 
            shadowMult += currentDepth - bias > pcfDepth  ? 1.0 : 0.0;        
        }    
    }
    shadowMult /= 9.0;
    
    if(smCoordsLocal.z > 1.0)
        shadowMult = 0.0;
        
    return shadowMult;
}

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 * textureColor * light.intensity * 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 * light.intensity;

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

	vec3 lightColor = vec3(1,1,1);

	vec3 diffuseColor = texture(sampler, fragmentUV).rgb;

	float shadowMult = 0;

	if (hasPCF)
	{
		shadowMult = hasShadows ? calculatePCF(fragmentPositionInLightSpace) : 0.0;
		colorSum = ambientColor + attenuation * (1.0 - shadowMult) * (diffuseComponent + specularComponent);
	}
	else
	{
		shadowMult = hasShadows ? textureProj(shadowMap2, smCoords) : 0.0;
		colorSum = ambientColor + attenuation * (shadowMult) * (diffuseComponent + specularComponent);
	}

//	colorSum = ambientColor + attenuation * (1.0 - shadowMult) * (diffuseComponent + specularComponent);

	outColor = vec4(colorSum, 0);
}
