#version 430 core

in vec2 vUV;

uniform vec2 uUVMin;
uniform vec2 uUVMax;

in vec2 vFragScreenPos;
out vec4 FragColor;

uniform sampler2D uTex;
uniform sampler2D uNormalMap;

uniform float uRotation;
uniform float uBrightness;
uniform float uSaturation;
uniform float uGamma;

uniform int uLightCount;
uniform int uClusterWidth;
uniform int uClusterHeight;
uniform int uClusterCols;
uniform int uMaxLightsPerCluster;



#define MAX_LIGHTS 512
uniform vec2  uLightPos[MAX_LIGHTS];
uniform vec3  uLightColor[MAX_LIGHTS];
uniform float uLightIntensity[MAX_LIGHTS];
uniform float uLightRadius[MAX_LIGHTS];

layout(std430, binding = 1) readonly buffer ClusterLightBuffer {
    int clusterLightIndices[];
};

void main()
{
    
    vec2 rotatedUV = mix(uUVMin, uUVMax, vec2(vUV.y, 1.0 - vUV.x));

    vec4 texColor = texture(uTex, rotatedUV);
    if (texColor.a < 0.1)
        discard;

    vec3 n = texture(uNormalMap, rotatedUV).rgb * 2.0 - 1.0;
    n.y = -n.y;

    float c = cos(uRotation);
    float s = sin(uRotation);
    mat2 rot = mat2(c, -s, s, c);
    n.xy = rot * n.xy;

    vec3 normal = normalize(n);
    vec3 finalLight = vec3(0.0);

    int cx = int(vFragScreenPos.x) / uClusterWidth;
    int cy = int(vFragScreenPos.y) / uClusterHeight;
    int clusterIndex = cy * uClusterCols + cx;

    for (int i = 0; i < uMaxLightsPerCluster; ++i) {
        int lightIndex = clusterLightIndices[clusterIndex * uMaxLightsPerCluster + i];
        if (lightIndex < 0 || lightIndex >= uLightCount)
            break;

        vec2 lightVec = uLightPos[lightIndex] - vFragScreenPos;
        float dist = length(lightVec);
        if (dist < uLightRadius[lightIndex]) {
            vec2 lightDir2D = normalize(lightVec);
            vec3 lightDir = normalize(vec3(lightDir2D, 1.0));
            float attenuation = smoothstep(uLightRadius[lightIndex], 0.0, dist);
            float diff = max(dot(normal, lightDir), 0.0);
            vec3 light = uLightColor[lightIndex] * diff * attenuation * uLightIntensity[lightIndex];
            finalLight += light;
        }
    }

    vec3 result = texColor.rgb * finalLight;

    result *= uBrightness;

    float gray = dot(result, vec3(0.299, 0.587, 0.114));
    result = mix(vec3(gray), result, uSaturation);

    result = pow(result, vec3(1.0 / uGamma));
    FragColor = vec4(clamp(result, 0.0, 1.0), texColor.a);
}
