// Organic family: interference rings spreading from a handful of drop points,
// like rain on still water.
//
// Distinct from Classic Wave (one centred ring set) and Metaballs (merging
// bodies): here several sources overlap and the SUM is what is drawn, so the
// image is the interference pattern rather than the rings themselves. Where two
// wavefronts meet they cancel, which produces the moving lattice of nodes that
// makes water look like water.
//
// Ring geometry is measured in the track's signature form, so a hexagonal track
// gets hexagonal wavefronts.

export const tideRings = {
    name: 'Tide Rings',
    family: 'organic',
    kind: 'fragment',
    consumes: ['cast', 'ink'],
    traits: ['shape', 'camera', 'space', 'style'],

    params: {
        sources:   { type: 'int',   range: [2, 7],      default: 4,    uniform: 'u_sources', bias: 'density' },
        wavelength:{ type: 'float', range: [3, 26],     default: 10,   uniform: 'u_wavelength', bias: 'density' },
        speed:     { type: 'float', range: [0.05, 1.2], default: 0.35, uniform: 'u_speed', bias: 'motion', rate: true },
        decay:     { type: 'float', range: [0.2, 2.0],  default: 0.8,  uniform: 'u_decay' },
        caustic:   { type: 'float', range: [0, 1.5],    default: 0.6,  uniform: 'u_caustic', bias: 'energy' },
        spread:    { type: 'float', range: [0.2, 1.1],  default: 0.65, uniform: 'u_spread' },
        palette:   { type: 'palette', count: 5 },
    },

    reactive: {
        caustic:    { feature: 'beat',     amount: 0.3, response: 'smooth' },
        wavelength: { feature: 'bandMid',  amount: 0.2 },
    },

    shader: `
vec4 scene(vec2 uv, vec2 p) {
    float t = u_time * u_speed + u_seed;
    p = sigCamera(p);

    float sum = 0.0;
    float energy = 0.0;

    for (int i = 0; i < 7; i++) {
        if (i >= u_sources) break;
        float fi = float(i);
        float s = u_seed + fi * 91.7;

        // Sources wander slowly, so the interference lattice never settles into
        // a fixed pattern the eye can lock onto.
        vec2 src = vec2(
            sin(t * 0.21 + s) * u_spread,
            cos(t * 0.17 + s * 1.4) * u_spread * 0.7
        );

        // Distance in the signature metric: round tracks get circular wavefronts.
        float d = castMain(p - src) + 1.0;
        float amp = exp(-d * u_decay);
        sum += sin(d * u_wavelength - t * 6.0 + fract(s) * 6.28) * amp;
        energy += amp;
    }

    float wave = sum / max(energy, 1e-3);

    // The node lattice: where the sum passes through zero, the surface is flat
    // and bright. Squaring the gradient-ish term is what picks those out.
    float nodes = 1.0 - abs(wave);
    nodes = pow(sat(nodes), 3.0);

    vec3 col = mix(pal(0) * 0.1, pal(1), sat(wave * 0.5 + 0.5));
    col += pal(3) * nodes * u_caustic;
    col += pal(4) * pow(sat(wave), 6.0) * u_caustic * 0.5;

    col = sigAir(col, p, smoothstep(0.0, 1.7, length(p)));
    return vec4(inkValue(col), 1.0);
}
`,
};

export default tideRings;
