/*
====================================================================================================

    Copyright (C) 2020 RRe36

    All Rights Reserved unless otherwise explicitly stated.


    By downloading this you have agreed to the license and terms of use.
    These can be found inside the included license-file
    or here: https://rre36.com/copyright-license

    Violating these terms may be penalized with actions according to the Digital Millennium
    Copyright Act (DMCA), the Information Society Directive and/or similar laws
    depending on your country.

====================================================================================================
*/

#ifdef rtaoSkySample
    /* - */
#endif

#define rtaoSkySampleMult pi

vec3 screenspaceRT_long(vec3 position, vec3 direction, float noise) {
    const uint maxSteps     = rtaoSteps;
    const float stepSize    = (pi * rtaoLength) / float(maxSteps);

    vec3 stepVector         = direction * stepSize;

    vec3 endPosition        = position + stepVector * maxSteps;
    vec3 endScreenPosition  = viewToScreenSpace(endPosition);

    vec2 maxPosXY           = max(abs(endScreenPosition.xy * 2.0 - 1.0), vec2(1.0));
    float stepMult          = min2(vec2(1.0) / maxPosXY);
        stepVector         *= stepMult;

    vec3 samplePos          = position + stepVector / maxSteps / 2.0;
        samplePos          += stepVector * noise;

    for (uint i = 0; i < maxSteps; ++i) {
        vec3 screenPos      = viewToScreenSpace(samplePos);
            samplePos      += stepVector;
        if (saturate(screenPos.xy) != screenPos.xy) break;

        float depthSample   = texelFetch(depthtex0, ivec2(screenPos.xy * viewSize), 0).x;
        float linearSample  = depthLinear(depthSample);
        float currentDepth  = depthLinear(screenPos.z);

        if (linearSample < currentDepth) {
            float dist      = abs(linearSample - currentDepth) / currentDepth;
            if (dist <= 0.2) return vec3(screenPos.xy, depthSample);
        }
    }

    return vec3(1.1);
}

vec3 getRTAO(vec3 viewPos, vec3 viewNormal, float dither, bool hand, float skyOcclusion) {
    //if (hand) return 1.0;

    const uint samples  = rtaoSPP;

    vec3 viewDir        = normalize(viewPos);

    #if (defined rtaoSkySample || !defined DIM)
        vec3 ambient        = vec3(0.0);
    #else
        float ambient       = 0.0;
    #endif

    vec3 upDir  = mat3(gbufferModelView) * vec3(0.0, 1.0, 0.0);

    float noise     = ditherBluenoise();
    float gnoise    = ditherHashNoise();

    for (uint i = 0; i < samples; ++i) {
        vec3 rDir           = sphereMap(fermatsSpiralGoldenN(float(i + 1) * 64.0 + noise * 64.0, float(samples) * 64.0));
            rDir            = mat3(gbufferModelView) * rDir;

        #ifndef DIM
            rDir            = mix(rDir, upDir, 0.33);
        #endif

        if (dot(rDir, viewNormal) < 0.0) rDir = -rDir;

        vec3 worldDir       = mat3(gbufferModelViewInverse) * rDir;
        vec2 sphereCoord    = unprojectSphere(worldDir);
            sphereCoord    *= rcp(skyCaptureResolution);
            sphereCoord.y  += exp2(-SKY_RENDER_LOD) * 2.0;

        vec3 hitPosition    = screenspaceRT_long(viewPos, rDir, gnoise);

        if (hitPosition.z < 1.0) continue;

        #if (defined rtaoSkySample || !defined DIM)
            vec3 fakeBounce     = ((1.0 - expf(-max0(-worldDir.y - 0.005) * pi)) * 0.04 + 0.02) * directLightColor;
        #endif

        #ifdef rtaoSkySample
            ambient += (texture(colortex5, sphereCoord).rgb * rtaoSkySampleMult + fakeBounce) * saturate(dot(viewNormal, rDir));
        #else
            #ifndef DIM
                ambient += (indirectLightCol + fakeBounce) * saturate(dot(viewNormal, rDir));
            #else
                ambient += saturate(dot(viewNormal, rDir));
            #endif
        #endif
    }
    ambient    /= float(samples);
    ambient     = max0(ambient);

    #ifndef DIM
        ambient *= cube(skyOcclusion);
    #endif

    #if (defined rtaoSkySample || !defined DIM)
        return ambient;
    #else
        return indirectLightCol * ambient;
    #endif
}