

#include "/lib/basefiles.glsl"

varying vec2 texcoord;

#ifdef VSH

    void main() {
        gl_Position = ftransform();
        texcoord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy;
    }

#endif

#ifdef FSH

    #include "/lib/sky.glsl"
    #include "/lib/cloud.glsl"
    #include "/lib/stars.glsl"
    #include "/lib/end.glsl"

    /* RENDERTARGETS: 0,4 */
    layout(location = 0) out vec4 color0;
    layout(location = 1) out vec4 color4;

    vec3 sampleReflectionEnv(vec3 worldReflectDir, float lmY, vec3 skylight) {
        vec3 col;
        #ifdef DIM_END
            col = vec3(0.0);
            col += render_stars(worldReflectDir);
            _vcRender(col, worldReflectDir, blueNoise, 1e6);
        #else
            col = sampleSkybox(worldReflectDir);
            vec3 trans = TransToAtmos(cameraLocation, worldReflectDir);
            col = drawSun(col, worldReflectDir, trans);
            #ifdef REFLECTED_CLOUD
                vec4 cloudHigh = RenderCloudHigh(cameraLocation, worldReflectDir, lightDir, lightLuminance);
                col = col * cloudHigh.a + cloudHigh.rgb;

                vec4 cloud2D = RenderCloud2D(cameraLocation, worldReflectDir, lightDir, lightLuminance);
                col = col * cloud2D.a + cloud2D.rgb;

                vec4 cloud3D = RenderCloud(cameraLocation, worldReflectDir, lightDir, lightLuminance, skylight);
                col = col * cloud3D.a + cloud3D.rgb;
            #endif
            col *= lmY;
        #endif
        return col;
    }

    void main() {
        vec3 upskylight = texelFetch(colortex5, ivec2(viewSize - 1.0) - ivec2(6, 0), 0).rgb;

        vec4 baseCol0 = texelFetch(colortex0, texelUV, 0);
        vec4 baseCol4 = texelFetch(colortex4, texelUV, 0);

        color0 = baseCol0;
        color4 = baseCol4;

        float depth0 = texture(depthtex0, texcoord).r;
        float depth1 = texture(depthtex1, texcoord).r;

        if(depth0 >= 1.0 && depth1 >= 1.0) return;

        bool isTranslucent = depth0 < depth1 - 1e-6;
        float depth = isTranslucent ? depth0 : depth1;
        if(depth >= 1.0) return;

        vec4 data1 = texelFetch(colortex1, texelUV, 0);
        vec4 data2 = texelFetch(colortex2, texelUV, 0);
        vec4 data3 = texelFetch(colortex3, texelUV, 0);

        float blockID = data1.b * 10000.0;
        if(isTranslucent && blockID < -0.5) return;

        #ifndef SPECULAR_REFLECTION
            if(!isTranslucent) return;
        #endif

        float smoothness = data3.r;
        if(!isTranslucent && smoothness < 1e-3) return;

        vec3 viewPos = GetViewPosition(texcoord, depth);
        vec3 worldPos = matrixMultiply(gbufferModelViewInverse, vec4(viewPos, 1.0));
        vec3 worldDir = normalize(mat3(gbufferModelViewInverse) * viewPos);
        vec3 worldNormal = normalDecode(data2.zw);
        vec3 worldOriNormal = normalDecode(data2.xy);

        vec3 worldReflectDir = reflect(worldDir, worldNormal);
        if(dot(worldReflectDir, worldOriNormal) < 0.0) {
            worldReflectDir = reflect(worldReflectDir, worldOriNormal);
        }
        vec3 viewReflectDir = normalize(mat3(gbufferModelView) * worldReflectDir);

        vec2 rayTracingPos = vec2(0.0);
        bool rayTracingIsHit = false;
        screenRayTracingDDA(viewPos, viewReflectDir, rayTracingPos, rayTracingIsHit);

        if(rayTracingIsHit && !isTranslucent) {
            float hitBlockID = texture(colortex1, rayTracingPos).b * 10000.0;
            if(abs(hitBlockID - 9999.0) < 0.5) rayTracingIsHit = false;
        }

        float lmY = remap(data1.g, 0.5 / 16.0, 15.5 / 16.0, 0.0, 1.0);

        vec3 reflCol;
        if(rayTracingIsHit) {
            vec2 prevUV = getPreCoord(rayTracingPos.xy);
            reflCol = texture(colortex7, outScreen(prevUV) ? rayTracingPos.xy : prevUV).rgb;
        } else {
            reflCol = sampleReflectionEnv(worldReflectDir, lmY, upskylight);
        }

        float NdotV = max0(dot(worldNormal, -worldDir));

        if(isTranslucent) {
            float F0 = data3.g;
            float fresnel = fresnelSchlick(NdotV, F0);

            if(abs(blockID - 79.0) < 0.5) {
                fresnel = max(fresnel, 0.97);
            }

            color0 = vec4(mix(baseCol0.rgb, reflCol, fresnel), baseCol0.a);
        } else {
            vec3 albedo = GammaToLinear(texelFetch(colortex0, texelUV, 0).rgb);
            float metallic = data3.g;
            vec3 F0v = mix(vec3(0.04), albedo, metallic);
            float fresnel = fresnelSchlick(NdotV, 0.04);
            vec3 specF = mix(vec3(fresnel), F0v, metallic);
            vec3 specContribution = reflCol * specF * pow2(smoothness);

            vec3 outc = baseCol0.rgb + specContribution;

            bool isGrass = abs(blockID - 31.0) < 0.5 || abs(blockID - 32.0) < 0.5 || abs(blockID - 33.0) < 0.5;
            if(rainStrength > 1e-6 && lmY > 1e-6 && !isGrass) {
                float wetFactor = pow2(rainStrength) * lmY;
                float puddleMask = smoothstep(0.7, 0.92, smoothness);
                float wetFresnel = fresnelSchlick(NdotV, 0.02);
                outc = mix(outc, reflCol, wetFresnel * wetFactor * 0.4);
                if(puddleMask > 0.001) {
                    float pf = fresnelSchlick(NdotV, 0.02);
                    outc = mix(outc, reflCol, pf * puddleMask);
                }
            }
            color0 = vec4(outc, baseCol0.a);
        }
    }

#endif