/* 
NightBloom Shader by SillyyLily 
*/ 

//Settings//
#include "/lib/settings.glsl"

//Fragment Shader///////////////////////////////////////////////////////////////////////////////////
#ifdef FSH

//Varyings//
varying float mat;

varying vec2 texCoord;

#ifdef WATER_CAUSTICS
varying vec3 worldPos;
#endif

varying vec4 color;

//Uniforms//
uniform int blockEntityId;

uniform sampler2D tex;

#ifdef WATER_CAUSTICS
uniform sampler2D noisetex;
uniform vec3 cameraPosition;
uniform float frameTimeCounter;
uniform vec4 glColor;
#endif

//Common Variables//
#ifdef WATER_CAUSTICS
#ifdef WORLD_TIME_ANIMATION
float frametime = float(worldTime) * 0.05 * ANIMATION_SPEED;
#else
float frametime = frameTimeCounter * ANIMATION_SPEED;
#endif

float GetLuminance(vec3 color) {
    return dot(color, vec3(0.299, 0.587, 0.114));
}

float max0(float x) {
    return max(x, 0.0);
}

float min1(float x) {
    return min(x, 1.0);
}

float Bayer64(vec2 coord) {
    coord = mod(coord, 8.0);
    return fract(dot(coord, vec2(0.5, 0.5)));
}

void applyWaterCaustics(inout vec4 surfaceColor, vec3 worldPosition) {
    #if defined WATER_CAUSTICS && defined OVERWORLD
        vec3 scaledWorldPos = worldPosition * 0.5;
        float causticIntensity = 0.0;
        float causticStrength = 0.6;
        
        vec2 waveMovement = vec2(frametime) * 0.3;
        float heightOffset = scaledWorldPos.y * 0.2;

        if (causticStrength > 0.01) {
            float scaleFactor = 1.0 / 500.0;
            float amplitude = 1.0;
            float totalWeight = 0.0;

            for(int i = 0; i < 8; i++) {
                float waveDirection = mod(i, 2) * 2.0 - 1.0;
                vec2 sampleCoord = scaledWorldPos.xz + waveMovement * waveDirection - heightOffset;
                if (i < 7) {
                    causticIntensity += texture2D(noisetex, sampleCoord * scaleFactor).r * amplitude;
                } else {
                    causticIntensity += texture2D(noisetex, sampleCoord * scaleFactor * 0.125).r * amplitude * 10.0;
                    causticIntensity = -causticIntensity;
                    float intensityBoost = 1.0 + 0.125 * -causticIntensity;
                    intensityBoost *= intensityBoost;
                    intensityBoost *= intensityBoost;
                    causticIntensity *= intensityBoost;
                }

                if (i == 0) causticIntensity = -causticIntensity;

                totalWeight += amplitude;
                scaleFactor *= 1.50;
                amplitude *= 0.60;
            }
            causticIntensity *= causticStrength / totalWeight;
        }
        float causticEffect = 1.1 + causticIntensity;
        causticEffect = pow(causticEffect, 8.0);
        surfaceColor.rgb = mix(surfaceColor.rgb, vec3(0.0, 0.6, 0.8), causticEffect * 1.0);
        surfaceColor.rgb *= vec3(0.0, 0.4, 0.4);
    #endif
}
#endif



//Program//
void main() {
    #if MC_VERSION >= 11300
    if (blockEntityId == 10205) discard;
    #endif

    vec4 albedo = texture2D(tex, texCoord.xy);
    albedo.rgb *= color.rgb;

    float premult = float(mat > 0.98 && mat < 1.02);
    float water = float(mat > -0.02 && mat < 0.02);
    float disable = float(mat > 3.98 && mat < 4.02);
    if (albedo.a < 0.01 || disable > 0.5) discard;

    if (water > 0.5) {
        #if !defined WATER_CAUSTICS
            discard;
        #else        
            #ifdef WATER_CAUSTICS
                applyWaterCaustics(albedo, worldPos);
            #endif
        #endif
    } else {
        
    }

    #ifdef SHADOW_COLOR
    if (water > 0.5) {
        // Skip shadow color for water blocks
    } else {
        albedo.rgb = mix(vec3(1.0), albedo.rgb, 1.0 - pow(1.0 - albedo.a, 1.5));
        albedo.rgb *= 1.0 - pow(albedo.a, 96.0);
    }
    #else
    if ((premult > 0.5 && albedo.a < 0.98)) albedo.a = 0.0;
    #endif

    gl_FragData[0] = albedo;
}

#endif

//Vertex Shader/////////////////////////////////////////////////////////////////////////////////////
#ifdef VSH

//Varyings//
varying float mat;

varying vec2 texCoord;

#ifdef WATER_CAUSTICS
varying vec3 worldPos;
#endif

varying vec4 color;

//Uniforms//
uniform int worldTime;

uniform float frameTimeCounter;

uniform vec3 cameraPosition;

uniform mat4 gbufferModelView, gbufferModelViewInverse;
uniform mat4 shadowProjection, shadowProjectionInverse;
uniform mat4 shadowModelView, shadowModelViewInverse;

//Attributes//
attribute vec4 mc_Entity;
attribute vec4 mc_midTexCoord;

//Common Variables//
#ifdef WORLD_TIME_ANIMATION
float frametime = float(worldTime) * 0.05 * ANIMATION_SPEED;
#else
float frametime = frameTimeCounter * ANIMATION_SPEED;
#endif

//Includes//
#include "/lib/vertex/waving.glsl"

#ifdef WORLD_CURVATURE
#include "/lib/vertex/worldCurvature.glsl"
#endif

//Program//
void main() {
    texCoord = gl_MultiTexCoord0.xy;
    vec2 lmCoord = (gl_TextureMatrix[1] * gl_MultiTexCoord1).xy;
    lmCoord = clamp((lmCoord - 0.03125) * 1.06667, vec2(0.0), vec2(0.9333, 1.0));

    int blockID = int(mod(max(mc_Entity.x - 10000, 0), 10000));

    color = gl_Color;
    
    mat = 0;
    #ifdef PLANT_SHADOWS
    // Non-leaf foliage (10304-10313, 10315-10319) casts shadows
    if (blockID >= 304 && blockID <= 313 || blockID >= 315 && blockID <= 319) mat = 1;
    #endif
    // Water
    if (blockID == 0) mat = 2;
    // Leaves
    if (blockID == 314) mat = 3;
    
    vec4 position = shadowModelViewInverse * shadowProjectionInverse * ftransform();

    #ifdef WATER_CAUSTICS
    if (blockID == 0) mat = 0;
    worldPos = position.xyz + cameraPosition.xyz;
    #endif
    
    float istopv = gl_MultiTexCoord0.t < mc_midTexCoord.t ? 1.0 : 0.0;
    position.xyz = getWavingBlocks(position.xyz, istopv, lmCoord.y);

    #ifdef WORLD_CURVATURE
    position.y -= WorldCurvature(position.xz);
    #endif
    
    gl_Position = shadowProjection * shadowModelView * position;

    float dist = sqrt(gl_Position.x * gl_Position.x + gl_Position.y * gl_Position.y);
    float distortFactor = dist * shadowMapBias + (1.0 - shadowMapBias);
    
    gl_Position.xy *= 1.0 / distortFactor;
    gl_Position.z = gl_Position.z * 0.2;
}

#endif