#include "/lib/config.glsl"
#include "/lib/color_utils.glsl"

// HDR firefly radiance is evaluated in a true half-resolution colortex2.
// The native composite reconstructs it into the original post chain.
uniform sampler2D colortex1;
uniform sampler2D colortex9;
uniform sampler2D depthtex0;
uniform sampler2D depthtex2;
uniform float far;
uniform float near;
uniform float rainStrength;
uniform int isEyeInWater;
uniform ivec2 eyeBrightnessSmooth;
uniform mat4 gbufferProjectionInverse;
uniform mat4 gbufferModelViewInverse;
uniform vec3 cameraPosition;

#if defined DISTANT_RENDER_MOD && defined DISTANT_HORIZONS
    uniform sampler2D dhDepthTex0;
    uniform float dhNearPlane;
    uniform float dhFarPlane;
#endif

varying vec2 texcoord;

#include "/lib/depth.glsl"
#if defined DISTANT_RENDER_MOD && defined DISTANT_HORIZONS
    #include "/lib/depth_dh.glsl"
#endif
#include "/lib/fireflies.glsl"

float sample_halfres_fantasy_habitat(vec2 sampleCoord) {
    vec4 habitatData = texture2D(
        colortex9, clamp(sampleCoord, vec2(0.0), vec2(1.0)));
    if (habitatData.z < 0.49) {
        return 0.0;
    }
    return clamp((habitatData.z - 0.5) / 0.49, 0.0, 1.0);
}

void main() {
    vec3 fireflyLighting = vec3(0.0);

    #if PROFILE_QUALITY == 1 && defined FANTASY_LIFE_SYSTEM && FANTASY_FIREFLIES > 0
        float nightAmount = day_blend_float(0.0, 0.0, 1.0);
        if (isEyeInWater == 0 && nightAmount > 0.01) {
            float depth = texture2DLod(depthtex0, texcoord, 0.0).r;
            float linearDepth = ld(depth);
            #if defined DISTANT_RENDER_MOD && defined DISTANT_HORIZONS
                float dhDepth = texture2DLod(
                    dhDepthTex0, texcoord, 0.0).r;
                bool isSky = linearDepth > 0.9999
                    && ld_dh(dhDepth) > 0.9999;
            #else
                bool isSky = linearDepth > 0.9999;
            #endif

            vec4 sceneViewHomogeneous = gbufferProjectionInverse
                * vec4(texcoord * 2.0 - 1.0,
                    depth * 2.0 - 1.0, 1.0);
            vec3 sceneViewPosition = sceneViewHomogeneous.xyz
                / max(sceneViewHomogeneous.w, 0.00001);
            vec3 viewRay = normalize(sceneViewPosition);
            vec3 worldRay = normalize(
                (gbufferModelViewInverse * vec4(viewRay, 0.0)).xyz);

            // The original ground reconstruction is defined only for this
            // horizon/canopy cone. Avoid ungrounded cells above it.
            if (!isSky || worldRay.y < 0.52) {
                float sceneDistance = isSky
                    ? min(far, 48.0) : length(sceneViewPosition);
                vec3 visibleSurfaceWorld = cameraPosition
                    + worldRay * sceneDistance;
                float skyLight = clamp(
                    float(eyeBrightnessSmooth.y) / 240.0, 0.0, 1.0);
                float fireflyGroundY = visibleSurfaceWorld.y;
                float projectedGroundHabitat = 0.0;

                if (isSky && worldRay.y < 0.52) {
                    #if PROFILE_QUALITY == 1
                        const int fireflyGroundSteps = 4;
                    #else
                        const int fireflyGroundSteps = 7;
                    #endif
                    for (int groundStep = 1;
                            groundStep <= fireflyGroundSteps;
                            groundStep++) {
                        float scanAmount = float(groundStep)
                            / float(fireflyGroundSteps);
                        vec2 groundCoord = vec2(
                            texcoord.x,
                            mix(texcoord.y, 0.055, scanAmount));
                        float groundDepth = texture2DLod(
                            depthtex2, groundCoord, 0.0).x;
                        if (ld(groundDepth) < 0.9999) {
                            vec4 groundViewHomogeneous =
                                gbufferProjectionInverse * vec4(
                                    groundCoord * 2.0 - 1.0,
                                    groundDepth * 2.0 - 1.0,
                                    1.0);
                            vec3 groundViewPosition =
                                groundViewHomogeneous.xyz
                                / max(groundViewHomogeneous.w, 0.00001);
                            vec3 groundRelativeWorld =
                                mat3(gbufferModelViewInverse)
                                * groundViewPosition;
                            fireflyGroundY = cameraPosition.y
                                + groundRelativeWorld.y;
                            projectedGroundHabitat = max(
                                projectedGroundHabitat,
                                sample_halfres_fantasy_habitat(
                                    groundCoord));
                        }
                    }
                }

                vec3 sceneColor = max(
                    texture2DLod(colortex1, texcoord, 0.0).rgb,
                    vec3(0.0));
                float greenHabitat = clamp(
                    sceneColor.g - max(sceneColor.r, sceneColor.b) * 0.62,
                    0.0, 1.0);
                float habitatPeak = max(
                    max(sceneColor.r, sceneColor.g), sceneColor.b);
                float habitatLow = min(
                    min(sceneColor.r, sceneColor.g), sceneColor.b);
                float flowerHabitat = clamp(
                    (habitatPeak - habitatLow) * 0.42, 0.0, 0.35);
                float horizonHabitat = 1.0
                    - smoothstep(0.16, 0.56, worldRay.y);

                float materialHabitat =
                    sample_halfres_fantasy_habitat(texcoord);
                vec2 habitatPixel = vec2(
                    1.0 / viewWidth, 1.0 / viewHeight) * 13.0;
                float nearbyMaterialHabitat = max(
                    max(sample_halfres_fantasy_habitat(
                            texcoord + vec2(habitatPixel.x, 0.0)),
                        sample_halfres_fantasy_habitat(
                            texcoord - vec2(habitatPixel.x, 0.0))),
                    max(sample_halfres_fantasy_habitat(
                            texcoord + vec2(0.0, habitatPixel.y)),
                        sample_halfres_fantasy_habitat(
                            texcoord - vec2(0.0, habitatPixel.y))));

                float orbitHabitat = max(
                    materialHabitat, nearbyMaterialHabitat * 0.94);
                float releaseHabitat = max(
                    materialHabitat, nearbyMaterialHabitat);
                float releaseAmount = smoothstep(
                    0.82, 0.98, releaseHabitat);
                float habitatAmount = isSky
                    ? clamp(0.25 * horizonHabitat
                        + nearbyMaterialHabitat * 0.72
                        + projectedGroundHabitat * 0.68,
                        0.0, 1.0)
                    : clamp(0.35 + greenHabitat * 0.40
                        + flowerHabitat * 0.30
                        + orbitHabitat * 0.85,
                        0.0, 1.0);

                float reactiveMask;
                fireflyLighting = render_fantasy_fireflies(
                    cameraPosition,
                    worldRay,
                    sceneDistance,
                    nightAmount,
                    skyLight,
                    rainStrength,
                    habitatAmount,
                    releaseAmount,
                    fireflyGroundY,
                    1.0,
                    frameTimeCounter,
                    reactiveMask);
            }
        }
    #endif

    /* DRAWBUFFERS:2 */
    gl_FragData[0] = vec4(fireflyLighting, 1.0);
}
