/* Butter - GetCaustics.glsl
Fragment caustics shadow function.

Typon - GNU Lesser General Public License v3.0
*/

float clamp01(float value) { return clamp(value, 0.0, 1.0); }

float hash(vec2 p) {
    return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
}

float smoothNoise(vec2 p) {
    vec2 i = floor(p);
    vec2 f = fract(p);
    float a = hash(i);
    float b = hash(i + vec2(1.0, 0.0));
    float c = hash(i + vec2(0.0, 1.0));
    float d = hash(i + vec2(1.0, 1.0));
    vec2 u = f * f * (3.0 - 2.0 * f);
    return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
}

float calculateDnaWave(vec2 pos) {
    float t = frameTimeCounter * 0.5;

    vec2 waveOffset;
    waveOffset.x = sin(pos.y * 1.8 + t * 2.0) * 0.4;
    waveOffset.y = cos(pos.x * 2.0 + t * 2.5) * 0.4;
    pos += waveOffset;

    float baseWave = sin(pos.x * 3.0 + sin(pos.y * 0.6 + t)) * 0.5 + 0.5;

    float n = smoothNoise(pos * 0.7) * 0.35;

    return clamp01(baseWave + n * 0.005);
}

float calculateDnaWave2(vec2 pos) {
    float t = frameTimeCounter * 0.5;

    vec2 waveOffset;
    waveOffset.x = sin(pos.y * 1.8 + t * 2.0) * 0.4;
    waveOffset.y = cos(pos.x * 2.0 + t * 2.5) * 0.4;
    pos += waveOffset;

    float baseWave = sin(pos.x * 3.0 + sin(pos.y * 0.6 + t)) * 0.5 + 0.5;

    float n = smoothNoise(pos * 0.7) * 0.35;

    return clamp01(baseWave + n * 0.005);
}

float color_waves(vec3 position, float opacityPow) {
    float t = frameTimeCounter * 0.9;

    float angle = radians(60.0);
    mat2 rot = mat2(cos(angle), -sin(angle), sin(angle), cos(angle));
    vec2 uv = rot * position.xz;

    uv *= vec2(8.0, 3.0) * 1.2;
    uv += vec2(t * 0.18, 0.0);

    float n1 = calculateDnaWave(uv * 6.5 * 0.85);
    
    float wave = abs(n1);
    return pow(clamp01(1.0 - wave), opacityPow);
}

float color_waves2(vec3 position, float opacityPow) {
    float t = frameTimeCounter * 2.0;

    float angle = radians(-60.0);
    mat2 rot = mat2(cos(angle), -sin(angle), sin(angle), cos(angle));
    vec2 uv = rot * position.xz;

    uv *= vec2(8.0, 3.0) * 1.2;
    uv += vec2(-t * 0.16, 0.0);

    float n1 = calculateDnaWave2(uv * 7.5 * 0.85);
    
    float wave = abs(n1);
    return pow(clamp01(1.0 - wave), opacityPow);
}

vec3 GetCausticsRgb(vec3 p, float opacityPow, float strength) {
    vec3 o = vec3(1.0, 0.0, 1.0) * 0.02;
    vec3 w;
    w.x = color_waves(p + o, opacityPow);
    w.y = color_waves(p + o * 1.1, opacityPow);
    w.z = color_waves(p + o * 1.2, opacityPow);
    return vec3(1.0) * strength * color_waves(p, opacityPow);
}

vec3 GetCausticsRgb2(vec3 p, float opacityPow, float strength) {
    vec3 o = vec3(1.0, 0.0, 1.0) * 0.02;
    vec3 w;
    w.x = color_waves2(p + o, opacityPow);
    w.y = color_waves2(p + o * 1.1, opacityPow);
    w.z = color_waves2(p + o * 1.2, opacityPow);
    return vec3(1.0) * strength * color_waves2(p, opacityPow);
}

vec3 drawCaustic(vec3 col) {
	vec3 caustics = GetCausticsRgb((worldPos + cameraPosition.xyz) * 0.05, 230.0, 0.65);
	vec3 caustics2 = GetCausticsRgb2((worldPos + cameraPosition.xyz) * 0.05, 230.0, 0.65);
	vec3 caustics3 = GetCausticsRgb((2.0 * worldPos + cameraPosition.xyz * 2.0) * 0.05, 120.0, 0.7);
	vec3 caustics4 = GetCausticsRgb2((2.5 * worldPos + cameraPosition.xyz) * 0.05, 120.0, 0.7);
	
	col = mix(col, caustics + caustics2 + caustics3, 1.0);
	
	return col;
}
