#ifdef GL_ES
// Set default precision to medium
precision mediump int;
precision mediump float;
#endif

uniform mat3 n_matrix;
uniform vec3 cameraPosition;

uniform sampler2D texture;
uniform float materialShininess;
uniform vec3 materialSpecularColor;

uniform bool b_transparent;
uniform bool b_specular;
uniform bool b_light;

uniform struct Light {
	vec4 position;
	vec3 intensities;
	float attenuationFactor;
	float ambientCoefficient;
} light;

varying vec2 v_surfaceUV;
varying vec3 v_surfacePosition;
varying vec3 v_surfaceNormal;

void main()
{
	if(b_light)
	{
		// some values
		vec3 normalWorld = normalize(n_matrix * v_surfaceNormal);

		vec4 surfaceColor = vec4(texture2D(texture, v_surfaceUV));
		surfaceColor.rgb = pow(surfaceColor.rgb, vec3(2.2));
		
		vec3 surfaceToLight;
		float attenuation;
		// directional light
		if(light.position.w == 0.0f)
		{
			surfaceToLight = normalize(light.position.xyz);
		}
		// point light
		else
		{
			surfaceToLight = normalize(light.position.xyz - v_surfacePosition);
		}
		
		float distanceToLight = length(light.position.xyz - v_surfacePosition);
		attenuation = 1.0 / (1.0 + light.attenuationFactor * pow(distanceToLight, 2));

		vec3 surfaceToCamera = normalize(cameraPosition - v_surfacePosition);

		// ambient
		vec3 ambient = light.ambientCoefficient * surfaceColor.rgb * light.intensities;

		// diffuse
		float diffuseCoefficient = max(0.0, dot(normalWorld, surfaceToLight));
		vec3 diffuse = diffuseCoefficient * surfaceColor.rgb * light.intensities;

		// specular
		float specularCoefficient = 0.0;
		if(diffuseCoefficient > 0.0)
			specularCoefficient = pow(max(0.0, dot(surfaceToCamera, reflect(-surfaceToLight, normalWorld))), materialShininess);
		vec3 specColor;
		if(b_specular)
			specColor = vec3(surfaceColor.a);
		else
			specColor = materialSpecularColor;
		vec3 specular = specularCoefficient * specColor * light.intensities;

		// linear color before gamma correction)
		vec3 linearColor = ambient + attenuation * (diffuse + specular);

		// final color after gama correction
		vec3 gamma = vec3(1.0/2.2);
		if(!b_transparent)
			surfaceColor.a = 1.0f;
		gl_FragColor = vec4(pow(linearColor, gamma), surfaceColor.a);
	}
	else
	{
		vec4 surfaceColor = vec4(texture2D(texture, v_surfaceUV));
		if(!b_transparent)
			surfaceColor.a = 1.0f;

		gl_FragColor = surfaceColor;
	}
}
