#version 330 core
precision highp float;

// Beat-synchronised fullscreen effect. All beat-derived values are computed on the CPU (BeatSync
// demopart) from a precomputed sidecar and fed in as uniforms, so the look is identical in realtime
// playback and in --record frame capture.

in vec2 fragCoord; // pixel coordinates, [0, iResolution]
out vec4 fragColor;

uniform vec3  iResolution;
uniform float iTime;

uniform float uKick;      // low-band energy [0,1], fast-attack/slow-release smoothed
uniform float uMid;       // mid-band energy [0,1]
uniform float uHigh;      // high-band energy [0,1]
uniform float uBeatPulse; // 1.0 at beat onset -> 0.0 before next beat
uniform float uBarPhase;  // [0,1) progress through the current bar
uniform float uColorShift;// hue offset, advances per bar
uniform float uKickAmt;   // kick intensity (from JSON)
uniform float uStrobe;    // on-beat flash intensity (from JSON)
uniform int   uBar;       // bar index
uniform int   uBeatInBar; // beat within the bar (0 == downbeat)
uniform int   uVariant;   // forced background pattern (0/1/2); < 0 = auto (switch every 4 bars)

vec2 rot(vec2 p, float a) {
	float c = cos(a), s = sin(a);
	return mat2(c, -s, s, c) * p;
}

void main() {
	vec2 res = iResolution.xy;
	vec2 uv = (fragCoord - 0.5 * res) / res.y;

	// Kick zoom: punch inward on every kick.
	float zoom = 0.18 * uKick * uKickAmt;
	vec2 p = uv * (1.0 - zoom);

	// Slow global rotation, nudged per bar.
	p = rot(p, iTime * 0.08 + float(uBar) * 0.15);

	float r = length(p);
	float a = atan(p.y, p.x);

	// Background pattern: forced by uVariant (from the JSON schedule), else auto-switches every 4 bars.
	int variant = (uVariant >= 0) ? (uVariant % 3) : ((uBar / 4) % 3);
	float pattern;
	if (variant == 0) {
		// Tunnel rings.
		pattern = 0.5 + 0.5 * sin(r * 26.0 - iTime * 3.0);
	} else if (variant == 1) {
		// Pulsing grid.
		vec2 g = fract(p * 6.0) - 0.5;
		pattern = smoothstep(0.45, 0.05, length(g));
	} else {
		// Radial kaleidoscope spokes.
		pattern = 0.5 + 0.5 * sin(a * 12.0 + iTime * 2.0 - r * 8.0);
	}

	// Cool blue tint over the monochrome pattern (single hue, not the old rainbow palette).
	// Dial the color / how far it pulls from grey to taste.
	vec3 col = pattern * vec3(0.55, 0.72, 1.0);

	// Vignette to keep the centre reading.
	col *= smoothstep(1.3, 0.1, r);

	// Mid energy lifts the whole frame; kick adds a brightness punch.
	col *= (0.6 + 0.8 * uMid);
	col *= (1.0 + 0.7 * uKick * uKickAmt);

	// Hi-hat sparkle.
	float spark = 0.5 + 0.5 * sin(r * 120.0 - iTime * 20.0);
	col += vec3(0.15) * uHigh * spark;

	// On-beat strobe, with an extra hit on the downbeat (hard cut on the bar).
	float flash = uBeatPulse * uStrobe * 0.5;
	if (uBeatInBar == 0) {
		flash += uBeatPulse * uStrobe * 0.4;
	}
	col += vec3(flash);

	fragColor = vec4(clamp(col, 0.0, 1.0), 1.0);
}
