// @name Prism Split
// @group Prism
// @param uSplitAmount "Split Amount" 0.02 0.0 0.1 0.002
// @param uSplitAngle "Split Angle" 0.0 -3.14 3.14 0.05
// @param uRotationSpeed "Rotation Speed" 0.5 -2.0 2.0 0.1
// @group Spectral
// @param uSpectralBands "Spectral Bands" 3.0 3.0 7.0 1.0
// @param uSpectralSpread "Spectral Spread" 1.0 0.5 3.0 0.1
// @param uSpectralBlend "Band Blending" 0.5 0.0 1.0 0.05
// @group Center
// @param uCenterX "Center X" 0.5 0.0 1.0 0.01
// @param uCenterY "Center Y" 0.5 0.0 1.0 0.01
// @param uRadialFalloff "Radial Falloff" 1.5 0.0 4.0 0.1
// @group Animation
// @param uPulseSpeed "Pulse Speed" 0.0 0.0 5.0 0.25
// @param uPulseAmount "Pulse Amount" 0.0 0.0 0.5 0.02
// @param uWaveAmount "Wave Distortion" 0.0 0.0 1.0 0.05
// @param uWaveFreq "Wave Frequency" 3.0 1.0 10.0 0.5
// @group Refraction
// @param uRefractionIndex "Refraction Index" 1.5 1.0 3.0 0.1
// @param uDispersion "Dispersion" 0.5 0.0 2.0 0.05
// @group Glow
// @param uRainbowGlow "Rainbow Glow" 0.3 0.0 1.0 0.05
// @param uGlowSize "Glow Size" 3.0 1.0 10.0 0.5
// @group Blend
// @param uOriginalMix "Original Mix" 0.0 0.0 1.0 0.05
// @param uSaturationBoost "Saturation Boost" 0.2 0.0 1.0 0.05

vec3 hsv2rgb(vec3 c) {
    vec4 K = vec4(1.0, 2.0/3.0, 1.0/3.0, 3.0);
    vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}

vec3 rgb2hsv(vec3 c) {
    vec4 K = vec4(0.0, -1.0/3.0, 2.0/3.0, -1.0);
    vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
    vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
    float d = q.x - min(q.w, q.y);
    float e = 1.0e-10;
    return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}

// Wavelength to RGB approximation
vec3 wavelengthToRGB(float wavelength) {
    // Approximate visible spectrum (380-780nm) mapped to 0-1
    float w = wavelength * 400.0 + 380.0;
    vec3 col;
    
    if (w < 440.0) {
        col = vec3(-(w - 440.0) / 60.0, 0.0, 1.0);
    } else if (w < 490.0) {
        col = vec3(0.0, (w - 440.0) / 50.0, 1.0);
    } else if (w < 510.0) {
        col = vec3(0.0, 1.0, -(w - 510.0) / 20.0);
    } else if (w < 580.0) {
        col = vec3((w - 510.0) / 70.0, 1.0, 0.0);
    } else if (w < 645.0) {
        col = vec3(1.0, -(w - 645.0) / 65.0, 0.0);
    } else {
        col = vec3(1.0, 0.0, 0.0);
    }
    
    // Intensity falloff at spectrum edges
    float factor = 1.0;
    if (w < 420.0) factor = 0.3 + 0.7 * (w - 380.0) / 40.0;
    else if (w > 700.0) factor = 0.3 + 0.7 * (780.0 - w) / 80.0;
    
    return col * factor;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    vec2 uv = fragCoord / uResolution.xy;
    vec2 center = vec2(uCenterX, uCenterY);
    
    // Distance and angle from center
    vec2 toCenter = uv - center;
    float dist = length(toCenter);
    float angle = atan(toCenter.y, toCenter.x);
    
    // Animated rotation
    float rotAngle = uSplitAngle + uTime * uRotationSpeed * uIntensity;
    
    // Pulse animation
    float pulse = 1.0;
    if (uPulseSpeed > 0.0) {
        pulse = 1.0 + sin(uTime * uPulseSpeed) * uPulseAmount * uIntensity;
    }
    
    // Wave distortion
    float wave = 0.0;
    if (uWaveAmount > 0.0) {
        wave = sin(angle * uWaveFreq + uTime * 2.0) * uWaveAmount * uIntensity;
    }
    
    // Calculate split with radial falloff
    float splitMag = uSplitAmount * pow(dist, uRadialFalloff) * pulse * uIntensity;
    splitMag += wave * 0.02;
    
    // Refraction simulation
    float refractOffset = (uRefractionIndex - 1.0) * splitMag;
    
    // Split direction
    vec2 splitDir = vec2(cos(rotAngle), sin(rotAngle));
    
    vec3 result = vec3(0.0);
    
    if (uSpectralBands <= 3.5) {
        // Simple RGB split
        float spread = splitMag * uSpectralSpread;
        
        vec2 redOffset = splitDir * (spread + refractOffset * uDispersion);
        vec2 greenOffset = vec2(0.0);
        vec2 blueOffset = -splitDir * (spread + refractOffset * uDispersion * 1.2);
        
        result.r = texture(uTexture, clamp(uv + redOffset, 0.0, 1.0)).r;
        result.g = texture(uTexture, clamp(uv + greenOffset, 0.0, 1.0)).g;
        result.b = texture(uTexture, clamp(uv + blueOffset, 0.0, 1.0)).b;
    } else {
        // Multi-band spectral split
        float bands = floor(uSpectralBands);
        
        for (float i = 0.0; i < 7.0; i++) {
            if (i >= bands) break;
            
            float t = i / (bands - 1.0); // 0 to 1
            float offset = (t - 0.5) * 2.0 * splitMag * uSpectralSpread;
            offset += (t - 0.5) * refractOffset * uDispersion;
            
            vec2 sampleOffset = splitDir * offset;
            vec3 samp = texture(uTexture, clamp(uv + sampleOffset, 0.0, 1.0)).rgb;
            
            // Weight by spectral color
            vec3 spectralWeight = wavelengthToRGB(t);
            
            // Blend mode
            if (uSpectralBlend > 0.5) {
                result += samp * spectralWeight;
            } else {
                float luma = dot(samp, vec3(0.299, 0.587, 0.114));
                result += spectralWeight * luma;
            }
        }
        
        result /= bands * 0.5;
    }
    
    // Rainbow glow
    if (uRainbowGlow > 0.0) {
        vec3 glow = vec3(0.0);
        
        for (float i = 1.0; i <= 10.0; i++) {
            if (i > uGlowSize) break;
            
            float weight = 1.0 / i;
            
            for (float a = 0.0; a < 6.28; a += 1.047) {
                vec2 offset = vec2(cos(a + rotAngle), sin(a + rotAngle)) / uResolution.xy * i * 2.0;
                vec3 samp = texture(uTexture, clamp(uv + offset, 0.0, 1.0)).rgb;
                
                vec3 rainbowTint = wavelengthToRGB(fract(a / 6.28 + uTime * 0.1));
                glow += samp * rainbowTint * weight;
            }
        }
        
        glow /= uGlowSize * 3.0;
        result += glow * uRainbowGlow * uIntensity;
    }
    
    // Saturation boost
    if (uSaturationBoost > 0.0) {
        vec3 hsv = rgb2hsv(result);
        hsv.y = min(1.0, hsv.y * (1.0 + uSaturationBoost));
        result = hsv2rgb(hsv);
    }
    
    // Mix with original
    vec3 original = texture(uTexture, uv).rgb;
    result = mix(result, original, uOriginalMix);
    
    fragColor = vec4(clamp(result, 0.0, 1.0), 1.0);
}

