From 25d43ddacf32f425b9974110f886ded90ecbfbb4 Mon Sep 17 00:00:00 2001 From: RuiwenTang Date: Fri, 19 Apr 2024 17:29:45 +0800 Subject: [PATCH] gl_engine: fix gradient rendering error * Fix error when handle GradientTransform calculation. And move the inv calculation into gradient vertex shader. * Fix cubic tessellation not close the last point --- src/renderer/gl_engine/tvgGlRenderer.cpp | 63 ++++++++++++++++----- src/renderer/gl_engine/tvgGlShaderSrc.cpp | 47 ++++++++------- src/renderer/gl_engine/tvgGlTessellator.cpp | 2 +- 3 files changed, 74 insertions(+), 38 deletions(-) diff --git a/src/renderer/gl_engine/tvgGlRenderer.cpp b/src/renderer/gl_engine/tvgGlRenderer.cpp index 4359023a..3d548a5c 100644 --- a/src/renderer/gl_engine/tvgGlRenderer.cpp +++ b/src/renderer/gl_engine/tvgGlRenderer.cpp @@ -20,6 +20,7 @@ * SOFTWARE. */ +#include "tvgMath.h" #include "tvgGlRenderer.h" #include "tvgGlGpuBuffer.h" #include "tvgGlGeometry.h" @@ -600,6 +601,22 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla // matrix buffer { auto matrix = sdata.geometry->getTransforMatrix(); + + auto gradientTransform = fill->transform(); + float invMat4[16]; + if (!mathIdentity(const_cast(&gradientTransform))) { + Matrix inv{}; + mathInverse(&gradientTransform , &inv); + + GET_MATRIX44(inv, invMat4); + } else { + memset(invMat4, 0, 16 * sizeof(float)); + invMat4[0] = 1.f; + invMat4[5] = 1.f; + invMat4[10] = 1.f; + invMat4[15] = 1.f; + } + uint32_t loc = task->getProgram()->getUniformBlockIndex("Matrix"); uint32_t viewOffset = mGpuBuffer->push(matrix, 16 * sizeof(float), true); @@ -621,6 +638,17 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla 16 * sizeof(float), }); } + + loc = task->getProgram()->getUniformBlockIndex("InvMatrix"); + viewOffset = mGpuBuffer->push(invMat4, 16 * sizeof(float), true); + + task->addBindResource(GlBindingResource{ + 1, + loc, + mGpuBuffer->getBufferId(), + viewOffset, + 16 * sizeof(float), + }); } // gradient block @@ -633,29 +661,31 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla GlLinearGradientBlock gradientBlock; - gradientBlock.nStops[0] = stopCnt * 1.f; gradientBlock.nStops[1] = NOISE_LEVEL; gradientBlock.nStops[2] = static_cast(fill->spread()) * 1.f; + uint32_t nStops = 0; for (uint32_t i = 0; i < stopCnt; ++i) { + if (i > 0 && gradientBlock.stopPoints[nStops - 1] > stops[i].offset) continue; + gradientBlock.stopPoints[i] = stops[i].offset; gradientBlock.stopColors[i * 4 + 0] = stops[i].r / 255.f; gradientBlock.stopColors[i * 4 + 1] = stops[i].g / 255.f; gradientBlock.stopColors[i * 4 + 2] = stops[i].b / 255.f; gradientBlock.stopColors[i * 4 + 3] = stops[i].a / 255.f; + nStops++; } + gradientBlock.nStops[0] = nStops * 1.f; float x1, x2, y1, y2; linearFill->linear(&x1, &y1, &x2, &y2); - auto transform = linearFill->transform(); - - gradientBlock.startPos[0] = x1 * transform.e11 + transform.e13; - gradientBlock.startPos[1] = y1 * transform.e22 + transform.e23; - gradientBlock.stopPos[0] = x2 * transform.e11 + transform.e13; - gradientBlock.stopPos[1] = y2 * transform.e22 + transform.e23; + gradientBlock.startPos[0] = x1; + gradientBlock.startPos[1] = y1; + gradientBlock.stopPos[0] = x2; + gradientBlock.stopPos[1] = y2; gradientBinding = GlBindingResource{ - 1, + 2, loc, mGpuBuffer->getBufferId(), mGpuBuffer->push(&gradientBlock, sizeof(GlLinearGradientBlock), true), @@ -666,28 +696,31 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla GlRadialGradientBlock gradientBlock; - gradientBlock.nStops[0] = stopCnt * 1.f; gradientBlock.nStops[1] = NOISE_LEVEL; gradientBlock.nStops[2] = static_cast(fill->spread()) * 1.f; + + uint32_t nStops = 0; for (uint32_t i = 0; i < stopCnt; ++i) { + if (i > 0 && gradientBlock.stopPoints[nStops - 1] > stops[i].offset) continue; + gradientBlock.stopPoints[i] = stops[i].offset; gradientBlock.stopColors[i * 4 + 0] = stops[i].r / 255.f; gradientBlock.stopColors[i * 4 + 1] = stops[i].g / 255.f; gradientBlock.stopColors[i * 4 + 2] = stops[i].b / 255.f; gradientBlock.stopColors[i * 4 + 3] = stops[i].a / 255.f; + nStops++; } + gradientBlock.nStops[0] = nStops * 1.f; float x, y, r; radialFill->radial(&x, &y, &r); - auto transform = radialFill->transform(); - - gradientBlock.centerPos[0] = x * transform.e11 + transform.e13; - gradientBlock.centerPos[1] = y * transform.e22 + transform.e23; - gradientBlock.radius[0] = r * transform.e11; + gradientBlock.centerPos[0] = x; + gradientBlock.centerPos[1] = y; + gradientBlock.radius[0] = r; gradientBinding = GlBindingResource{ - 1, + 2, loc, mGpuBuffer->getBufferId(), mGpuBuffer->push(&gradientBlock, sizeof(GlRadialGradientBlock), true), diff --git a/src/renderer/gl_engine/tvgGlShaderSrc.cpp b/src/renderer/gl_engine/tvgGlShaderSrc.cpp index 0b67552f..c10e58ef 100644 --- a/src/renderer/gl_engine/tvgGlShaderSrc.cpp +++ b/src/renderer/gl_engine/tvgGlShaderSrc.cpp @@ -52,11 +52,15 @@ out vec2 vPos; layout(std140) uniform Matrix { \n mat4 transform; \n } uMatrix; \n +layout(std140) uniform InvMatrix { \n + mat4 transform; \n +} uInvMatrix; \n \n void main() \n { \n gl_Position = uMatrix.transform * vec4(aLocation, 0.0, 1.0); \n - vPos = aLocation; \n + vec4 pos = uInvMatrix.transform * vec4(aLocation, 0.0, 1.0); \n + vPos = pos.xy / pos.w; \n }); @@ -89,20 +93,23 @@ float gradientWrap(float d) return clamp(d, 0.0, 1.0); \n } \n \n - int i = 1; \n - while (d > 1.0) { \n - d = d - 1.0; \n - i *= -1; \n + if (spread == 1) { /* Reflect */ \n + float n = mod(d, 2.0); \n + if (n > 1.0) \n + { \n + n = 2.0 - n; \n + } \n + return n; \n } \n \n - if (spread == 2) { /* Reflect */ \n - return smoothstep(0.0, 1.0, d); \n + if (spread == 2) { /* Repeat */ \n + float n = mod(d, 1.0); \n + if (n < 0.0) \n + { \n + n += 1.0 + n; \n + } \n + return n; \n } \n - \n - if (i == 1) \n - return smoothstep(0.0, 1.0, d); \n - else \n - return smoothstep(1.0, 0.0, d); \n } \n \n vec4 gradient(float t) \n @@ -112,11 +119,11 @@ vec4 gradient(float t) int count = int(uGradientInfo.nStops[0]); \n if (t <= gradientStop(0)) \n { \n - col += uGradientInfo.stopColors[0]; \n + col = uGradientInfo.stopColors[0]; \n } \n else if (t >= gradientStop(count - 1)) \n { \n - col += uGradientInfo.stopColors[count - 1]; \n + col = uGradientInfo.stopColors[count - 1]; \n } \n else \n { \n @@ -126,7 +133,7 @@ vec4 gradient(float t) float stopi1 = gradientStop(i + 1); \n if (t > stopi && t (stepCount); s++) { + for (uint32_t s = 1; s <= static_cast(stepCount); s++) { auto pt = bezPointAt(curve, step * s); auto currIndex = pushVertex(pt.x, pt.y);