#version 440 layout(location = 0) in vec2 qt_TexCoord0; layout(location = 0) out vec4 fragColor; layout(std140, binding = 0) uniform buf { mat4 qt_Matrix; float qt_Opacity; float uSize; float uWavePhase; float uBreath; float uGlitch; float uGlitchSeed; vec4 uResolution; vec4 uC0; vec4 uC1; vec4 uC2; }; float sdHexagon(vec2 p, float r) { const vec3 k = vec3(-0.866025404, 0.5, 0.577350269); p = abs(p); p -= 2.0 * min(dot(k.xy, p), 0.0) * k.xy; p -= vec2(clamp(p.x, -k.z * r, k.z * r), r); return length(p) * sign(p.y); } // Interpolate between three theme stops (t in [0,1]) vec3 themeGradient(float t) { return t < 0.5 ? mix(uC0.rgb, uC1.rgb, t * 2.0) : mix(uC1.rgb, uC2.rgb, (t - 0.5) * 2.0); } // Cheap hash for glitch bands float hash(float n) { return fract(sin(n) * 43758.5453123); } void main() { vec2 res = uResolution.xy; // Glitch: shift some horizontal bands slightly vec2 frag = qt_TexCoord0 * res; if (uGlitch > 0.0) { float band = floor(frag.y / 7.0); float h = hash(band * 127.1 + uGlitchSeed * 311.7); if (h > 0.72) { float shift = (hash(band * 93.9 + uGlitchSeed) - 0.5) * 14.0 * uGlitch; frag.x = clamp(frag.x + shift, 0.0, res.x); } } float dx = uSize * 1.5; float dy = uSize * 1.7320508; float col = round(frag.x / dx); float yoff = mod(col, 2.0) != 0.0 ? dy * 0.5 : 0.0; float row = round((frag.y - yoff) / dy); vec2 center = vec2(col * dx, row * dy + yoff); // Wave — wide gaussian so it reads more as a broad pulse than a sharp sweep float dist = center.x - uWavePhase; float wf = exp(-dist * dist / 40000.0); float baseR = uSize * 0.48; float inradius = baseR * (1.0 + 0.15 * wf); vec2 p = frag - center; float d = sdHexagon(p.yx, inradius); // swap for flat-top if (d > 0.0) { fragColor = vec4(0.0); return; } // Gradient color float fx = clamp(center.x / res.x, 0.0, 1.0); vec3 rgb = fx < 0.5 ? mix(uC0.rgb, uC1.rgb, fx * 2.0) : mix(uC1.rgb, uC2.rgb, (fx - 0.5) * 2.0); // Alpha from distance to center (vignette) float fy = clamp(center.y / res.y, 0.0, 1.0); float dc = length(vec2(fx - 0.5, fy - 0.5)); float a = 0.03 + dc * 0.06; // Breathing pulse (when overview open) a += 0.025 * uBreath; rgb = min(rgb + vec3(0.04 * uBreath), vec3(1.0)); // Wave brighten (softer than before) rgb = min(rgb + vec3(0.15 * wf), vec3(1.0)); a += 0.07 * wf; // Shimmer on hex edges as wave passes float edgeWidth = 5.0; float edgeFactor = smoothstep(-edgeWidth, 0.0, d); if (wf > 0.01 && edgeFactor > 0.0) { float angle = atan(p.y, p.x); float rawT = fract((angle + 3.14159) / 6.28318 + center.x * 0.003 + center.y * 0.005); float t = abs(rawT * 2.0 - 1.0); vec3 shimmerColor = themeGradient(t); float shimmer = edgeFactor * wf; rgb = mix(rgb, shimmerColor, shimmer * 0.5); a = mix(a, 0.5, shimmer * 0.35); } // Anti-alias outer edge float aa = 1.0 - smoothstep(-1.0, 0.0, d); a *= aa; fragColor = vec4(rgb * a, a) * qt_Opacity; }