/*
  Screen-Space Global Illumination (SSGI)
  Traces rays in screen space to gather indirect lighting from nearby surfaces.
  Uses cosine-weighted hemisphere sampling with temporal accumulation.
*/

#ifndef SSGI_GLSL
#define SSGI_GLSL

#if SHADOW_QUALITY >= 2
#define SSGI_RAYS         4
#elif SHADOW_QUALITY >= 3
#define SSGI_RAYS         6
#else
#define SSGI_RAYS         4
#endif

#define SSGI_STEPS        8
#define SSGI_RADIUS       2.0
#define SSGI_INTENSITY    0.8

// Cosine-weighted hemisphere sample directions (2D, projected)
vec2 ssgiDirections[8] = vec2[8](
    vec2( 1.0,  0.0),
    vec2(-1.0,  0.0),
    vec2( 0.0,  1.0),
    vec2( 0.0, -1.0),
    vec2( 0.707,  0.707),
    vec2(-0.707,  0.707),
    vec2( 0.707, -0.707),
    vec2(-0.707, -0.707)
);

vec3 GetSSGI(vec3 viewPos, vec3 normal, float depth, float dither) {
    vec3 gi = vec3(0.0);
    float linearDepth = GetLinearDepth(depth);

    if (linearDepth > 0.999 || depth < AO_HAND_DEPTH_THRESHOLD) return vec3(0.0);

    // Screen-space normal for hemisphere orientation
    vec3 viewNormal = normalize(normal);

    float fovScale = gbufferProjection[1][1] / AO_FOV_REFERENCE;
    float distScale = max(linearDepth * (far - near) + near, AO_MIN_DIST);
    float radius = SSGI_RADIUS * fovScale / distScale;

    // Rotate sample pattern with temporal noise
    float rotAngle = dither * 6.283185;
    float cosR = cos(rotAngle);
    float sinR = sin(rotAngle);

    float totalWeight = 0.0;

    for (int i = 0; i < SSGI_RAYS; i++) {
        vec2 dir = ssgiDirections[i];
        // Apply rotation
        vec2 rotDir = vec2(dir.x * cosR - dir.y * sinR,
                           dir.x * sinR + dir.y * cosR);

        // March along this direction in screen space
        vec2 stepOffset = rotDir * radius / float(SSGI_STEPS);

        for (int j = 1; j <= SSGI_STEPS; j++) {
            vec2 sampleCoord = texCoord + stepOffset * float(j);

            // Bounds check
            if (sampleCoord.x < 0.0 || sampleCoord.x > 1.0 ||
                sampleCoord.y < 0.0 || sampleCoord.y > 1.0) break;

            float sampleDepth = texture2D(depthtex0, sampleCoord).r;
            float sampleLinear = GetLinearDepth(sampleDepth);

            // Check if sample is in front (closer) and within reasonable range
            float depthDiff = linearDepth - sampleLinear;

            if (depthDiff > 0.0001 && depthDiff < 0.05) {
                // This surface is occluding us - gather its color as indirect light
                vec3 sampleColor = texture2D(colortex0, sampleCoord).rgb;
                #if ALPHA_BLEND == 0
                sampleColor *= sampleColor; // undo sqrt encoding
                #endif

                // Weight by depth proximity and angular factor
                float weight = 1.0 - float(j) / float(SSGI_STEPS + 1);
                weight *= 1.0 - depthDiff / 0.05;

                gi += sampleColor * weight;
                totalWeight += weight;
                break; // first hit per ray
            }
        }
    }

    if (totalWeight > 0.001) {
        gi /= totalWeight;
    }

    gi *= SSGI_INTENSITY / float(SSGI_RAYS);

    return gi;
}

#endif
