diff options
Diffstat (limited to 'src/quick/scenegraph/shaders_ng/shapecurve.frag')
-rw-r--r-- | src/quick/scenegraph/shaders_ng/shapecurve.frag | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/src/quick/scenegraph/shaders_ng/shapecurve.frag b/src/quick/scenegraph/shaders_ng/shapecurve.frag new file mode 100644 index 0000000000..bd0d02b73b --- /dev/null +++ b/src/quick/scenegraph/shaders_ng/shapecurve.frag @@ -0,0 +1,142 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#version 440 + +layout(location = 0) in vec4 qt_TexCoord; +layout(location = 1) in vec4 gradient; + +#if defined(LINEARGRADIENT) +layout(location = 2) in float gradTabIndex; +#elif defined(RADIALGRADIENT) || defined(CONICALGRADIENT) +layout(location = 2) in vec2 coord; +#endif + + +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { +#if QSHADER_VIEW_COUNT >= 2 + mat4 qt_Matrix[QSHADER_VIEW_COUNT]; +#else + mat4 qt_Matrix; +#endif + float matrixScale; + float opacity; + float debug; + float reserved3; + +#if defined(LINEARGRADIENT) + vec2 gradientStart; + vec2 gradientEnd; +#elif defined(RADIALGRADIENT) + vec2 translationPoint; + vec2 focalToCenter; + float centerRadius; + float focalRadius; +#elif defined(CONICALGRADIENT) + vec2 translationPoint; + float angle; +#else + vec4 color; +#endif +} ubuf; + +#define INVERSE_2PI 0.1591549430918953358 + +#if defined(LINEARGRADIENT) || defined(RADIALGRADIENT) || defined(CONICALGRADIENT) +layout(binding = 1) uniform sampler2D gradTabTexture; +#endif + +vec4 baseColor() +{ +#if defined(LINEARGRADIENT) + return texture(gradTabTexture, vec2(gradTabIndex, 0.5)); +#elif defined(RADIALGRADIENT) + float rd = ubuf.centerRadius - ubuf.focalRadius; + float b = 2.0 * (rd * ubuf.focalRadius + dot(coord, ubuf.focalToCenter)); + float fmp2_m_radius2 = -ubuf.focalToCenter.x * ubuf.focalToCenter.x - ubuf.focalToCenter.y * ubuf.focalToCenter.y + rd * rd; + float inverse_2_fmp2_m_radius2 = 1.0 / (2.0 * fmp2_m_radius2); + float det = b * b - 4.0 * fmp2_m_radius2 * ((ubuf.focalRadius * ubuf.focalRadius) - dot(coord, coord)); + vec4 result = vec4(0.0); + if (det >= 0.0) { + float detSqrt = sqrt(det); + float w = max((-b - detSqrt) * inverse_2_fmp2_m_radius2, (-b + detSqrt) * inverse_2_fmp2_m_radius2); + if (ubuf.focalRadius + w * (ubuf.centerRadius - ubuf.focalRadius) >= 0.0) + result = texture(gradTabTexture, vec2(w, 0.5)); + } + + return result; +#elif defined(CONICALGRADIENT) + float t; + if (abs(coord.y) == abs(coord.x)) + t = (atan(-coord.y + 0.002, coord.x) + ubuf.angle) * INVERSE_2PI; + else + t = (atan(-coord.y, coord.x) + ubuf.angle) * INVERSE_2PI; + return texture(gradTabTexture, vec2(t - floor(t), 0.5)); +#else + return vec4(ubuf.color.rgb, 1.0) * ubuf.color.a; +#endif +} + +void main() +{ + float f = qt_TexCoord.z * (qt_TexCoord.x * qt_TexCoord.x - qt_TexCoord.y) // curve + + (1.0 - abs(qt_TexCoord.z)) * (qt_TexCoord.x - qt_TexCoord.y); // line + +#if defined(USE_DERIVATIVES) + float _ddx = dFdx(f); + float _ddy = dFdy(f); + float df = length(vec2(_ddx, _ddy)); +#else + // We calculate the partial derivatives for f'(x, y) based on knowing the partial derivatives + // for the texture coordinates (u, v). + // So for curves: + // f(x,y) = u(x, y) * u(x, y) - v(x, y) + // f(x,y) = p(u(x,y)) - v(x, y) where p(u) = u^2 + // So f'(x, y) = p'(u(x, y)) * u'(x, y) - v'(x, y) + // (by chain rule and sum rule) + // f'(x, y) = 2 * u(x, y) * u'(x, y) - v'(x, y) + // And so: + // df/dx = 2 * u(x, y) * du/dx - dv/dx + // df/dy = 2 * u(x, y) * du/dy - dv/dy + // + // and similarly for straight lines: + // f(x, y) = u(x, y) - v(x, y) + // f'(x, y) = dudx - dvdx + + float dudx = gradient.x; + float dvdx = gradient.y; + float dudy = gradient.z; + float dvdy = gradient.w; + + // Test with analytic derivatives +// dudx = dFdx(qt_TexCoord.x); +// dvdx = dFdx(qt_TexCoord.y); +// dudy = dFdy(qt_TexCoord.x); +// dvdy = dFdy(qt_TexCoord.y); + + float dfx_curve = 2.0f * qt_TexCoord.x * dudx - dvdx; + float dfy_curve = 2.0f * qt_TexCoord.x * dudy - dvdy; + + float dfx_line = dudx - dvdx; + float dfy_line = dudy - dvdy; + + float dfx = qt_TexCoord.z * dfx_curve + (1.0 - abs(qt_TexCoord.z)) * dfx_line; + float dfy = qt_TexCoord.z * dfy_curve + (1.0 - abs(qt_TexCoord.z)) * dfy_line; + float df = length(vec2(dfx, dfy)); +#endif + + float isLine = 1.0 - abs(qt_TexCoord.z); + float isCurve = 1.0 - isLine; + float debugR = isCurve * min(1.0, 1.0 - qt_TexCoord.z); + float debugG = isLine; + float debugB = isCurve * min(1.0, 1.0 - qt_TexCoord.z * -1.0) + debugG; + vec3 debugColor = vec3(debugR, debugG, debugB); + + // Special case: mask out concave curve in "negative space". + int specialCaseMask = 1 - int(qt_TexCoord.w != 0.0) * (int(qt_TexCoord.x < 0.0) + int(qt_TexCoord.x > 1.0)); + float fillCoverage = clamp(0.5 + f / df, 0.0, 1.0) * float(specialCaseMask); + + fragColor = mix(baseColor() * fillCoverage, vec4(debugColor, 1.0), ubuf.debug) * ubuf.opacity; +} |