#version 410

#define MAX_LIGHTS 3

#pragma include "p3d_uniform.glsl"
#pragma include "colors.glsl"

// Uniform inputs
uniform float u_MaxShininess;
uniform float u_RimLightIntensity;
uniform float u_ShadowSamples;
uniform float u_ShadowSpread;
uniform float u_SpecularBlendStrength;
uniform int u_NumberOfLights;
uniform float u_SpecularPower;
uniform float u_Brightness;
uniform float u_Rougness;
uniform bool u_Grayscale;
uniform float u_Saturation;

uniform sampler2D u_BaseColorTex;
uniform sampler2D u_MetallicRoughnessTex;
uniform sampler2D u_NormalTex;
uniform bool u_UseBaseColorTex;
uniform bool u_UseMetallicRoughnessTex;
uniform bool u_UseNormalTex;

uniform sampler2D u_BackTex;
uniform bool u_End;
uniform float u_Scroll;

uniform vec3 u_TexOrder;

// Input from vertex shader
in vec4 vertInShadowSpaces[MAX_LIGHTS];
in vec4 vertColor;
in vec4 vertPosition;
//in vec4 domiPosition;
in vec2 vertMultiTexCoord0;
in vec3 vertNormal;
in vec3 binormal;
in vec3 tangent;
in float neg;

// Output to the screen
out vec4 fragColor;

#define MAX_FRESNEL_POWER 5.0
#define MAX_SHININESS     127.75

//sampler2D p3d_Textures[1] = sampler2D[1](p3d_Texture0);
//int i[1] = {0};

//vec4 getCol(int index, vec2 uv) {
//    switch (index) {
//        case 0: return texture(p3d_Texture0, uv);
//        case 1: return texture(p3d_Texture1, uv);
//        case 2: return texture(p3d_Texture2, uv);
//        case 3: return texture(p3d_Texture3, uv);
//        default:
//            return vec4(0.0);
//    }
//}


void main() {

    if (vertColor.a == 0.0) { discard; }

    vec4 diffuseColor;
//    bool u_End = true;
    if (u_End) {
        diffuseColor = texture(p3d_TextureModulate[0], vec2(1.0, -1.0 / 6.0 * 1920. / 1080.) * vertMultiTexCoord0 + vec2(0.0, u_Scroll)) * vertColor;
//        diffuseColor = texture(p3d_TextureModulate[0], vec2(1.0, -1.0 / 6.0 * 1920. / 1080.) * vertMultiTexCoord0 + vec2(0.0, -0.826)) * vertColor;
    } else {
        diffuseColor = texture(u_BackTex, vec2(1.0, -1.0) * vertMultiTexCoord0) * vertColor;
    }

    if (u_Grayscale) {
        diffuseColor = vec4(vec3(brightness(diffuseColor.rgb)), diffuseColor.a);  // Grayscale
    }

    // Apply saturation
    diffuseColor = vec4(mix(vec3(brightness(diffuseColor.rgb)), diffuseColor.rgb, u_Saturation), diffuseColor.a);  // Grayscale

    // Apply brightness
    float u_Brightness = 1.5;  // Adjust brightness factor
    diffuseColor = vec4(diffuseColor.rgb * u_Brightness, diffuseColor.a);  // Brightness





//    diffuseColor = vec4(vec3(0.5), 1.0);

    vec4 roughnessMap = texture(p3d_TextureSelector[0], vertMultiTexCoord0);
//    vec4 roughnessMap;
//    if (u_UseMetallicRoughnessTex) {
//    roughnessMap = texture(u_MetallicRoughnessTex, vertMultiTexCoord0);
//    } else {
//        roughnessMap = vec4(0.0);
//    }

    vec4 normalTex = texture(p3d_TextureNormal[0], vertMultiTexCoord0);
//    vec4 normalTex;
//    if (u_UseNormalTex) {
//        normalTex = texture(u_NormalTex, vertMultiTexCoord0);
//    }


//    float roughness = roughnessMap.r;
    float roughness = roughnessMap.g;
    float shininess = (1.0 - roughness) * MAX_SHININESS * u_MaxShininess;
//    float shininess = (1.0 - roughness) * MAX_SHININESS * 0.0;

    vec4 diffuse  = vec4(0.0, 0.0, 0.0, diffuseColor.a);
    vec4 specular = vec4(0.0, 0.0, 0.0, diffuseColor.a);
    vec4 rim      = vec4(0.0, 0.0, 0.0, diffuseColor.a);

    vec3 materialSpecularColor = p3d_Material.specular;

    vec3 normal;

    for (int i = 0; i < u_NumberOfLights; ++i) {  // i = 0

        vec3 lightDirection = p3d_LightSource[i].position.xyz - vertPosition.xyz * p3d_LightSource[i].position.w;

        if (u_UseNormalTex) {
            vec3 normalRaw = normalize(normalTex.rgb * 2.0 - 1.0);
            normal = normalize(mat3(tangent, binormal, vertNormal) * normalRaw);
        } else {
            normal = normalize(vertNormal);
        }

        vec3 unitLightDirection = normalize(lightDirection);
        vec3 eyeDirection       = normalize(-vertPosition.xyz);
        vec3 halfwayDirection   = normalize(unitLightDirection + eyeDirection);

        float lightDistance = length(lightDirection);

        float attenuation = 1 / (
            p3d_LightSource[i].constantAttenuation +
            p3d_LightSource[i].linearAttenuation * lightDistance +
            p3d_LightSource[i].quadraticAttenuation * (lightDistance * lightDistance)
        );

        if (attenuation <= 0.0) { continue; }

        // Diffuse
        float diffuseIntensity  = dot(normal, unitLightDirection);
        if (diffuseIntensity < 0.0) { continue; }
        vec4 diffuseTemp = vec4(
            clamp(diffuseColor.rgb * p3d_LightSource[i].diffuse.rgb * diffuseIntensity, 0.0 , 1.0), diffuseColor.a
        );
//        temp = normal;
        diffuseTemp = clamp(diffuseTemp, vec4(0), diffuseColor);


        // Specular
        float specularIntensity = clamp(dot(normal, halfwayDirection), 0.0, 1.0);

        vec4 lightSpecularColor = p3d_LightSource[i].specular;

        vec4 materialSpecularColor = vec4(vec3(1.0 - roughness), diffuseColor.a);
        float fresnelFactor = dot(halfwayDirection, eyeDirection);
        fresnelFactor = max(fresnelFactor, 0.0);
        fresnelFactor = 1.0 - fresnelFactor;
        fresnelFactor = pow(fresnelFactor, MAX_FRESNEL_POWER);
        materialSpecularColor.rgb = mix(
            materialSpecularColor.rgb,
            vec3(u_SpecularBlendStrength),
//            fresnelFactor
            clamp(fresnelFactor, 0.0, 1.0)
        );

        vec4 specularTemp = vec4(vec3(0.0), diffuseColor.a);
        specularTemp.rgb  = lightSpecularColor.rgb * pow(specularIntensity, shininess);
        specularTemp.rgb *= materialSpecularColor.rgb;
        specularTemp.rgb  = clamp(specularTemp.rgb, 0.0, 1.0);  // Comment to have more specular
        specularTemp.rbg *= u_SpecularPower;  // RBG?!!

        // Spot
        float unitLightDirectionDelta = dot(normalize(p3d_LightSource[i].spotDirection), -unitLightDirection);
        if (unitLightDirectionDelta < p3d_LightSource[i].spotCosCutoff) { continue; }
        float spotExponent = p3d_LightSource[i].spotExponent;
        diffuseTemp.rgb *= (spotExponent <= 0.0 ? 1.0 : pow(unitLightDirectionDelta, spotExponent));

        // Shadow
        int u_ShadowSamples = int(u_ShadowSamples);
        float shadow = 0.0;
        int count = 0;
        for (int si = -u_ShadowSamples; si <= u_ShadowSamples; ++si) {
            for (int sj = -u_ShadowSamples; sj <= u_ShadowSamples; ++sj) {
                shadow += textureProj(
                    p3d_LightSource[i].shadowMap,
                    vertInShadowSpaces[i] + vec4(vec2(si, sj) * u_ShadowSpread, vec2(0.0))
                );
                count += 1;
            }
        }
        shadow /= count;

        diffuseTemp.rgb  *= shadow;
        specularTemp.rgb *= shadow;

        diffuseTemp.rgb  *= attenuation;
        specularTemp.rgb *= attenuation;

        diffuse  += diffuseTemp;
        specular += specularTemp;

        // Rim
        vec4 rimLight = vec4(0.0);
        rimLight.rgb = vec3(1.0 - max(0.0, dot(normalize(-vertPosition.xyz), normalize(normal))));
        rimLight.rgb = pow(rimLight.rgb, vec3(2.0)) * u_RimLightIntensity;
        rimLight.rgb *= diffuse.rgb;
        rim += rimLight;

    }

    vec4 ambient = p3d_Material.ambient * p3d_LightModel.ambient * diffuseColor;
    vec3 color = diffuse.rgb + rim.rgb + specular.rgb + ambient.rgb + p3d_Material.emission.rgb;
//    vec3 color = diffuse.rgb + rim.rgb + ambient.rgb + specular.rgb + p3d_Material.emission.rgb;
//    color = specular.rgb;
//    color = vec3(1.);
//    color.r += specular.r * 0.0;
//    fragColor = vec4(color, diffuseColor.a);
//    color = texture(u_BaseColorTex, vertMultiTexCoord0).rgb;
//    color = texture(u_MetallicRoughnessTex, vertMultiTexCoord0).rgb;
//    color = texture(p3d_TextureSelector[0], vertMultiTexCoord0).rgb;
//
//    color = texture(u_NormalTex, vertMultiTexCoord0).rgb;

//    color = texture(p3d_TextureModulate[0], vertMultiTexCoord0).rgb;

//    uniform sampler2D p3d_TextureModulate[]; // default color: (1, 1, 1, 1)
//    color = texture(p3d_Texture0, vertMultiTexCoord0).rgb;
//    color = texture(p3d_Texture1, vertMultiTexCoord0).rgb;
//    color = texture(p3d_Texture2, vertMultiTexCoord0).rgb;
//    color = texture(p3d_Texture3, vertMultiTexCoord0).rgb;
//    color = getCol(3, vertMultiTexCoord0).rgb;

    fragColor = vec4(color, diffuseColor.a);
//    fragColor.g = smoothstep(-30.0, 30.0, vertPosition.x);
//    fragColor.r = 1.0;


}
