#version 330 core

#define MAX_LIGHTS 4

in vec2 texCoord;
in vec4 vertexFragColor;
in vec3 normal;
in vec3 eye;
in vec4 shadowPosition;

out vec4 fragColor;
uniform sampler2D texture0; // diffuse
uniform sampler2D texture1; // ambient / depth
uniform sampler2D texture2; // specular
uniform sampler2D texture3; // normal
uniform sampler2DShadow shadow10; // shadow
uniform vec4 color = vec4(1.0,1.0,1.0,1.0);
uniform bool enableVertexColor = false;
uniform int activeLightCount = 0;
uniform float shadowTransparency = 0.5;
uniform bool drawShadows = false;

in LightCalc {
    vec4 diffuse;
    vec4 ambient;
    vec4 specular;
    vec3 toLight;
} lightIn;/*[MAX_LIGHTS];*/

struct Material {
    vec4 diffuse;
    vec4 ambient;
    vec4 specular;
    float shininess;
};

uniform Material material = Material(vec4(1.0,1.0,1.0,1.0), vec4(1.0,1.0,1.0,1.0), vec4(1.0,1.0,1.0,1.0), 10.0);

vec4 calculateDepthColor()
{
    float z = texture(texture1, texCoord).r;
    float near = 1.0;
    float far = 1000.0;
    return vec4(vec3((2.0 * near) / (far + near - z * (far - near))), 1.0);
}

void main(void)
{
    fragColor = color;

    if (enableVertexColor) {
        fragColor *= vertexFragColor;
    }

    if (activeLightCount > 0) {
        // Blinn-Phong type of lighting calculation
        vec4 baseColor = fragColor;
        vec3 fragEye = normalize(eye);
        vec3 fragNormal = normalize(normal);

        fragColor = vec4(0.0,0.0,0.0,0.0);

        for (int i = 0; i < activeLightCount; i++) {
            // normalize after vs -> fs interpolation
            vec3 fragToLight = normalize(lightIn/*[i]*/.toLight);

            // maths should be checked at some sunny day. bump/normal mapping looked "good enough" with test subjects...
            vec3 bump = normalize(texture(texture3, texCoord).xyz * 2.0 - 1.0);
            float bumpDiffuse = max(dot(fragToLight, bump), 0.0);
            fragNormal *= bumpDiffuse;

            vec4 fragAmbientColor = material.ambient * lightIn/*[i]*/.ambient * texture(texture1, texCoord);

            // calculate diffuse / matte / lambertian reflection
            float diffuseTerm = clamp(dot(fragNormal, fragToLight), 0.0, 1.0);
            vec4 fragDiffuseColor = material.diffuse * lightIn/*[i]*/.diffuse * diffuseTerm * texture(texture0, texCoord);

            // calculate specular reflection
            vec4 fragSpecularColor = vec4(0.0,0.0,0.0,0.0);
            if(dot(fragNormal, fragToLight) > 0.0) {
                vec3 halfVector = normalize(fragToLight + fragEye);
                float specularHighlight = pow(dot(fragNormal, halfVector), material.shininess);

                fragSpecularColor = material.specular * lightIn/*[i]*/.specular * specularHighlight * texture(texture2, texCoord);
            }

            fragColor += baseColor * (fragAmbientColor + fragDiffuseColor + fragSpecularColor);
        }
    } else {
        fragColor *= texture(texture0, texCoord);
    }


    if (drawShadows){
        float visibility = texture(shadow10, vec3(shadowPosition.xy, (shadowPosition.z)/shadowPosition.w));

        fragColor.rgb *= visibility;
    }

    fragColor = clamp(fragColor, vec4(0.0,0.0,0.0,0.0), vec4(1.0,1.0,1.0,1.0));
} 
