gl_engine: Introduce tint effect for opengl renderer

issue: https://github.com/thorvg/thorvg/issues/3054
This commit is contained in:
Sergii Liebodkin 2025-04-09 10:31:11 +00:00 committed by Hermet Park
parent 85e215a294
commit 95f1b84a56
6 changed files with 51 additions and 5 deletions

View file

@ -210,6 +210,7 @@ struct GlGaussianBlur {
struct GlEffectParams { struct GlEffectParams {
// fill: [0..3]: color // fill: [0..3]: color
// tint: [0..2]: black, [4..6]: white, [8]: intensity
float params[4+4+4]; float params[4+4+4];
}; };

View file

@ -447,7 +447,7 @@ void GlEffectColorTransformTask::run()
GL_CHECK(glViewport(0, 0, width, height)); GL_CHECK(glViewport(0, 0, width, height));
GL_CHECK(glScissor(0, 0, width, height)); GL_CHECK(glScissor(0, 0, width, height));
// we need to make full copy of dst to intermediate buffers to be sure, that they are not contained prev data // we need to make full copy of dst to intermidiate buffers to be shure, that they are not containe prev data
GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, mDstFbo->getFboId())); GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, mDstFbo->getFboId()));
GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDstCopyFbo->getResolveFboId())); GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDstCopyFbo->getResolveFboId()));
GL_CHECK(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST)); GL_CHECK(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST));

View file

@ -145,6 +145,7 @@ void GlRenderer::initShaders()
mPrograms.push(new GlProgram(EFFECT_VERTEX, GAUSSIAN_VERTICAL)); mPrograms.push(new GlProgram(EFFECT_VERTEX, GAUSSIAN_VERTICAL));
mPrograms.push(new GlProgram(EFFECT_VERTEX, GAUSSIAN_HORIZONTAL)); mPrograms.push(new GlProgram(EFFECT_VERTEX, GAUSSIAN_HORIZONTAL));
mPrograms.push(new GlProgram(EFFECT_VERTEX, EFFECT_FILL)); mPrograms.push(new GlProgram(EFFECT_VERTEX, EFFECT_FILL));
mPrograms.push(new GlProgram(EFFECT_VERTEX, EFFECT_TINT));
} }
@ -975,6 +976,24 @@ void GlRenderer::effectFillUpdate(RenderEffectFill* effect, const Matrix& transf
} }
void GlRenderer::effectTintUpdate(RenderEffectTint* effect, const Matrix& transform)
{
auto params = (GlEffectParams*)effect->rd;
if (!params) params = tvg::malloc<GlEffectParams*>(sizeof(GlEffectParams));
params->params[0] = effect->black[0] / 255.0f;
params->params[1] = effect->black[1] / 255.0f;
params->params[2] = effect->black[2] / 255.0f;
params->params[3] = 0.0f;
params->params[4] = effect->white[0] / 255.0f;
params->params[5] = effect->white[1] / 255.0f;
params->params[6] = effect->white[2] / 255.0f;
params->params[7] = 0.0f;
params->params[8] = effect->intensity / 255.0f;
effect->rd = params;
effect->valid = true;
}
bool GlRenderer::effectGaussianBlurRegion(RenderEffectGaussianBlur* effect) bool GlRenderer::effectGaussianBlurRegion(RenderEffectGaussianBlur* effect)
{ {
auto gaussianBlur = (GlGaussianBlur*)effect->rd; auto gaussianBlur = (GlGaussianBlur*)effect->rd;
@ -999,6 +1018,7 @@ void GlRenderer::prepare(RenderEffect* effect, const Matrix& transform)
switch (effect->type) { switch (effect->type) {
case SceneEffect::GaussianBlur: effectGaussianBlurUpdate(static_cast<RenderEffectGaussianBlur*>(effect), transform); break; case SceneEffect::GaussianBlur: effectGaussianBlurUpdate(static_cast<RenderEffectGaussianBlur*>(effect), transform); break;
case SceneEffect::Fill: effectFillUpdate(static_cast<RenderEffectFill*>(effect), transform); break; case SceneEffect::Fill: effectFillUpdate(static_cast<RenderEffectFill*>(effect), transform); break;
case SceneEffect::Tint: effectTintUpdate(static_cast<RenderEffectTint*>(effect), transform); break;
default: break; default: break;
} }
effect->valid = true; effect->valid = true;
@ -1010,6 +1030,7 @@ bool GlRenderer::region(RenderEffect* effect)
switch (effect->type) { switch (effect->type) {
case SceneEffect::GaussianBlur: return effectGaussianBlurRegion(static_cast<RenderEffectGaussianBlur*>(effect)); case SceneEffect::GaussianBlur: return effectGaussianBlurRegion(static_cast<RenderEffectGaussianBlur*>(effect));
case SceneEffect::Fill: return true; case SceneEffect::Fill: return true;
case SceneEffect::Tint: return true;
default: return false; default: return false;
} }
return false; return false;
@ -1058,9 +1079,10 @@ bool GlRenderer::render(TVG_UNUSED RenderCompositor* cmp, const RenderEffect* ef
// add task to render pipeline // add task to render pipeline
pass->addRenderTask(gaussianTask); pass->addRenderTask(gaussianTask);
} // effect fill } // effect fill
else if (effect->type == SceneEffect::Fill) { else if ((effect->type == SceneEffect::Fill) || (effect->type == SceneEffect::Tint)) {
GlProgram* program{}; GlProgram* program{};
if (effect->type == SceneEffect::Fill) program = mPrograms[RT_EffectFill]; if (effect->type == SceneEffect::Fill) program = mPrograms[RT_EffectFill];
else if (effect->type == SceneEffect::Tint) program = mPrograms[RT_EffectTint];
// get current and intermidiate framebuffers // get current and intermidiate framebuffers
auto dstFbo = pass->getFbo(); auto dstFbo = pass->getFbo();
auto dstCopyFbo = mBlendPool[0]->getRenderTarget(vp); auto dstCopyFbo = mBlendPool[0]->getRenderTarget(vp);

View file

@ -125,6 +125,7 @@ private:
void effectGaussianBlurUpdate(RenderEffectGaussianBlur* effect, const Matrix& transform); void effectGaussianBlurUpdate(RenderEffectGaussianBlur* effect, const Matrix& transform);
void effectFillUpdate(RenderEffectFill* effect, const Matrix& transform); void effectFillUpdate(RenderEffectFill* effect, const Matrix& transform);
void effectTintUpdate(RenderEffectTint* effect, const Matrix& transform);
bool effectGaussianBlurRegion(RenderEffectGaussianBlur* effect); bool effectGaussianBlurRegion(RenderEffectGaussianBlur* effect);

View file

@ -776,7 +776,7 @@ void main()
for (int y = -radius; y <= radius; ++y) { for (int y = -radius; y <= radius; ++y) {
float weight = gaussian(float(y), sigma); float weight = gaussian(float(y), sigma);
vec2 offset = vec2(0.0, float(y) * texelSize.y); vec2 offset = min(vec2(1.0), vec2(0.0, float(y) * texelSize.y));
colorSum += texture(uSrcTexture, vUV + offset) * weight; colorSum += texture(uSrcTexture, vUV + offset) * weight;
weightSum += weight; weightSum += weight;
} }
@ -812,7 +812,8 @@ void main()
for (int y = -radius; y <= radius; ++y) { for (int y = -radius; y <= radius; ++y) {
float weight = gaussian(float(y), sigma); float weight = gaussian(float(y), sigma);
vec2 offset = vec2(float(y) * texelSize.x, 0.0); //vec2 offset = vec2(float(y) * texelSize.x, 0.0);
vec2 offset = min(vec2(1.0), vec2(float(y) * texelSize.x, 0.0));
colorSum += texture(uSrcTexture, vUV + offset) * weight; colorSum += texture(uSrcTexture, vUV + offset) * weight;
weightSum += weight; weightSum += weight;
} }
@ -837,3 +838,23 @@ void main()
FragColor = fill * orig.a * fill.a; FragColor = fill * orig.a * fill.a;
} }
)"; )";
const char* EFFECT_TINT = R"(
uniform sampler2D uSrcTexture;
layout(std140) uniform Params {
vec4 params[3];
} uParams;
in vec2 vUV;
out vec4 FragColor;
void main()
{
vec4 orig = texture(uSrcTexture, vUV);
float luma = dot(orig.rgb, vec3(0.2125, 0.7154, 0.0721));
vec4 black = uParams.params[0];
vec4 white = uParams.params[1];
float intens = uParams.params[2].r;
FragColor = mix(orig, mix(white, black, luma), intens) * orig.a;
}
)";

View file

@ -58,5 +58,6 @@ extern const char* EFFECT_VERTEX;
extern const char* GAUSSIAN_VERTICAL; extern const char* GAUSSIAN_VERTICAL;
extern const char* GAUSSIAN_HORIZONTAL; extern const char* GAUSSIAN_HORIZONTAL;
extern const char* EFFECT_FILL; extern const char* EFFECT_FILL;
extern const char* EFFECT_TINT;
#endif /* _TVG_GL_SHADERSRC_H_ */ #endif /* _TVG_GL_SHADERSRC_H_ */