// @name Chromatic Aberration
// @group Main
// @param uAberrationBase "Aberration Amount" 0.005 0.0 0.02 0.001
// @group Radial
// @param uRadialStrength "Radial Strength" 1.0 0.0 3.0 0.1
// @param uRadialFalloff "Radial Falloff" 2.0 0.5 4.0 0.1
// @group Lateral
// @param uLateralStrength "Lateral Strength" 0.5 0.0 2.0 0.05
// @param uLateralAngle "Lateral Angle" 0.0 -3.14 3.14 0.1
// @group Axial
// @param uAxialBlur "Axial Blur" 0.0 0.0 1.0 0.05
// @group Fringing
// @param uFringeStrength "Fringe Strength" 0.3 0.0 1.0 0.05
// @param uDispersionStrength "Dispersion" 0.2 0.0 1.0 0.05
// @group Bloom
// @param uAberrationBloom "Bloom Strength" 0.3 0.0 1.0 0.05
// @param uAberrationBloomThreshold "Bloom Threshold" 0.5 0.0 1.0 0.05
// @group Vignette
// @param uAberrationVignette "Vignette" 0.3 0.0 1.0 0.05

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    vec2 uv = fragCoord / uResolution.xy;
    vec2 center = vec2(0.5);
    
    // Base aberration amount
    float aberration = uAberrationBase * uIntensity * 3.0;
    
    // Distance from center for radial effect
    vec2 dir = uv - center;
    float dist = length(dir);
    vec2 normDir = dist > 0.0 ? dir / dist : vec2(0.0);
    
    // === RADIAL CHROMATIC ABERRATION ===
    float radialAmount = aberration * pow(dist, uRadialFalloff) * uRadialStrength;
    
    vec2 redOffset = normDir * radialAmount;
    vec2 greenOffset = vec2(0.0);
    vec2 blueOffset = -normDir * radialAmount;
    
    float r = texture(uTexture, uv + redOffset).r;
    float g = texture(uTexture, uv + greenOffset).g;
    float b = texture(uTexture, uv + blueOffset).b;
    
    // === LATERAL CHROMATIC ABERRATION ===
    float lateralAmount = aberration * uLateralStrength * 0.5;
    vec2 lateralDir = vec2(cos(uLateralAngle), sin(uLateralAngle));
    vec2 lateralOffset = lateralDir * lateralAmount;
    
    r = mix(r, texture(uTexture, uv + lateralOffset).r, 0.5);
    b = mix(b, texture(uTexture, uv - lateralOffset).b, 0.5);
    
    // === AXIAL CHROMATIC ABERRATION (blur difference) ===
    if (uAxialBlur > 0.05) {
        float blurAmount = aberration * uAxialBlur * 0.5;
        
        float rBlur = 0.0;
        float bBlur = 0.0;
        float samples = 0.0;
        
        for (float x = -2.0; x <= 2.0; x += 1.0) {
            for (float y = -2.0; y <= 2.0; y += 1.0) {
                float weight = 1.0 / (1.0 + length(vec2(x, y)));
                vec2 offset = vec2(x, y) * blurAmount / uResolution.xy * 100.0;
                rBlur += texture(uTexture, uv + redOffset + offset).r * weight;
                bBlur += texture(uTexture, uv + blueOffset + offset).b * weight;
                samples += weight;
            }
        }
        
        r = mix(r, rBlur / samples, uAxialBlur);
        b = mix(b, bBlur / samples, uAxialBlur);
    }
    
    vec3 col = vec3(r, g, b);
    
    // === FRINGING ===
    float luma = dot(texture(uTexture, uv).rgb, vec3(0.299, 0.587, 0.114));
    float lumaR = dot(col, vec3(0.299, 0.587, 0.114));
    float edge = abs(luma - lumaR);
    
    vec3 fringeColor = vec3(0.8, 0.2, 1.0); // Purple fringe
    col += fringeColor * edge * uFringeStrength * uIntensity;
    
    // === SPECTRAL DISPERSION ===
    if (dist > 0.3 && uDispersionStrength > 0.0) {
        float rainbowAngle = atan(dir.y, dir.x);
        vec3 rainbow = vec3(
            sin(rainbowAngle * 3.0) * 0.5 + 0.5,
            sin(rainbowAngle * 3.0 + 2.094) * 0.5 + 0.5,
            sin(rainbowAngle * 3.0 + 4.189) * 0.5 + 0.5
        );
        
        float rainbowMask = smoothstep(0.3, 0.7, dist) * uDispersionStrength * uIntensity * 0.2;
        col += rainbow * rainbowMask;
    }
    
    // === BLOOM ON ABERRATION ===
    float brightness = dot(col, vec3(0.299, 0.587, 0.114));
    col += col * smoothstep(uAberrationBloomThreshold, 1.0, brightness) * uAberrationBloom;
    
    // === VIGNETTE ===
    float vig = 1.0 - dist * dist * uAberrationVignette * 2.0;
    col *= vig;
    
    fragColor = vec4(clamp(col, 0.0, 1.0), 1.0);
}
