#version 330 core

#define WRONG_SSS false

uniform vec3 ambientLightColor;
uniform float ambientLightIntensity;

uniform vec3 directionalDiffuseLightColor;
uniform vec3 directionalLightViewDirection;
uniform float directionalLightIntensity;
uniform sampler2DShadow directionalShadowMap;

uniform vec3 pointLightViewPosition;
uniform vec3 pointDiffuseLightColor;
uniform vec3 pointLightWorldPosition;
uniform float pointLightFarPlane;
uniform float pointLightIntensity;
uniform samplerCubeShadow omniShadowMap;
uniform samplerCube omniShadowMapSSS;

uniform vec3 ambientObjectColor;
uniform vec3 diffuseObjectColor;
uniform vec3 specularObjectColor;
uniform bool hasSSS;
uniform vec2 specularAttributes; // x: specularCoeff, y: specPow
uniform sampler2D diffuseTexture;
 
in vec4 vertexViewPosition;
in vec3 vertexViewNormal;
in vec4 vertexColor;
in vec2 vertexTexCoord;

in vec4 vertexDirectionalSMTexCoord;
in vec3 vertexPointLightWorldDirection;

out vec4 outColor1;
 
void main(void)
{	
	// SHADOWS
	
	float isLitD = textureProj(directionalShadowMap, vertexDirectionalSMTexCoord);	
	
	float fragmentToPointLightDist = length(vertexPointLightWorldDirection);		
	float bias = 0.002;
	float isLitP = texture(omniShadowMap, vec4(-vertexPointLightWorldDirection, (fragmentToPointLightDist/pointLightFarPlane) - bias));
	
	// DIFFUSE TEXTURE
	
	vec3 diffuseTextureColor = texture(diffuseTexture, vertexTexCoord).xyz;	
	
	// POINT LIGHT FALLOFF
	
	float pointLightFalloff = 1.0 / (pow(fragmentToPointLightDist, 0.7) + 1.0);
	//pointLightFalloff = 1.0;
	
	// SSS

	vec3 sss = vec3(0, 0, 0);
	if(hasSSS)
	{
		if(WRONG_SSS) // looks kind of like sss but is wrong :)
		{		
			float factor = exp(-max(fragmentToPointLightDist, 0.0) * 4.5 + 2);						
			sss = vec3(factor, factor, factor) * pointDiffuseLightColor * diffuseTextureColor;
		}
		else
		{
			float sssSurfaceDist = texture(omniShadowMapSSS, -vertexPointLightWorldDirection).x * pointLightFarPlane;

			float sssPointLightFalloff = 1.0 / (pow(sssSurfaceDist, 0.7) + 1.0);
			sssPointLightFalloff = 1.0;

			float volumeDepth = fragmentToPointLightDist - sssSurfaceDist;
		
			float factor = exp(-max(volumeDepth, 0.0) * 5.5);
			
			sss = vec3(factor, factor, factor) * pointDiffuseLightColor * diffuseTextureColor * sssPointLightFalloff;
		}
	}

	// PHONG

	vec3 fragmentViewPosition = vertexViewPosition.xyz/vertexViewPosition.w;
	vec3 fragmentNormal = normalize(vertexViewNormal);

	vec3 pointLightViewDirection = normalize(pointLightViewPosition - fragmentViewPosition);
	
	// DIFFUSE

	float directionalDiffuseIntensity =  max(0.0, dot(fragmentNormal, directionalLightViewDirection));
	float pointDiffuseIntensity =  max(0.0, dot(fragmentNormal, pointLightViewDirection)) * pointLightFalloff;

	// SPECULAR 

	vec3 surfaceEyeDirection = normalize(-fragmentViewPosition);

	vec3 directionalLightReflection = reflect(-directionalLightViewDirection, fragmentNormal);
	float directionalSpecAngle = dot(surfaceEyeDirection, directionalLightReflection);
	float directionalSpecularIntensity = pow(max(0.0f, directionalSpecAngle), 100.0f/*specularAttributes.y*/);

	vec3 pointLightReflection = reflect(-pointLightViewDirection, fragmentNormal);
	float pointSpecAngle = dot(surfaceEyeDirection, pointLightReflection);
	float pointSpecularIntensity = pow(max(0.0f, pointSpecAngle), 100.0f/*specularAttributes.y*/) * pointLightFalloff;
	
	vec3 directionalDiffuseLight = directionalDiffuseLightColor * directionalDiffuseIntensity * isLitD;
	vec3 pointDiffuseLight = pointDiffuseLightColor * pointDiffuseIntensity * isLitP;

	vec3 directionalSpecularLight = directionalDiffuseLightColor * directionalSpecularIntensity * isLitD;
	vec3 pointSpecularLight = pointDiffuseLightColor * pointSpecularIntensity * isLitP;

	// COMBINE

	vec3 diffuseLight = directionalDiffuseLight * directionalLightIntensity + (pointDiffuseLight + sss) * pointLightIntensity;
	vec3 specularLight = directionalSpecularLight * directionalLightIntensity + pointSpecularLight * pointLightIntensity;
	
	vec3 ambientColor = ambientObjectColor * diffuseTextureColor * ambientLightIntensity; // little hack because blenders ambient light (world) color gets imported through this color via collada and assimp
	vec3 diffuseColor = diffuseLight * diffuseTextureColor;
	vec3 specularColor = specularLight * specularObjectColor;	
	vec3 finalColor = ambientColor + diffuseColor + specularColor;
	
	outColor1 = vec4(finalColor, 1);
}