#version 300 es
precision mediump float;

uniform vec2 u_display_size;
uniform vec3 u_background_color;
uniform vec3 u_colorA;
uniform vec3 u_colorB;
uniform vec3 u_colorC;
uniform float u_time;
uniform float u_fractal_noise_z;
uniform float u_grain_noise_scale;
uniform float u_mix_point_start;
uniform float u_mix_point_background;
uniform float u_mix_point_backgroundA;
uniform float u_mix_point_AB;
uniform float u_mix_point_BC;
uniform float u_mix_point_end;

in vec2 v_uv;  // From vertex shader
out vec4 fragColor;

// Fractal noise function for continuous grain effect
float fractal_noise(vec2 uv, float time) {
    return fract(sin(dot(uv * 10.0 + time * 0.1, vec2(12.9898, 78.233))) * 43758.5453);
}

// Grain noise function for additional texture
float grain_noise(vec2 uv) {
    return fract(sin(dot(uv * u_display_size.xy, vec2(12.9898, 78.233))) * 43758.5453) * u_grain_noise_scale;
}

// Color blending based on noise-driven transitions
vec3 getBlendedColor(float mix_point) {
    if (mix_point < u_mix_point_background) {
        return u_background_color;
    } else if (mix_point < u_mix_point_backgroundA) {
        return mix(u_background_color, u_colorA, smoothstep(u_mix_point_background, u_mix_point_backgroundA, mix_point));
    } else if (mix_point < u_mix_point_AB) {
        return u_colorA;
    } else if (mix_point < u_mix_point_BC) {
        return mix(u_colorA, u_colorB, smoothstep(u_mix_point_AB, u_mix_point_BC, mix_point));
    } else if (mix_point < u_mix_point_end) {
        return mix(u_colorB, u_colorC, smoothstep(u_mix_point_BC, u_mix_point_end, mix_point));
    } else {
        return u_colorC;
    }
}

void main() {
    vec2 uv = v_uv;

    // Calculate fractal noise to drive color transitions
    float fractalNoise = fractal_noise(uv, u_time * u_fractal_noise_z);

    // Apply color transitions based on fractal noise
    float mix_point = fractalNoise;
    vec3 color = getBlendedColor(mix_point);

    // Add grain noise for a textured effect
    float grain = grain_noise(uv);
    color += grain;

    // Final color output
    fragColor = vec4(color, 1.0);
}
