#version 450 layout(location = 0) in vec2 qt_TexCoord0; layout(location = 0) out vec4 fragColor; layout(binding = 1) uniform sampler2D dataSource; layout(std140, binding = 0) uniform buf { mat4 qt_Matrix; float qt_Opacity; vec4 fillColor; float count; float texWidth; float vertical; float mirrored; }; // Sample amplitude from data texture (R channel) float fetchData(float idx) { float i = clamp(idx, 0.0, texWidth - 1.0); float u = (floor(i) + 0.5) / texWidth; return texture(dataSource, vec2(u, 0.5)).r; } // Cubic Hermite interpolation for smooth wave curves float cubicHermite(float y0, float y1, float y2, float y3, float t) { float m1 = (y2 - y0) * 0.25; float m2 = (y3 - y1) * 0.25; float t2 = t * t; float t3 = t2 * t; return (2.0 * t3 - 3.0 * t2 + 1.0) * y1 + (t3 - 2.0 * t2 + t) * m1 + (-2.0 * t3 + 3.0 * t2) * y2 + (t3 - t2) * m2; } // Evaluate interpolated amplitude at fractional data index float evalCurve(float dataIdx) { float i = floor(dataIdx); float t = dataIdx - i; return cubicHermite( fetchData(i - 1.0), fetchData(i), fetchData(i + 1.0), fetchData(i + 2.0), t ); } void main() { vec2 uv = qt_TexCoord0; // Swap axes for vertical mode float axisPos = (vertical > 0.5) ? uv.y : uv.x; float crossPos = (vertical > 0.5) ? uv.x : uv.y; // Map axis position to data index float dataIdx; if (mirrored > 0.5) { // Mirror: value[0] at center, value[count-1] at edges float distFromCenter = abs(axisPos - 0.5) * 2.0; dataIdx = distFromCenter * max(count - 1.0, 1.0); } else { // Linear: value[0] at left/top, value[count-1] at right/bottom dataIdx = axisPos * max(count - 1.0, 1.0); } // Interpolated amplitude, clamped to valid range float amplitude = clamp(evalCurve(dataIdx), 0.0, 1.0); // Wave fills center ± amplitude/2 in the cross axis float halfAmp = amplitude * 0.5; float distFromMid = abs(crossPos - 0.5); // Antialiased edge (~1px smooth transition) float edge = fwidth(crossPos) * 1.5; float mask = smoothstep(halfAmp + edge, halfAmp - edge, distFromMid); // Premultiplied alpha output float a = mask * fillColor.a; fragColor = vec4(fillColor.rgb * a, a) * qt_Opacity; }