up su Gitea

This commit is contained in:
2026-04-19 17:07:18 +02:00
parent e78ce720bb
commit fe54b28378
298 changed files with 23460 additions and 0 deletions
@@ -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);
}