mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-13 19:44:28 +00:00
gl_engine: Support new radial gradient data struct and calculation
Change the shader and uniform struct to support new radial gradient. The mathematical calculation comes from https://skia.org/docs/dev/design/conical/
This commit is contained in:
parent
159bf6949e
commit
e82830147c
3 changed files with 132 additions and 31 deletions
|
@ -89,9 +89,9 @@ struct GlLinearGradientBlock
|
|||
struct GlRadialGradientBlock
|
||||
{
|
||||
alignas(16) float nStops[4] = {};
|
||||
alignas(16) float centerPos[2] = {};
|
||||
alignas(8) float radius[2] = {};
|
||||
alignas(8) float stopPoints[MAX_GRADIENT_STOPS] = {};
|
||||
alignas(16) float centerPos[4] = {};
|
||||
alignas(16) float radius[2] = {};
|
||||
alignas(16) float stopPoints[MAX_GRADIENT_STOPS] = {};
|
||||
alignas(16) float stopColors[4 * MAX_GRADIENT_STOPS] = {};
|
||||
};
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
*/
|
||||
|
||||
#include "tvgMath.h"
|
||||
#include "tvgFill.h"
|
||||
#include "tvgGlRenderer.h"
|
||||
#include "tvgGlGpuBuffer.h"
|
||||
#include "tvgGlGeometry.h"
|
||||
|
@ -411,12 +412,20 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla
|
|||
}
|
||||
gradientBlock.nStops[0] = nStops * 1.f;
|
||||
|
||||
float x, y, r;
|
||||
radialFill->radial(&x, &y, &r);
|
||||
|
||||
gradientBlock.centerPos[0] = x;
|
||||
gradientBlock.centerPos[1] = y;
|
||||
gradientBlock.radius[0] = r;
|
||||
float x, y, r, fx, fy, fr;
|
||||
x = P(radialFill)->cx;
|
||||
y = P(radialFill)->cy;
|
||||
r = P(radialFill)->r;
|
||||
fx = P(radialFill)->fx;
|
||||
fy = P(radialFill)->fy;
|
||||
fr = P(radialFill)->fr;
|
||||
|
||||
gradientBlock.centerPos[0] = fx;
|
||||
gradientBlock.centerPos[1] = fy;
|
||||
gradientBlock.centerPos[2] = x;
|
||||
gradientBlock.centerPos[3] = y;
|
||||
gradientBlock.radius[0] = fr;
|
||||
gradientBlock.radius[1] = r;
|
||||
|
||||
gradientBinding = GlBindingResource{
|
||||
2,
|
||||
|
|
|
@ -208,31 +208,123 @@ void main()
|
|||
});
|
||||
|
||||
std::string STR_RADIAL_GRADIENT_VARIABLES = TVG_COMPOSE_SHADER(
|
||||
layout(std140) uniform GradientInfo { \n
|
||||
vec4 nStops; \n
|
||||
vec2 centerPos; \n
|
||||
vec2 radius; \n
|
||||
vec4 stopPoints[MAX_STOP_COUNT / 4]; \n
|
||||
vec4 stopColors[MAX_STOP_COUNT]; \n
|
||||
} uGradientInfo ; \n
|
||||
layout(std140) uniform GradientInfo { \n
|
||||
vec4 nStops; \n
|
||||
vec4 centerPos; \n
|
||||
vec2 radius; \n
|
||||
vec4 stopPoints[MAX_STOP_COUNT / 4]; \n
|
||||
vec4 stopColors[MAX_STOP_COUNT]; \n
|
||||
} uGradientInfo ; \n
|
||||
);
|
||||
|
||||
std::string STR_RADIAL_GRADIENT_MAIN = TVG_COMPOSE_SHADER(
|
||||
out vec4 FragColor; \n
|
||||
void main() \n
|
||||
{ \n
|
||||
vec2 pos = vPos; \n
|
||||
\n
|
||||
float ba = uGradientInfo.radius.x; \n
|
||||
float d = distance(uGradientInfo.centerPos, pos); \n
|
||||
float t = (d / ba); \n
|
||||
\n
|
||||
t = gradientWrap(t); \n
|
||||
\n
|
||||
vec4 color = gradient(t, (d / ba), d); \n
|
||||
\n
|
||||
FragColor = vec4(color.rgb * color.a, color.a); \n
|
||||
});
|
||||
out vec4 FragColor; \n
|
||||
\n
|
||||
mat3 radial_matrix(vec2 p0, vec2 p1) \n
|
||||
{ \n
|
||||
mat3 a = mat3(0.0, -1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); \n
|
||||
mat3 b = mat3(p1.y - p0.y, p0.x - p1.x, 0.0, p1.x - p0.x, p1.y - p0.y, 0.0, p0.x, p0.y, 1.0); \n
|
||||
return a * inverse(b); \n
|
||||
} \n
|
||||
\n
|
||||
vec2 compute_radial_t(vec2 c0, float r0, vec2 c1, float r1, vec2 pos) \n
|
||||
{ \n
|
||||
const float scalar_nearly_zero = 1.0 / float(1 << 12); \n
|
||||
float d_center = distance(c0, c1); \n
|
||||
float d_radius = r1 - r0; \n
|
||||
bool radial = d_center < scalar_nearly_zero; \n
|
||||
bool strip = abs(d_radius) < scalar_nearly_zero; \n
|
||||
\n
|
||||
if (radial) { \n
|
||||
if (strip) return vec2(0.0, -1.0); \n
|
||||
\n
|
||||
float scale = 1.0 / d_radius; \n
|
||||
float scale_sign = sign(d_radius); \n
|
||||
float bias = r0 / d_radius; \n
|
||||
vec2 pt = (pos - c0) * scale; \n
|
||||
float t = length(pt) * scale_sign - bias; \n
|
||||
return vec2(t, 1.0); \n
|
||||
} else if (strip) { \n
|
||||
mat3 transform = radial_matrix(c0, c1); \n
|
||||
float r = r0 / d_center; \n
|
||||
float r_2 = r * r; \n
|
||||
vec2 pt = (transform * vec3(pos.xy, 1.0)).xy; \n
|
||||
float t = r_2 - pt.y * pt.y; \n
|
||||
\n
|
||||
if (t < 0.0) return vec2(0.0, -1.0); \n
|
||||
\n
|
||||
t = pt.x + sqrt(t); \n
|
||||
return vec2(t, 1.0); \n
|
||||
} else { \n
|
||||
float f = r0 / (r0 - r1); \n
|
||||
bool is_swapped = abs(f - 1.0) < scalar_nearly_zero; \n
|
||||
if (is_swapped) { \n
|
||||
vec2 c = c0; \n
|
||||
c0 = c1; \n
|
||||
c1 = c; \n
|
||||
f = 0.0; \n
|
||||
} \n
|
||||
vec2 cf = c0 * (1.0 - f) + c1 * f; \n
|
||||
mat3 transform = radial_matrix(cf, c1); \n
|
||||
\n
|
||||
float scale_x = abs(1.0 - f); \n
|
||||
float scale_y = scale_x; \n
|
||||
float r1 = abs(r1 - r0) / d_center; \n
|
||||
bool is_focal_on_circle = abs(r1 - 1.0) < scalar_nearly_zero; \n
|
||||
if (is_focal_on_circle) { \n
|
||||
scale_x *= 0.5; \n
|
||||
scale_y *= 0.5; \n
|
||||
} else { \n
|
||||
scale_x *= r1 / (r1 * r1 - 1.0); \n
|
||||
scale_y /= sqrt(abs(r1 * r1 - 1.0)); \n
|
||||
} \n
|
||||
transform = mat3(scale_x, 0.0, 0.0, 0.0, scale_y, 0.0, 0.0, 0.0, 1.0) * transform; \n
|
||||
\n
|
||||
vec2 pt = (transform * vec3(pos.xy, 1.0)).xy; \n
|
||||
\n
|
||||
float inv_r1 = 1.0 / r1; \n
|
||||
float d_radius_sign = sign(1.0 - f); \n
|
||||
bool is_well_behaved = !is_focal_on_circle && r1 > 1.0; \n
|
||||
\n
|
||||
float x_t = -1.0; \n
|
||||
if (is_focal_on_circle) x_t = dot(pt, pt) / pt.x; \n
|
||||
else if (is_well_behaved) x_t = length(pt) - pt.x * inv_r1; \n
|
||||
else { \n
|
||||
float temp = pt.x * pt.x - pt.y * pt.y; \n
|
||||
if (temp >= 0.0) { \n
|
||||
if (is_swapped || d_radius_sign < 0.0) { \n
|
||||
x_t = -sqrt(temp) - pt.x * inv_r1; \n
|
||||
} else { \n
|
||||
x_t = sqrt(temp) - pt.x * inv_r1; \n
|
||||
} \n
|
||||
} \n
|
||||
} \n
|
||||
\n
|
||||
if (!is_well_behaved && x_t < 0.0) return vec2(0.0, -1.0); \n
|
||||
\n
|
||||
float t = f + d_radius_sign * x_t; \n
|
||||
if (is_swapped) t = 1.0 - t; \n
|
||||
return vec2(t, 1.0); \n
|
||||
} \n
|
||||
} \n
|
||||
\n
|
||||
void main() \n
|
||||
{ \n
|
||||
vec2 pos = vPos; \n
|
||||
vec2 res = compute_radial_t(uGradientInfo.centerPos.xy, \n
|
||||
uGradientInfo.radius.x, \n
|
||||
uGradientInfo.centerPos.zw, \n
|
||||
uGradientInfo.radius.y, \n
|
||||
pos); \n
|
||||
if (res.y < 0.0) { \n
|
||||
FragColor = vec4(0.0, 0.0, 0.0, 0.0); \n
|
||||
return; \n
|
||||
} \n
|
||||
float t = gradientWrap(res.x); \n
|
||||
vec4 color = gradient(t, res.x, length(pos - uGradientInfo.centerPos.xy)); \n
|
||||
FragColor = vec4(color.rgb * color.a, color.a); \n
|
||||
}
|
||||
);
|
||||
|
||||
std::string STR_LINEAR_GRADIENT_FRAG_SHADER =
|
||||
STR_GRADIENT_FRAG_COMMON_VARIABLES +
|
||||
|
|
Loading…
Add table
Reference in a new issue