up su Gitea
This commit is contained in:
@@ -0,0 +1,559 @@
|
||||
#version 450
|
||||
|
||||
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 time;
|
||||
float itemWidth;
|
||||
float itemHeight;
|
||||
vec4 primaryColor;
|
||||
vec4 secondaryColor;
|
||||
float sensitivity;
|
||||
float rotationSpeed;
|
||||
float barWidth;
|
||||
float ringOpacity;
|
||||
float cornerRadius;
|
||||
float bloomIntensity;
|
||||
float visualizationMode; // 0=bars, 1=wave, 2=rings, 3=bars+rings, 4=wave+rings, 5=all
|
||||
float waveThickness;
|
||||
float innerDiameter;
|
||||
} ubuf;
|
||||
|
||||
// Mode helper functions
|
||||
bool hasRings() { return ubuf.visualizationMode >= 2.0; }
|
||||
bool hasBars() { return ubuf.visualizationMode == 0.0 || ubuf.visualizationMode == 3.0 || ubuf.visualizationMode >= 5.0; }
|
||||
bool hasWave() { return ubuf.visualizationMode == 1.0 || ubuf.visualizationMode == 4.0 || ubuf.visualizationMode >= 5.0; }
|
||||
|
||||
layout(binding = 1) uniform sampler2D source;
|
||||
|
||||
#define TWOPI 6.28318530718
|
||||
#define PI 3.14159265359
|
||||
#define NBARS 32
|
||||
|
||||
// Sample audio amplitude at normalized position (0.0-1.0)
|
||||
float getAudio(float pos) {
|
||||
return texture(source, vec2(clamp(pos, 0.0, 1.0), 0.5)).r;
|
||||
}
|
||||
|
||||
// Smoothed audio sampling with interpolation
|
||||
float smoothAudio(float pos) {
|
||||
float idx = pos * float(NBARS - 1);
|
||||
float frac = fract(idx);
|
||||
float i0 = floor(idx) / float(NBARS - 1);
|
||||
float i1 = ceil(idx) / float(NBARS - 1);
|
||||
return mix(getAudio(i0), getAudio(i1), frac) * ubuf.sensitivity;
|
||||
}
|
||||
|
||||
// Frequency band helpers
|
||||
float getBass() { return smoothAudio(0.05); }
|
||||
float getMid() { return smoothAudio(0.3); }
|
||||
float getHighMid() { return smoothAudio(0.6); }
|
||||
float getTreble() { return smoothAudio(0.9); }
|
||||
|
||||
// SDF for rounded rectangle
|
||||
float roundedBoxSDF(vec2 center, vec2 size, float radius) {
|
||||
vec2 q = abs(center) - size + radius;
|
||||
return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - radius;
|
||||
}
|
||||
|
||||
// Compute polar wave visualization
|
||||
vec4 computePolarWave(vec2 uv, float iTime, float bass, float mid, float highMid, float treble) {
|
||||
float aspect = ubuf.itemWidth / ubuf.itemHeight;
|
||||
vec2 centered = (uv - 0.5) * 2.0;
|
||||
centered.x *= aspect;
|
||||
|
||||
float theta = atan(centered.y, centered.x);
|
||||
float d = length(centered);
|
||||
float innerRadius = ubuf.innerDiameter / 2.0;
|
||||
float baseRadius = 0.35; // Fixed reference for outer extent
|
||||
|
||||
vec4 color = vec4(0.0);
|
||||
|
||||
// RING SYSTEM
|
||||
if (hasRings()) {
|
||||
// Center Waves
|
||||
if (d < innerRadius * 0.6) {
|
||||
float wave = mid * 0.8;
|
||||
float ripple = sin(d * 25.0 + wave * 15.0 - iTime * 2.0);
|
||||
if (ripple > 0.7) {
|
||||
float intensity = clamp(mid * 0.6, 0.0, 0.4);
|
||||
vec4 waveColor = ubuf.secondaryColor * intensity * ubuf.ringOpacity;
|
||||
color = max(color, waveColor);
|
||||
}
|
||||
}
|
||||
|
||||
// Energy Ring
|
||||
float energyRad = innerRadius * 0.65;
|
||||
float energyThickness = 0.015 + clamp(highMid * 0.02, 0.0, 0.03);
|
||||
if (d > energyRad - energyThickness && d < energyRad + energyThickness) {
|
||||
float segmentAngle = theta * 8.0 + highMid * 3.0 + iTime;
|
||||
if (mod(segmentAngle, 1.0) < 0.6) {
|
||||
float alpha = clamp(highMid * 2.0, 0.3, 1.0) * ubuf.ringOpacity;
|
||||
vec4 energyColor = mix(ubuf.primaryColor, ubuf.secondaryColor, 0.5) * alpha;
|
||||
color = max(color, energyColor);
|
||||
}
|
||||
}
|
||||
|
||||
// Particle Ring
|
||||
float particleRad = innerRadius * 0.75;
|
||||
if (d > particleRad - 0.02 && d < particleRad + 0.02) {
|
||||
float particleAngle = theta + treble * 2.0 + iTime * 0.5;
|
||||
float particleSpacing = TWOPI / 16.0;
|
||||
if (mod(particleAngle, particleSpacing) < 0.15) {
|
||||
float brightness = 0.5 + clamp(treble * 1.5, 0.0, 0.5);
|
||||
vec4 particleColor = ubuf.secondaryColor * brightness * ubuf.ringOpacity;
|
||||
color = max(color, particleColor);
|
||||
}
|
||||
}
|
||||
|
||||
// Tech Grid Ring
|
||||
float gridRad = innerRadius * 0.85;
|
||||
if (d > gridRad - 0.012 && d < gridRad + 0.012) {
|
||||
float gridAngle = theta + iTime * ubuf.rotationSpeed;
|
||||
float gridDensity = 0.08 + clamp(mid * 0.05, 0.0, 0.1);
|
||||
if (mod(gridAngle, 0.2) < gridDensity) {
|
||||
vec4 gridColor = ubuf.primaryColor * 0.7 * ubuf.ringOpacity;
|
||||
gridColor.rgb += vec3(0.1, 0.15, 0.2) * clamp(mid, 0.0, 0.8);
|
||||
color = max(color, gridColor);
|
||||
}
|
||||
}
|
||||
|
||||
// Accent Ring
|
||||
float accentRad = innerRadius * 0.92;
|
||||
float pulse = clamp(bass * 0.08, 0.0, 0.05);
|
||||
if (d > accentRad - pulse - 0.008 && d < accentRad + pulse + 0.015) {
|
||||
float colorShift = clamp(bass * 0.5, 0.0, 1.0);
|
||||
vec4 ringColor = mix(ubuf.secondaryColor * 0.7, ubuf.primaryColor, colorShift);
|
||||
ringColor.a = ubuf.ringOpacity;
|
||||
ringColor.rgb *= 1.0 + bass * 0.3;
|
||||
color = max(color, ringColor);
|
||||
}
|
||||
|
||||
// Outer Ring
|
||||
float outerRad = innerRadius + bass * 0.05;
|
||||
if (d > outerRad - 0.008 && d < outerRad + 0.008) {
|
||||
vec4 outerColor = ubuf.primaryColor * ubuf.ringOpacity;
|
||||
outerColor.rgb += vec3(0.2, 0.3, 0.4) * clamp(treble * 0.5, 0.0, 0.3);
|
||||
outerColor.rgb *= 1.0 + bass * 0.4;
|
||||
color = max(color, outerColor);
|
||||
}
|
||||
}
|
||||
|
||||
// POLAR WAVE - filled shape with mirrored bands (64 visual bands from 32 samples)
|
||||
if (hasWave()) {
|
||||
float adjustedTheta = theta + PI + iTime * ubuf.rotationSpeed * 0.2;
|
||||
|
||||
// Map angle to 0-1 range around the full circle
|
||||
float normalizedAngle = mod(adjustedTheta, TWOPI) / TWOPI;
|
||||
|
||||
// Mirror: first half (0-0.5) maps to bands 0->31, second half (0.5-1) maps back 31->0
|
||||
float mirroredPos = normalizedAngle < 0.5 ? normalizedAngle * 2.0 : (1.0 - normalizedAngle) * 2.0;
|
||||
|
||||
// Catmull-Rom spline interpolation for smooth curve through mirrored bands
|
||||
float bandPos = mirroredPos * float(NBARS - 1);
|
||||
float fband1 = floor(bandPos);
|
||||
float fband0 = max(fband1 - 1.0, 0.0);
|
||||
float fband2 = min(fband1 + 1.0, float(NBARS - 1));
|
||||
float fband3 = min(fband1 + 2.0, float(NBARS - 1));
|
||||
|
||||
float t = fract(bandPos);
|
||||
|
||||
// Sample the 4 control points
|
||||
float p0 = getAudio(fband0 / float(NBARS - 1)) * ubuf.sensitivity;
|
||||
float p1 = getAudio(fband1 / float(NBARS - 1)) * ubuf.sensitivity;
|
||||
float p2 = getAudio(fband2 / float(NBARS - 1)) * ubuf.sensitivity;
|
||||
float p3 = getAudio(fband3 / float(NBARS - 1)) * ubuf.sensitivity;
|
||||
|
||||
// Catmull-Rom spline interpolation
|
||||
float t2 = t * t;
|
||||
float t3 = t2 * t;
|
||||
float smoothedAudio = 0.5 * (
|
||||
(2.0 * p1) +
|
||||
(-p0 + p2) * t +
|
||||
(2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2 +
|
||||
(-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3
|
||||
);
|
||||
smoothedAudio = max(smoothedAudio, 0.0);
|
||||
|
||||
// Calculate wave radius at this angle
|
||||
float waveDisplacement = smoothedAudio * 0.5;
|
||||
float waveRadius = baseRadius + waveDisplacement; // Fixed outer extent
|
||||
|
||||
// Fill the entire area from inner to wave edge
|
||||
if (d >= innerRadius && d <= waveRadius) {
|
||||
float fillFactor = (d - innerRadius) / max(waveRadius - innerRadius, 0.001);
|
||||
|
||||
// Gradient from primary at base to accent at edge
|
||||
vec3 fillColor = mix(ubuf.primaryColor.rgb * 0.8, ubuf.secondaryColor.rgb, fillFactor);
|
||||
|
||||
// Boost brightness with bass
|
||||
fillColor *= 1.0 + bass * 0.3;
|
||||
|
||||
// Alpha: stronger near the edge, fades toward center
|
||||
float fillAlpha = mix(0.4, 1.0, fillFactor) * ubuf.waveThickness;
|
||||
fillAlpha = clamp(fillAlpha, 0.0, 1.0);
|
||||
|
||||
vec4 fill = vec4(fillColor, fillAlpha);
|
||||
color = max(color, fill);
|
||||
}
|
||||
|
||||
// Bright edge line at the wave boundary
|
||||
float edgeThickness = ubuf.waveThickness * 0.025;
|
||||
float distToEdge = abs(d - waveRadius);
|
||||
if (distToEdge < edgeThickness) {
|
||||
float edgeFactor = 1.0 - smoothstep(0.0, edgeThickness, distToEdge);
|
||||
vec3 edgeColor = ubuf.secondaryColor.rgb * (1.2 + smoothedAudio * 0.5);
|
||||
|
||||
// Add highlight at peaks
|
||||
if (smoothedAudio > 0.5) {
|
||||
edgeColor += vec3(0.3, 0.4, 0.5) * (smoothedAudio - 0.5);
|
||||
}
|
||||
|
||||
vec4 edge = vec4(edgeColor, edgeFactor);
|
||||
color = max(color, edge);
|
||||
}
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
// Compute visualization color at given UV coordinates
|
||||
// Returns vec4 with RGB color and alpha
|
||||
vec4 computeVisualization(vec2 uv, float iTime, float bass, float mid, float highMid, float treble) {
|
||||
float aspect = ubuf.itemWidth / ubuf.itemHeight;
|
||||
vec2 centered = (uv - 0.5) * 2.0;
|
||||
centered.x *= aspect;
|
||||
|
||||
float theta = atan(centered.y, centered.x);
|
||||
float d = length(centered);
|
||||
float innerRadius = ubuf.innerDiameter / 2.0;
|
||||
float baseRadius = 0.35; // Fixed reference for outer extent
|
||||
|
||||
vec4 color = vec4(0.0);
|
||||
|
||||
// RING SYSTEM
|
||||
if (hasRings()) {
|
||||
// Center Waves
|
||||
if (d < innerRadius * 0.6) {
|
||||
float wave = mid * 0.8;
|
||||
float ripple = sin(d * 25.0 + wave * 15.0 - iTime * 2.0);
|
||||
if (ripple > 0.7) {
|
||||
float intensity = clamp(mid * 0.6, 0.0, 0.4);
|
||||
vec4 waveColor = ubuf.secondaryColor * intensity * ubuf.ringOpacity;
|
||||
color = max(color, waveColor);
|
||||
}
|
||||
}
|
||||
|
||||
// Energy Ring
|
||||
float energyRad = innerRadius * 0.65;
|
||||
float energyThickness = 0.015 + clamp(highMid * 0.02, 0.0, 0.03);
|
||||
if (d > energyRad - energyThickness && d < energyRad + energyThickness) {
|
||||
float segmentAngle = theta * 8.0 + highMid * 3.0 + iTime;
|
||||
if (mod(segmentAngle, 1.0) < 0.6) {
|
||||
float alpha = clamp(highMid * 2.0, 0.3, 1.0) * ubuf.ringOpacity;
|
||||
vec4 energyColor = mix(ubuf.primaryColor, ubuf.secondaryColor, 0.5) * alpha;
|
||||
color = max(color, energyColor);
|
||||
}
|
||||
}
|
||||
|
||||
// Particle Ring
|
||||
float particleRad = innerRadius * 0.75;
|
||||
if (d > particleRad - 0.02 && d < particleRad + 0.02) {
|
||||
float particleAngle = theta + treble * 2.0 + iTime * 0.5;
|
||||
float particleSpacing = TWOPI / 16.0;
|
||||
if (mod(particleAngle, particleSpacing) < 0.15) {
|
||||
float brightness = 0.5 + clamp(treble * 1.5, 0.0, 0.5);
|
||||
vec4 particleColor = ubuf.secondaryColor * brightness * ubuf.ringOpacity;
|
||||
color = max(color, particleColor);
|
||||
}
|
||||
}
|
||||
|
||||
// Tech Grid Ring
|
||||
float gridRad = innerRadius * 0.85;
|
||||
if (d > gridRad - 0.012 && d < gridRad + 0.012) {
|
||||
float gridAngle = theta + iTime * ubuf.rotationSpeed;
|
||||
float gridDensity = 0.08 + clamp(mid * 0.05, 0.0, 0.1);
|
||||
if (mod(gridAngle, 0.2) < gridDensity) {
|
||||
vec4 gridColor = ubuf.primaryColor * 0.7 * ubuf.ringOpacity;
|
||||
gridColor.rgb += vec3(0.1, 0.15, 0.2) * clamp(mid, 0.0, 0.8);
|
||||
color = max(color, gridColor);
|
||||
}
|
||||
}
|
||||
|
||||
// Accent Ring
|
||||
float accentRad = innerRadius * 0.92;
|
||||
float pulse = clamp(bass * 0.08, 0.0, 0.05);
|
||||
if (d > accentRad - pulse - 0.008 && d < accentRad + pulse + 0.015) {
|
||||
float colorShift = clamp(bass * 0.5, 0.0, 1.0);
|
||||
vec4 ringColor = mix(ubuf.secondaryColor * 0.7, ubuf.primaryColor, colorShift);
|
||||
ringColor.a = ubuf.ringOpacity;
|
||||
ringColor.rgb *= 1.0 + bass * 0.3;
|
||||
color = max(color, ringColor);
|
||||
}
|
||||
|
||||
// Outer Ring
|
||||
float outerRad = innerRadius + bass * 0.05;
|
||||
if (d > outerRad - 0.008 && d < outerRad + 0.008) {
|
||||
vec4 outerColor = ubuf.primaryColor * ubuf.ringOpacity;
|
||||
outerColor.rgb += vec3(0.2, 0.3, 0.4) * clamp(treble * 0.5, 0.0, 0.3);
|
||||
outerColor.rgb *= 1.0 + bass * 0.4;
|
||||
color = max(color, outerColor);
|
||||
}
|
||||
}
|
||||
|
||||
// CIRCULAR AUDIO BARS (64 bars, mirrored from 32 audio samples)
|
||||
if (hasBars() && d > innerRadius) {
|
||||
// Double the visual bars by using NBARS * 2
|
||||
float section = TWOPI / float(NBARS * 2);
|
||||
float center = section / 2.0;
|
||||
|
||||
float adjustedTheta = theta + PI + iTime * ubuf.rotationSpeed * 0.2;
|
||||
float m = mod(adjustedTheta, section);
|
||||
float ym = d * sin(center - m);
|
||||
|
||||
float barW = ubuf.barWidth * 0.015;
|
||||
if (abs(ym) < barW) {
|
||||
// Calculate position in the circle (0.0 to 1.0)
|
||||
float circlePos = mod(adjustedTheta, TWOPI) / TWOPI;
|
||||
// Mirror: first half (0-0.5) maps to 0-1, second half (0.5-1) maps back 1-0
|
||||
float mirroredPos = circlePos < 0.5 ? circlePos * 2.0 : (1.0 - circlePos) * 2.0;
|
||||
float v = smoothAudio(mirroredPos);
|
||||
|
||||
float wave = sin(theta * 3.0 + mid * 5.0) * clamp(mid * 0.03, 0.0, 0.05);
|
||||
v += wave;
|
||||
v = max(v, 0.0);
|
||||
|
||||
float barStart = innerRadius;
|
||||
float barEnd = baseRadius + v * 0.5; // Fixed outer extent
|
||||
|
||||
if (d >= barStart && d <= barEnd) {
|
||||
float heightFactor = (d - barStart) / max(barEnd - barStart, 0.001);
|
||||
|
||||
vec3 bottomColor = ubuf.primaryColor.rgb * 0.6;
|
||||
vec3 middleColor = ubuf.primaryColor.rgb;
|
||||
vec3 topColor = ubuf.secondaryColor.rgb;
|
||||
|
||||
vec3 barColor;
|
||||
if (heightFactor < 0.5) {
|
||||
barColor = mix(bottomColor, middleColor, heightFactor * 2.0);
|
||||
} else {
|
||||
barColor = mix(middleColor, topColor, (heightFactor - 0.5) * 2.0);
|
||||
}
|
||||
|
||||
barColor *= 1.0 + bass * 0.4;
|
||||
|
||||
if (heightFactor > 0.85) {
|
||||
barColor += vec3(0.3, 0.4, 0.5) * clamp(treble * 0.8, 0.0, 0.5);
|
||||
}
|
||||
|
||||
float edgeFactor = 1.0 - smoothstep(barW * 0.7, barW, abs(ym));
|
||||
vec4 finalBarColor = vec4(barColor, edgeFactor);
|
||||
color = max(color, finalBarColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
void main() {
|
||||
// ============================================
|
||||
// DYNAMIC CONTENT SCALING
|
||||
// ============================================
|
||||
// Calculate max possible extent from current settings to guarantee
|
||||
// nothing ever reaches the widget border.
|
||||
//
|
||||
// Max visualization radius in centered space [-1,1]:
|
||||
// Bars/Wave: baseRadius(0.35) + sensitivity * 0.5
|
||||
// Rings: innerDiameter/2 + sensitivity * 0.05 (always smaller)
|
||||
//
|
||||
// Bloom reach: exp(-dist * minDecayRate / bloomIntensity) decays to
|
||||
// < 1/255 at dist ≈ bloomIntensity * 1.0 (from solving exp decay
|
||||
// with worst-case amplitude * multiplier chain)
|
||||
//
|
||||
// contentScale maps the widget edge to ±contentScale in centered space,
|
||||
// so setting it to maxTotalRadius ensures everything fits.
|
||||
|
||||
float maxContentRadius = 0.35 + ubuf.sensitivity * 0.5;
|
||||
float maxBloomReach = ubuf.bloomIntensity * 1.0;
|
||||
float maxTotalRadius = maxContentRadius + maxBloomReach;
|
||||
float contentScale = max(maxTotalRadius * 1.05, 1.0); // 5% safety margin
|
||||
|
||||
vec2 uv = (qt_TexCoord0 - 0.5) * contentScale + 0.5;
|
||||
|
||||
// Convert linear time (0-3600) to smooth oscillation for seamless looping
|
||||
// sin() ensures perfect continuity when QML wraps from 3600 back to 0
|
||||
float iTime = sin(ubuf.time * TWOPI / 3600.0) * 1800.0 + 1800.0;
|
||||
|
||||
// Frequency analysis
|
||||
float bass = getBass();
|
||||
float mid = getMid();
|
||||
float highMid = getHighMid();
|
||||
float treble = getTreble();
|
||||
|
||||
// Get base visualization color based on mode
|
||||
// Mode 0: bars only, Mode 1: wave only, Mode 2: rings only
|
||||
// Mode 3: bars+rings, Mode 4: wave+rings, Mode 5: all
|
||||
vec4 color;
|
||||
if (hasWave() && !hasBars()) {
|
||||
// Wave only or wave+rings (modes 1, 4)
|
||||
color = computePolarWave(uv, iTime, bass, mid, highMid, treble);
|
||||
} else if (hasBars() && !hasWave()) {
|
||||
// Bars only or bars+rings (modes 0, 3)
|
||||
color = computeVisualization(uv, iTime, bass, mid, highMid, treble);
|
||||
} else if (hasWave() && hasBars()) {
|
||||
// All mode (5) - combine both
|
||||
vec4 barsColor = computeVisualization(uv, iTime, bass, mid, highMid, treble);
|
||||
vec4 waveColor = computePolarWave(uv, iTime, bass, mid, highMid, treble);
|
||||
color = max(barsColor, waveColor);
|
||||
} else {
|
||||
// Rings only (mode 2) - still need to call one of them for ring rendering
|
||||
color = computeVisualization(uv, iTime, bass, mid, highMid, treble);
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// BLOOM EFFECT - Glow based on distance to geometry
|
||||
// ============================================
|
||||
|
||||
if (ubuf.bloomIntensity > 0.01 && color.a < 0.01) {
|
||||
// Only apply bloom where there's no geometry (empty space)
|
||||
// Find distance to nearest bright element
|
||||
|
||||
float aspect = ubuf.itemWidth / ubuf.itemHeight;
|
||||
vec2 centered = (uv - 0.5) * 2.0;
|
||||
centered.x *= aspect;
|
||||
float d = length(centered);
|
||||
float theta = atan(centered.y, centered.x);
|
||||
|
||||
float innerRadius = ubuf.innerDiameter / 2.0;
|
||||
float baseRadius = 0.35; // Fixed reference for outer extent
|
||||
float glowAmount = 0.0;
|
||||
vec3 glowColor = vec3(0.0);
|
||||
|
||||
// Glow from rings (if enabled)
|
||||
if (hasRings()) {
|
||||
// Outer ring glow
|
||||
float outerRad = innerRadius + bass * 0.05;
|
||||
float ringDist = abs(d - outerRad);
|
||||
float ringGlow = exp(-ringDist * 8.0 / ubuf.bloomIntensity) * (1.0 + bass * 0.5);
|
||||
glowColor += ubuf.primaryColor.rgb * ringGlow;
|
||||
glowAmount = max(glowAmount, ringGlow);
|
||||
|
||||
// Accent ring glow
|
||||
float accentRad = innerRadius * 0.92;
|
||||
float accentDist = abs(d - accentRad);
|
||||
float accentGlow = exp(-accentDist * 10.0 / ubuf.bloomIntensity) * (0.7 + bass * 0.3);
|
||||
glowColor += mix(ubuf.secondaryColor.rgb, ubuf.primaryColor.rgb, 0.5) * accentGlow;
|
||||
glowAmount = max(glowAmount, accentGlow);
|
||||
}
|
||||
|
||||
// Glow from visualization (bars or polar wave)
|
||||
if ((hasBars() || hasWave()) && d > innerRadius * 0.8) {
|
||||
float adjustedTheta = theta + PI + iTime * ubuf.rotationSpeed * 0.2;
|
||||
float circlePos = mod(adjustedTheta, TWOPI) / TWOPI;
|
||||
float mirroredPos = circlePos < 0.5 ? circlePos * 2.0 : (1.0 - circlePos) * 2.0;
|
||||
float v = smoothAudio(mirroredPos);
|
||||
|
||||
if (hasWave()) {
|
||||
// Polar wave bloom - Catmull-Rom spline with mirroring matching main render
|
||||
float mirroredPos = circlePos < 0.5 ? circlePos * 2.0 : (1.0 - circlePos) * 2.0;
|
||||
float bandPos = mirroredPos * float(NBARS - 1);
|
||||
float fband1 = floor(bandPos);
|
||||
float fband0 = max(fband1 - 1.0, 0.0);
|
||||
float fband2 = min(fband1 + 1.0, float(NBARS - 1));
|
||||
float fband3 = min(fband1 + 2.0, float(NBARS - 1));
|
||||
|
||||
float t = fract(bandPos);
|
||||
float p0 = getAudio(fband0 / float(NBARS - 1)) * ubuf.sensitivity;
|
||||
float p1 = getAudio(fband1 / float(NBARS - 1)) * ubuf.sensitivity;
|
||||
float p2 = getAudio(fband2 / float(NBARS - 1)) * ubuf.sensitivity;
|
||||
float p3 = getAudio(fband3 / float(NBARS - 1)) * ubuf.sensitivity;
|
||||
|
||||
float t2 = t * t;
|
||||
float t3 = t2 * t;
|
||||
float smoothedAudio = 0.5 * (
|
||||
(2.0 * p1) +
|
||||
(-p0 + p2) * t +
|
||||
(2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2 +
|
||||
(-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3
|
||||
);
|
||||
smoothedAudio = max(smoothedAudio, 0.0);
|
||||
|
||||
float waveRadius = baseRadius + smoothedAudio * 0.5;
|
||||
|
||||
// Glow from the filled area and edge
|
||||
float distToWave = abs(d - waveRadius);
|
||||
float waveGlow = exp(-distToWave * 8.0 / ubuf.bloomIntensity) * smoothedAudio * 2.5;
|
||||
|
||||
vec3 waveGlowColor = mix(ubuf.primaryColor.rgb, ubuf.secondaryColor.rgb, smoothedAudio);
|
||||
glowColor += waveGlowColor * waveGlow;
|
||||
glowAmount = max(glowAmount, waveGlow);
|
||||
}
|
||||
|
||||
if (hasBars()) {
|
||||
// Bars bloom
|
||||
float section = TWOPI / float(NBARS * 2);
|
||||
float m = mod(adjustedTheta, section);
|
||||
float center = section / 2.0;
|
||||
|
||||
float barAngleDist = min(abs(m - center), section - abs(m - center));
|
||||
float barEnd = baseRadius + v * 0.5; // Fixed outer extent
|
||||
|
||||
float radialDist = 0.0;
|
||||
if (d < innerRadius) {
|
||||
radialDist = innerRadius - d;
|
||||
} else if (d > barEnd) {
|
||||
radialDist = d - barEnd;
|
||||
}
|
||||
|
||||
float totalDist = length(vec2(barAngleDist * d, radialDist));
|
||||
float barGlow = exp(-totalDist * 15.0 / ubuf.bloomIntensity) * v * 2.0;
|
||||
|
||||
float heightFactor = clamp((d - innerRadius) / max(barEnd - innerRadius, 0.001), 0.0, 1.0);
|
||||
vec3 barGlowColor = mix(ubuf.primaryColor.rgb, ubuf.secondaryColor.rgb, heightFactor);
|
||||
|
||||
glowColor += barGlowColor * barGlow;
|
||||
glowAmount = max(glowAmount, barGlow);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply bloom
|
||||
float bloomMult = ubuf.bloomIntensity * (1.0 + bass * 0.5);
|
||||
color.rgb = glowColor * bloomMult;
|
||||
color.a = glowAmount * bloomMult * 0.6;
|
||||
|
||||
// Clamp to reasonable values
|
||||
color.rgb = min(color.rgb, vec3(1.5));
|
||||
color.a = min(color.a, 0.8);
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// EDGE FADE - radial falloff that only affects the bloom zone
|
||||
// ============================================
|
||||
// Fade starts just past where main content ends (maxContentRadius)
|
||||
// and reaches zero at the widget edge (contentScale) in centered space.
|
||||
// This catches bloom tails without affecting the main visualization.
|
||||
|
||||
vec2 fromCenter = (qt_TexCoord0 - 0.5) * 2.0; // -1 to 1 in widget space
|
||||
float edgeProximity = max(abs(fromCenter.x), abs(fromCenter.y)); // box distance
|
||||
float fadeStart = maxContentRadius / contentScale; // where content ends in widget space
|
||||
float edgeFade = 1.0 - smoothstep(fadeStart, 1.0, edgeProximity);
|
||||
color *= edgeFade;
|
||||
|
||||
// ============================================
|
||||
// CORNER MASKING
|
||||
// ============================================
|
||||
|
||||
vec2 pixelPos = qt_TexCoord0 * vec2(ubuf.itemWidth, ubuf.itemHeight);
|
||||
vec2 centerPos = pixelPos - vec2(ubuf.itemWidth, ubuf.itemHeight) * 0.5;
|
||||
vec2 halfSize = vec2(ubuf.itemWidth, ubuf.itemHeight) * 0.5;
|
||||
float dist = roundedBoxSDF(centerPos, halfSize, ubuf.cornerRadius);
|
||||
float cornerMask = 1.0 - smoothstep(-1.0, 0.0, dist);
|
||||
|
||||
// Final output with premultiplied alpha
|
||||
float finalAlpha = color.a * ubuf.qt_Opacity * cornerMask;
|
||||
fragColor = vec4(color.rgb * finalAlpha, finalAlpha);
|
||||
}
|
||||
Reference in New Issue
Block a user