// Fork of "Water Droplets" by Marrrk. https://shadertoy.com/view/4sBcDh
// 2023-04-30 17:03:42

#define GET 2 // 0 - Height, 1 - Normal, 2 - Textured

const int maxDroplets = 10;

const float dropletExpandSpeed = 1.5;
const float dropletHeightFactor = 1.;
const float dropletRipple = 80.0;
const float PI = 3.141;

float getDropletHeight(vec2 uv)
{
    float time = (iTime + 1245.6789) * 0.5;
    vec2 ddxy = 1.0 / iChannelResolution[0].xy;
    float height = 0.0;
    for (int i = 0; i < maxDroplets; ++i)
    {
        float decayRate = 0.323 + 2.0 * texture(iChannel0, vec2(float(i) * ddxy.x, 0.237)).x;
        float dropletStrength = texture(iChannel0, vec2(float(i) * ddxy.x, 0)).x;
        float dropletStrengthBias = 0.1 + 0.2 * texture(iChannel0, vec2(float(i) * ddxy.x, 0.345)).x;
        float dropFraction = time / decayRate;
        float dropIndex = floor(dropFraction);
        dropFraction = fract(dropFraction);

        float dropletX = texture(iChannel0, vec2(float(i) * ddxy.x + dropIndex * 0.1, dropIndex)).x;
        float dropletY = texture(iChannel0, vec2(float(i) * ddxy.y + dropIndex * 0.1, dropIndex)).y;
        vec2 dropletPosition;

        //if (iMouse.z > 0. || iMouse.w > 0.)
        //{
        //    dropletPosition = iMouse.xy / iResolution.xy - .5;
        //}
        //else
        //{
        //    dropletPosition = (vec2(dropletX, dropletY) * 2.0 - 1.0);
        //}
        
        dropletPosition = (vec2(dropletX, dropletY) * 2.0 - 1.0);

        float ringRadius = dropletExpandSpeed * dropFraction * dropletStrength - dropletStrengthBias;
        float distanceToDroplet = distance(uv, dropletPosition);
        float distanceToEdge = max(0.0, ringRadius - distanceToDroplet) / ringRadius;

        float dropletHeight = distanceToDroplet > ringRadius ? 0.0 : distanceToDroplet;
        dropletHeight = cos(PI + (dropletHeight - ringRadius) * dropletRipple * dropletStrength) * 0.5 + 0.5;
        dropletHeight *= 1.0 - dropFraction;
        dropletHeight *= distanceToDroplet > ringRadius ? 0.0 : distanceToDroplet / ringRadius;

        height += (1.0 - (cos(dropletHeight * 3.141) + 1.0) * 0.5) * dropletHeightFactor;
    }

    return height;
}

vec3 getDropletNormal(vec2 uv)
{
    float NORMAL_OFF = (1.0 / 128.0);
    vec3 off = vec3(-NORMAL_OFF, 0, NORMAL_OFF);

    // s11 = Current
    float s11 = getDropletHeight(uv);

    // s01 = Left
    float s01 = getDropletHeight(vec2(uv.xy + off.xy));

    // s21 = Right
    float s21 = getDropletHeight(vec2(uv.xy + off.zy));

    // s10 = Below
    float s10 = getDropletHeight(vec2(uv.xy + off.yx));

    // s12 = Above
    float s12 = getDropletHeight(vec2(uv.xy + off.yz));

    vec3 va = normalize( vec3(off.z, 0.0, s21 - s11) );
    vec3 vb = normalize( vec3(0.0, off.z, s12 - s11) );

    vec3 normal = cross(va, vb);
    normal.xy *= s11;
    return normalize(normal);
}

vec3 generateNormalMap(vec2 uv)
{
    vec3 d = getDropletNormal(uv - 0.5);
    return normalize(d);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	vec2 uv = gl_FragCoord.xy / iResolution.xy;
	if (GET > 0)
	{
    	vec3 normal = generateNormalMap(uv);
    	if (GET == 1)
    	{
    		fragColor = vec4((normal + 1.0) * 0.5, 1.0);
    	}
    	else if (GET == 2)
    	{
    		fragColor.xyz = texture(iChannel1, normal).xyz;
    	}
	}
	else
	{
        float h = getDropletHeight(uv);
        fragColor = vec4(h, h, h, 1.0);
    }
}
