Revision control

Copy as Markdown

// 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 texCoordDerivative;
#if defined(LINEARGRADIENT)
layout(location = 2) in float gradTabIndex;
#elif defined(RADIALGRADIENT) || defined(CONICALGRADIENT)
layout(location = 2) in vec2 coord;
#elif defined(TEXTUREFILL)
layout(location = 2) in vec2 textureCoord;
#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) || defined(RADIALGRADIENT) || defined(CONICALGRADIENT) || defined(TEXTUREFILL)
mat4 gradientMatrix;
#endif
#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;
#elif defined(TEXTUREFILL)
vec2 boundsSize;
#else
vec4 color;
#endif
} ubuf;
#define INVERSE_2PI 0.1591549430918953358
#if defined(LINEARGRADIENT) || defined(RADIALGRADIENT) || defined(CONICALGRADIENT)
layout(binding = 1) uniform sampler2D gradTabTexture;
#elif defined(TEXTUREFILL)
layout(binding = 1) uniform sampler2D sourceTexture;
#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));
#elif defined(TEXTUREFILL)
return texture(sourceTexture, textureCoord);
#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 = texCoordDerivative.x;
float dvdx = texCoordDerivative.y;
float dudy = texCoordDerivative.z;
float dvdy = texCoordDerivative.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;
}