/*
--------------------------------------------------------------------------------
                   ___
                  /  /
                 /  /
        ________/  /__________ _______
       /  _____/  /_______   //  ____/
      /  /	  /  /_______/  //  /
     /  /____/  //  _______//  /
    /__________//_____________/

    Screen Space Reflections (SSR) Module
    
    Implements SSR and SSGI using the ray tracer

--------------------------------------------------------------------------------
*/

//============================================================================//
// SSR/SSGI CONFIGURATION
//============================================================================//

#ifndef SSR_ENABLED
    #define SSR_ENABLED 1           // [0 1] Enable Screen Space Reflections
#endif

#ifndef SSGI_ENABLED
    #define SSGI_ENABLED 1          // [0 1] Enable Screen Space Global Illumination
#endif

#ifndef ROUGH_REFLECTIONS
    #define ROUGH_REFLECTIONS 1     // [0 1] Enable rough/blurred reflections
#endif

#ifndef SSR_SKY_FALLBACK
    #define SSR_SKY_FALLBACK 1      // [0 1] Use sky color when ray misses
#endif

//============================================================================//
// INCLUDES (required)
//============================================================================//

// Make sure RayTracer.glsl is included before this file
// #include "RayTracer.glsl"

//============================================================================//
// SSR CALCULATION
//============================================================================//

/**
 * Calculate Screen Space Reflections
 * 
 * @param screenPos     Current screen position with depth
 * @param viewPos       View-space position
 * @param normal        View-space normal
 * @param albedo        Surface albedo color
 * @param smoothness    Surface smoothness [0-1]
 * @param metallic      Surface metallic value [0-1]
 * @param dither        Random value for temporal stability
 * @param sceneColor    Current scene color at this pixel
 * 
 * @return vec3         Color with SSR applied
 */
vec3 calculateSSR(
    in vec3 screenPos,
    in vec3 viewPos, 
    in vec3 normal,
    in vec3 albedo,
    in float smoothness,
    in float metallic,
    in vec2 dither,
    in vec3 sceneColor
) {
    #if SSR_ENABLED == 0
        return sceneColor;
    #endif
    
    // Early exit if smoothness is too low
    if (smoothness < 0.005) return sceneColor;
    
    // Apply rough reflections by perturbing the normal
    #ifdef ROUGH_REFLECTIONS
        vec3 noiseUnitVector = generateUnitVector(dither);
        normal = generateCosineVector(normal, noiseUnitVector * (sqr(1.0 - smoothness) * 0.5));
    #endif
    
    // Normalize view position
    vec3 nViewPos = fastNormalize(viewPos);
    
    // Calculate reflected view direction
    // reflect(I, N) = I - 2.0 * dot(N, I) * N
    float NV = dot(normal, -nViewPos);
    vec3 reflectViewDir = nViewPos + (2.0 * NV) * normal;
    
    // Perform ray tracing
    vec3 SSRCoord = rayTraceScene(screenPos, viewPos, reflectViewDir, dither.x);
    
    // Get reflection color
    vec3 reflectCol = vec3(0.0);
    
    if (SSRCoord.z > 0.5) {
        // Hit found - sample scene color at hit location
        reflectCol = textureLod(colortex4, SSRCoord.xy, 0).rgb;
    } 
    #if SSR_SKY_FALLBACK == 1
    else {
        // No hit - use sky color as fallback
        vec3 worldReflectDir = mat3(gbufferModelViewInverse) * reflectViewDir;
        reflectCol = getSkyColor(worldReflectDir);
    }
    #endif
    
    // Calculate Fresnel using Schlick's approximation
    // F = F0 + (1 - F0) * (1 - NV)^5
    // Optimized version for PBR
    float smoothCosTheta = NV > 0.0 ? exp2(-9.28 * NV) * smoothness : smoothness;
    float oneMinusCosTheta = smoothness - smoothCosTheta;
    
    // Apply reflection based on metallic value
    if (metallic <= 0.9) {
        // Dielectric - use simple Fresnel
        return sceneColor + reflectCol * (smoothCosTheta + metallic * oneMinusCosTheta);
    } else {
        // Metallic - use albedo as F0
        return sceneColor + reflectCol * (smoothCosTheta + albedo * oneMinusCosTheta);
    }
}

//============================================================================//
// SSGI CALCULATION
//============================================================================//

/**
 * Calculate Screen Space Global Illumination
 * 
 * @param screenPos     Current screen position with depth
 * @param viewPos       View-space position
 * @param normal        View-space normal
 * @param albedo        Surface albedo color
 * @param dither        Random value for temporal stability
 * @param sceneColor    Current scene color at this pixel
 * 
 * @return vec3         Color with SSGI applied
 */
vec3 calculateSSGI(
    in vec3 screenPos,
    in vec3 viewPos,
    in vec3 normal,
    in vec3 albedo,
    in vec2 dither,
    in vec3 sceneColor
) {
    #if SSGI_ENABLED == 0
        return sceneColor;
    #endif
    
    // Generate random cosine-weighted hemisphere direction
    vec3 noiseUnitVector = generateUnitVector(dither);
    vec3 giDir = generateCosineVector(normal, noiseUnitVector);
    
    // Trace ray in GI direction
    vec3 SSGICoord = rayTraceScene(screenPos, viewPos, giDir, dither.x);
    
    // If hit found, add indirect lighting
    if (SSGICoord.z > 0.5) {
        vec3 giColor = textureLod(colortex4, SSGICoord.xy, 0).rgb;
        return sceneColor + albedo * giColor * 0.5; // Scale GI contribution
    }
    
    return sceneColor;
}

//============================================================================//
// COMBINED SSR + SSGI
//============================================================================//

/**
 * Calculate both SSR and SSGI in one pass
 * 
 * @param screenPos     Current screen position with depth
 * @param viewPos       View-space position
 * @param normal        View-space normal
 * @param albedo        Surface albedo color
 * @param smoothness    Surface smoothness [0-1]
 * @param metallic      Surface metallic value [0-1]
 * @param dither        Random values for temporal stability
 * @param sceneColor    Current scene color at this pixel
 * 
 * @return vec3         Color with SSR and SSGI applied
 */
vec3 calculateSSR_SSGI(
    in vec3 screenPos,
    in vec3 viewPos,
    in vec3 normal,
    in vec3 albedo,
    in float smoothness,
    in float metallic,
    in vec3 dither,
    in vec3 sceneColor
) {
    vec3 result = sceneColor;
    
    // Apply SSGI first (diffuse indirect)
    #if SSGI_ENABLED == 1
        result = calculateSSGI(screenPos, viewPos, normal, albedo, dither.xy, result);
    #endif
    
    // Then apply SSR (specular indirect)
    #if SSR_ENABLED == 1
        result = calculateSSR(screenPos, viewPos, normal, albedo, smoothness, metallic, dither.xy, result);
    #endif
    
    return result;
}

//============================================================================//
// EXAMPLE USAGE IN DEFERRED SHADING
//============================================================================//

/*

// In your deferred shading pass:

vec3 complexShadingDeferred(
    in vec3 sceneCol, 
    in vec3 screenPos, 
    in vec3 viewPos, 
    in vec3 normal, 
    in vec3 albedo, 
    in vec3 dither, 
    in float metallic, 
    in float smoothness
) {
    // ... other shading calculations ...
    
    // Apply SSR and SSGI
    sceneCol = calculateSSR_SSGI(
        screenPos,
        viewPos,
        normal,
        albedo,
        smoothness,
        metallic,
        dither,
        sceneCol
    );
    
    return sceneCol;
}

*/
