#version 330 

// remember to change the light amount in LightSource.h too!
const int lightSourcesAmount = 8;
float intensity = 1;

layout(std140) uniform;

in vec3 modelSpaceNormal;
in vec4 modelSpacePos;

struct LightSource
{
	vec4 worldPos;
	vec4 diffColor;
	vec4 specColor;
};
uniform Light {
	vec4 ambientColor;

	LightSource[lightSourcesAmount] lightSources;
} Lgt;

uniform Material {
	vec4 diffColor;
	vec4 specColor;
	float specCoeff;
} Mtl;

uniform vec4 camPosWorldSpace;
uniform mat4 world2model;

float calcAttenuation(in vec3 lightPosModelSpace)
{
	vec3 lightDir =  lightPosModelSpace - modelSpacePos.xyz;
	float lightDistanceSqr = dot(lightDir, lightDir);
	
	return (1 / ( 1.0 + 0.008 * lightDistanceSqr));
}

vec3 calcLightDir(LightSource light) {
	//if the w coordinate of lightPos is 1 then the light is a positional light
	//if the w coordinat of lightPos is 0, then the light is directional
	if(light.worldPos.w == 0.0) {
		return normalize(light.worldPos.xyz);
	} else {
		vec4 lightPosModelSpace = light.worldPos*transpose(world2model);
		intensity = calcAttenuation(lightPosModelSpace.xyz);
		return normalize(normalize(lightPosModelSpace - modelSpacePos).xyz);
	}
}

vec4 calcLighting(LightSource light) {
	vec3 lightDir = calcLightDir(light);
	float normalLightAngle = clamp(dot(modelSpaceNormal,lightDir), 0.0, 1.0);
	vec4 I_diff = light.diffColor * Mtl.diffColor * light.diffColor.w * Mtl.diffColor.w;
	vec4 I_spec = light.specColor * Mtl.specColor * light.specColor.w * Mtl.specColor.w;

	if(I_diff.a > 0) {
		//calculate Diffuse Term:
		I_diff = I_diff * normalLightAngle;
	}

	if(I_spec.a > 0) {
		// calculate Specular Term:
		vec4 camPosModelSpace = camPosWorldSpace * world2model;
		vec3 viewingDir = normalize(normalize(camPosModelSpace - modelSpacePos).xyz);
	
		vec3 halfAngle = normalize(lightDir + viewingDir);
		float angleNormalHalf = acos(dot(halfAngle, modelSpaceNormal));
		float exponent = angleNormalHalf / Mtl.specCoeff;
		exponent = -pow(exponent, 2);
		float gaussian = exp(exponent);
		gaussian = normalLightAngle != 0.0 ? gaussian : 0.0;
		I_spec = I_spec * gaussian;
	}
	return (I_diff+I_spec)*intensity;
}

vec4 calcAccumLighting(void) {
	//calculate Ambient Term:
	vec4 I_amb = Lgt.ambientColor * Lgt.ambientColor.w;

	vec4 accumLighting = I_amb;


	for( int i=0;i<lightSourcesAmount;i++ ) {
		vec4 lighting = calcLighting(Lgt.lightSources[i]);

		accumLighting += lighting;
	}

	return accumLighting;
}