

#define SIMPLEFOG
#define WATERSTAGE
#include "/lib/taa/res_params.glsl"
#include "/lib/uniforms.glsl"
varying mat3 tbnMatrix;
varying vec4 color;
varying float iswater;
varying vec4 lmtexcoord;
varying vec3 torch;
varying vec3 viewVector;
uniform int isEyeInWater;
varying vec3 normal0;
varying vec3 normal1;

uniform sampler2D texture;

uniform float darknessLightFactor;
uniform float far;
uniform float frameTimeCounter;
uniform float near;

#include "/lib/color_transforms.glsl"
#include "/lib/projections.glsl"
#include "/lib/sky_gradient.glsl"
#include "/lib/light.glsl"
#ifdef WATER_SHADOWS
uniform mat4 shadowModelView;
uniform mat4 shadowProjection;
#include "/lib/shadow_param.glsl"
const vec2 shadowOffsets[6] = vec2[6](vec2(0.5303, 0.5303), vec2(-0.6250, -0.0000), vec2(0.3536, -0.3536),
                                      vec2(-0.0000, 0.3750), vec2(-0.1768, -0.1768), vec2(0.1250, 0.0000));

uniform sampler2DShadow shadow;
vec2 tapLocation(int sampleNumber, int nb, float nbRot, float jitter, float distort)
{
    float alpha = (sampleNumber + jitter) / nb;
    float angle = jitter * TWO_PI + alpha * nbRot * TWO_PI;

    float sin_v, cos_v;

    sin_v = sin(angle);
    cos_v = cos(angle);

    return vec2(cos_v, sin_v) * sqrt(alpha);
}
#endif
#define viewMAD(m, v) (mat3(m) * (v) + (m)[3].xyz)

#define diagonal3(m) vec3((m)[0].x, (m)[1].y, m[2].z)
#define projMAD(m, v) (diagonal3(m) * (v) + (m)[3].xyz)

#include "/lib/water/waterfuncs.glsl"

/* RENDERTARGETS: 1,3 */

void main()
{
    vec4 outcolor = texture2D(texture, lmtexcoord.xy);
    outcolor.rgb *= color.rgb;
    float alpha0 = outcolor.a;
    vec3 normFragpos = normalize(viewVector);
    vec3 normal = normal1;
    vec3 normalWorld = normal0;
    vec3 normalTex = vec3(0.0);
    gl_FragData[1] = vec4(float(iswater > 0.99), 0, 0, 1);

    if (iswater > 0.99)
    {
        const vec3 wcolor = vec3(0.1, 0.4, 0.5);

        alpha0 = 0.1;
        outcolor.rgb = mix(wcolor, color.rgb, 0.25) * 0.5;
        vec3 p3 = (mat3(gbufferModelViewInverse) * viewVector) + gbufferModelViewInverse[3].xyz;
        outcolor.a = 0.75;
        vec3 posxz = p3 + cameraPosition;

        normalTex = waterNormal(posxz.xz - posxz.y, normFragpos) * 2.0 - 1.0;
        normal = normalize(tbnMatrix * normalTex);
        normalWorld = worldToView(normal);
    }

    float diffuseSun = mix(1.0, max(dot(normal, lightPos), 0.0), clamp(outcolor.a + 0.05, 0.0, 1.0)) * lmtexcoord.w;
    // float diffuseSun = max(dot(normal, lightPos), 0.0) * lmtexcoord.w;
    vec3 direct = sunLight;

#ifdef WATER_SHADOWS
    float shading = 1.0;
    if (diffuseSun > 0.001)
    {
        float noise = R2_dither(gl_FragCoord.xy);
        vec3 p3_shadows = (mat3(gbufferModelViewInverse) * viewVector) + gbufferModelViewInverse[3].xyz;

        vec3 ProjShadowPos = mat3(shadowModelView) * p3_shadows + shadowModelView[3].xyz;
        ProjShadowPos = diagonal3(shadowProjection) * ProjShadowPos + shadowProjection[3].xyz;

        float distortFactor = calcDistort(ProjShadowPos.xy);
        ProjShadowPos.xy *= distortFactor;

        if (all(lessThan(abs(ProjShadowPos.xy), (vec2(1.0, 1.0) - 1.5 / shadowMapResolution))) &&
            abs(ProjShadowPos.z) < 6)
        {

            float distortThresh = (sqrt(1.0 - diffuseSun * diffuseSun) / diffuseSun + 0.7) / distortFactor;
            float diffthresh = distortThresh / 6000.0 * max(2048.0 / shadowMapResolution * shaddist / 128.0, 0.95);

            ProjShadowPos = ProjShadowPos * vec3(0.5, 0.5, 0.5 / 6.0) + 0.5;

            shading = 0.0;
            float rdMul = 4.0 / shadowMapResolution;
            for (int i = 0; i < 9; i++)
            {
                vec2 offsetS = tapLocation(i, 9, 2.0, noise, 0.0);

                float weight = 1.0 + (i + noise) * rdMul / 9.0 * shadowMapResolution;
                shading += shadow2D(shadow, vec3(ProjShadowPos + vec3(rdMul * offsetS, -diffthresh * weight))).x / 9.0;
            }
        }
    }
    diffuseSun *= clamp(shading, 0.5, 1.0);
    direct *= shading;
#endif

    vec3 ambient = calcAmbientLight(normal, lmtexcoord.zw, atmosphereUp, diffuseSun, torch) * color.a;
    outcolor.rgb = ambient * toLinear(outcolor.rgb);

    if (iswater == 0.0)
    {
        gl_FragData[0] = outcolor;
        return;
    }

    float fresnel =
        fresnel0(normFragpos, normalWorld, mix(1.333, 1.0, float(isEyeInWater)), mix(1.0, 1.333, float(isEyeInWater)));
    float sunSpec = min(speculars(normalWorld, normFragpos, sunVec, 0.003, 0.02), 16.0) * lmtexcoord.w * (1.0 - rainStrength);

    vec3 reflected = reflections(direct, fresnel, sunSpec, lmtexcoord.w, normalWorld,
                                 mix(1.0, -1.0, float(isEyeInWater)), viewVector);

    float effectiveAlpha = outcolor.a * (1.0 - fresnel) + fresnel;

    vec3 baseColorCorrected = outcolor.rgb * alpha0 * (1.0 - fresnel);

    outcolor = vec4((baseColorCorrected + reflected) / effectiveAlpha, effectiveAlpha);
    // outcolor.rgb = normalTex;
    // outcolor.rgb = vec3(ambient);
    // outcolor.a = 1;
    // outcolor.a = 1;

    gl_FragData[0] = outcolor;
}
