diff --git a/examples/SceneEffects.cpp b/examples/SceneEffects.cpp index 6aa6b0ac..99825cd1 100644 --- a/examples/SceneEffects.cpp +++ b/examples/SceneEffects.cpp @@ -115,9 +115,9 @@ struct UserExample : tvgexam::Example tint->push(tvg::SceneEffect::ClearAll); tint->push(tvg::SceneEffect::Tint, 0, 0, 0, 0, (int)(progress * 255), 0, (double)(progress * 100.0f)); - //Apply Trintone post effect (shadow:rgb, midtone:rgb, highlight:rgb) + //Apply Tritone post effect (shadow:rgb, midtone:rgb, highlight:rgb, blending with original) trintone->push(tvg::SceneEffect::ClearAll); - trintone->push(tvg::SceneEffect::Tritone, 0, (int)(progress * 255), 0, 199, 110, 36, 255, 255, 255); + trintone->push(tvg::SceneEffect::Tritone, 0, (int)(progress * 255), 0, 199, 110, 36, 255, 255, 255, 0); canvas->update(); diff --git a/inc/thorvg.h b/inc/thorvg.h index d962e84b..25231ce1 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -233,9 +233,9 @@ enum class SceneEffect : uint8_t ClearAll = 0, ///< Reset all previously applied scene effects, restoring the scene to its original state. GaussianBlur, ///< Apply a blur effect with a Gaussian filter. Param(4) = {sigma(double)[> 0], direction(int)[both: 0 / horizontal: 1 / vertical: 2], border(int)[duplicate: 0 / wrap: 1], quality(int)[0 - 100]} DropShadow, ///< Apply a drop shadow effect with a Gaussian Blur filter. Param(8) = {color_R(int)[0 - 255], color_G(int)[0 - 255], color_B(int)[0 - 255], opacity(int)[0 - 255], angle(double)[0 - 360], distance(double), blur_sigma(double)[> 0], quality(int)[0 - 100]} - Fill, ///< Override the scene content color with a given fill information (Experimental API). Param(4) = {color_R(int)[0 - 255], color_G(int)[0 - 255], color_B(int)[0 - 255], opacity(int)[0 - 255]} - Tint, ///< Tinting the current scene color with a given black, white color parameters (Experimental API). Param(7) = {black_R(int)[0 - 255], black_G(int)[0 - 255], black_B(int)[0 - 255], white_R(int)[0 - 255], white_G(int)[0 - 255], white_B(int)[0 - 255], intensity(double)[0 - 100]} - Tritone ///< Apply a tritone color effect to the scene using three color parameters for shadows, midtones, and highlights (Experimental API). Param(9) = {Shadow_R(int)[0 - 255], Shadow_G(int)[0 - 255], Shadow_B(int)[0 - 255], Midtone_R(int)[0 - 255], Midtone_G(int)[0 - 255], Midtone_B(int)[0 - 255], Highlight_R(int)[0 - 255], Highlight_G(int)[0 - 255], Highlight_B(int)[0 - 255]} + Fill, ///< Override the scene content color with a given fill information. Param(4) = {color_R(int)[0 - 255], color_G(int)[0 - 255], color_B(int)[0 - 255], opacity(int)[0 - 255]} + Tint, ///< Tinting the current scene color with a given black, white color parameters. Param(7) = {black_R(int)[0 - 255], black_G(int)[0 - 255], black_B(int)[0 - 255], white_R(int)[0 - 255], white_G(int)[0 - 255], white_B(int)[0 - 255], intensity(double)[0 - 100]} + Tritone ///< Apply a tritone color effect to the scene using three color parameters for shadows, midtones, and highlights. A blending factor determines the mix between the original color and the tritone colors. Param(9) = {Shadow_R(int)[0 - 255], Shadow_G(int)[0 - 255], Shadow_B(int)[0 - 255], Midtone_R(int)[0 - 255], Midtone_G(int)[0 - 255], Midtone_B(int)[0 - 255], Highlight_R(int)[0 - 255], Highlight_G(int)[0 - 255], Highlight_B(int)[0 - 255], Blend(int)[0 - 255]} }; diff --git a/src/bindings/capi/thorvg_capi.h b/src/bindings/capi/thorvg_capi.h index d700f27a..207e5a33 100644 --- a/src/bindings/capi/thorvg_capi.h +++ b/src/bindings/capi/thorvg_capi.h @@ -2091,10 +2091,11 @@ TVG_API Tvg_Result tvg_scene_push_effect_tint(Tvg_Paint* scene, int black_r, int * @param[in] highlight_r Red component of the highlight color [0 - 255]. * @param[in] highlight_g Green component of the highlight color [0 - 255]. * @param[in] highlight_b Blue component of the highlight color [0 - 255]. + * @param[in] blend A blending factor that determines the mix between the original color and the tritone colors [0 - 255]. * * @since 1.0 */ -TVG_API Tvg_Result tvg_scene_push_effect_tritone(Tvg_Paint* scene, int shadow_r, int shadow_g, int shadow_b, int midtone_r, int midtone_g, int midtone_b, int highlight_r, int highlight_g, int highlight_b); +TVG_API Tvg_Result tvg_scene_push_effect_tritone(Tvg_Paint* scene, int shadow_r, int shadow_g, int shadow_b, int midtone_r, int midtone_g, int midtone_b, int highlight_r, int highlight_g, int highlight_b, int blend); /** \} */ // end defgroup ThorVGCapi_Scene diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index 4b8dc5e1..737b95e1 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -813,9 +813,9 @@ TVG_API Tvg_Result tvg_scene_push_effect_tint(Tvg_Paint* scene, int black_r, int } -TVG_API Tvg_Result tvg_scene_push_effect_tritone(Tvg_Paint* scene, int shadow_r, int shadow_g, int shadow_b, int midtone_r, int midtone_g, int midtone_b, int highlight_r, int highlight_g, int highlight_b) +TVG_API Tvg_Result tvg_scene_push_effect_tritone(Tvg_Paint* scene, int shadow_r, int shadow_g, int shadow_b, int midtone_r, int midtone_g, int midtone_b, int highlight_r, int highlight_g, int highlight_b, int blend) { - if (scene) return (Tvg_Result) reinterpret_cast(scene)->push(SceneEffect::Tritone, shadow_r, shadow_g, shadow_b, midtone_r, midtone_g, midtone_b, highlight_r, highlight_g, highlight_b); + if (scene) return (Tvg_Result) reinterpret_cast(scene)->push(SceneEffect::Tritone, shadow_r, shadow_g, shadow_b, midtone_r, midtone_g, midtone_b, highlight_r, highlight_g, highlight_b, blend); return TVG_RESULT_INVALID_ARGUMENT; } diff --git a/src/loaders/lottie/tvgLottieBuilder.cpp b/src/loaders/lottie/tvgLottieBuilder.cpp index 2d5eb857..d0c44088 100644 --- a/src/loaders/lottie/tvgLottieBuilder.cpp +++ b/src/loaders/lottie/tvgLottieBuilder.cpp @@ -1343,7 +1343,7 @@ void LottieBuilder::updateEffect(LottieLayer* layer, float frameNo) auto dark = effect->dark(frameNo); auto midtone = effect->midtone(frameNo); auto bright = effect->bright(frameNo); - layer->scene->push(SceneEffect::Tritone, dark.rgb[0], dark.rgb[1], dark.rgb[2], midtone.rgb[0], midtone.rgb[1], midtone.rgb[2], bright.rgb[0], bright.rgb[1], bright.rgb[2]); + layer->scene->push(SceneEffect::Tritone, dark.rgb[0], dark.rgb[1], dark.rgb[2], midtone.rgb[0], midtone.rgb[1], midtone.rgb[2], bright.rgb[0], bright.rgb[1], bright.rgb[2], (int)effect->blend(frameNo)); break; } case LottieEffect::DropShadow: { diff --git a/src/loaders/lottie/tvgLottieModel.h b/src/loaders/lottie/tvgLottieModel.h index 6f54132b..8a7b4fe4 100644 --- a/src/loaders/lottie/tvgLottieModel.h +++ b/src/loaders/lottie/tvgLottieModel.h @@ -204,6 +204,7 @@ struct LottieFxTritone : LottieEffect LottieColor bright; LottieColor midtone; LottieColor dark; + LottieOpacity blend; LottieFxTritone() { diff --git a/src/loaders/lottie/tvgLottieParser.cpp b/src/loaders/lottie/tvgLottieParser.cpp index 54a3e381..7b08ed00 100644 --- a/src/loaders/lottie/tvgLottieParser.cpp +++ b/src/loaders/lottie/tvgLottieParser.cpp @@ -1338,6 +1338,7 @@ void LottieParser::parseTritone(LottieEffect* effect, int idx) if (idx == 0) parsePropertyInternal(tritone->bright); else if (idx == 1) parsePropertyInternal(tritone->midtone); else if (idx == 2) parsePropertyInternal(tritone->dark); + else if (idx == 3) parsePropertyInternal(tritone->blend); else skip(); } diff --git a/src/renderer/gl_engine/tvgGlCommon.h b/src/renderer/gl_engine/tvgGlCommon.h index 547d69ce..44695a2e 100644 --- a/src/renderer/gl_engine/tvgGlCommon.h +++ b/src/renderer/gl_engine/tvgGlCommon.h @@ -177,7 +177,7 @@ struct GlDropShadow: GlGaussianBlur { struct GlEffectParams { // fill: [0..3]: color // tint: [0..2]: black, [4..6]: white, [8]: intensity - // tritone: [0..2]: shadow, [4..6]: midtone, [8..10]: highlight + // tritone: [0..2]: shadow, [4..6]: midtone, [8..10]: highlight [11]: blender float params[4+4+4]; }; diff --git a/src/renderer/gl_engine/tvgGlRenderer.cpp b/src/renderer/gl_engine/tvgGlRenderer.cpp index 5f72f1e9..e6b5c83d 100644 --- a/src/renderer/gl_engine/tvgGlRenderer.cpp +++ b/src/renderer/gl_engine/tvgGlRenderer.cpp @@ -1001,6 +1001,9 @@ void GlRenderer::effectFillUpdate(RenderEffectFill* effect, const Matrix& transf void GlRenderer::effectTintUpdate(RenderEffectTint* effect, const Matrix& transform) { + effect->valid = (effect->intensity > 0); + if (!effect->valid) return; + auto params = (GlEffectParams*)effect->rd; if (!params) params = tvg::malloc(sizeof(GlEffectParams)); params->params[0] = effect->black[0] / 255.0f; @@ -1013,12 +1016,14 @@ void GlRenderer::effectTintUpdate(RenderEffectTint* effect, const Matrix& transf params->params[7] = 0.0f; params->params[8] = effect->intensity / 255.0f; effect->rd = params; - effect->valid = (effect->intensity > 0); } void GlRenderer::effectTritoneUpdate(RenderEffectTritone* effect, const Matrix& transform) { + effect->valid = (effect->blender < 255); + if (!effect->valid) return; + auto params = (GlEffectParams*)effect->rd; if (!params) params = tvg::malloc(sizeof(GlEffectParams)); params->params[0] = effect->shadow[0] / 255.0f; @@ -1032,9 +1037,8 @@ void GlRenderer::effectTritoneUpdate(RenderEffectTritone* effect, const Matrix& params->params[8] = effect->highlight[0] / 255.0f; params->params[9] = effect->highlight[1] / 255.0f; params->params[10] = effect->highlight[2] / 255.0f; - params->params[11] = 0.0f; + params->params[11] = effect->blender / 255.0f; effect->rd = params; - effect->valid = true; } diff --git a/src/renderer/gl_engine/tvgGlShaderSrc.cpp b/src/renderer/gl_engine/tvgGlShaderSrc.cpp index fe4dc1e9..1126fb69 100644 --- a/src/renderer/gl_engine/tvgGlShaderSrc.cpp +++ b/src/renderer/gl_engine/tvgGlShaderSrc.cpp @@ -889,11 +889,15 @@ void main() vec4 midtone = uParams.params[1]; vec4 highlight = uParams.params[2]; - FragColor = vec4( + vec4 tmp = vec4( luma >= 0.5f ? mix(midtone.r, highlight.r, (luma - 0.5f)*2.0f) : mix(shadow.r, midtone.r, luma * 2.0f), luma >= 0.5f ? mix(midtone.g, highlight.g, (luma - 0.5f)*2.0f) : mix(shadow.g, midtone.g, luma * 2.0f), luma >= 0.5f ? mix(midtone.b, highlight.b, (luma - 0.5f)*2.0f) : mix(shadow.b, midtone.b, luma * 2.0f), luma >= 0.5f ? mix(midtone.a, highlight.a, (luma - 0.5f)*2.0f) : mix(shadow.a, midtone.a, luma * 2.0f) - ) * orig.a; + ); + + //blender + if (highlight.a > 0.0f) tmp = mix(tmp, orig, highlight.a); + FragColor = tmp * orig.a; } )"; diff --git a/src/renderer/sw_engine/tvgSwPostEffect.cpp b/src/renderer/sw_engine/tvgSwPostEffect.cpp index 6373ec9e..9ffc7296 100644 --- a/src/renderer/sw_engine/tvgSwPostEffect.cpp +++ b/src/renderer/sw_engine/tvgSwPostEffect.cpp @@ -540,7 +540,7 @@ static uint32_t _trintone(uint32_t s, uint32_t m, uint32_t h, int l) void effectTritoneUpdate(RenderEffectTritone* params) { - params->valid = true; + params->valid = (params->blender < 255); } @@ -555,7 +555,7 @@ bool effectTritone(SwCompositor* cmp, const RenderEffectTritone* params, bool di auto opacity = cmp->opacity; auto luma = cmp->recoverSfc->alphas[2]; //luma function - TVGLOG("SW_ENGINE", "Tritone region(%d, %d, %d, %d), param(%d %d %d, %d %d %d, %d %d %d)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->shadow[0], params->shadow[1], params->shadow[2], params->midtone[0], params->midtone[1], params->midtone[2], params->highlight[0], params->highlight[1], params->highlight[2]); + TVGLOG("SW_ENGINE", "Tritone region(%d, %d, %d, %d), param(%d %d %d, %d %d %d, %d %d %d, %d)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->shadow[0], params->shadow[1], params->shadow[2], params->midtone[0], params->midtone[1], params->midtone[2], params->highlight[0], params->highlight[1], params->highlight[2], params->blender); if (direct) { auto dbuffer = cmp->recoverSfc->buf32 + (bbox.min.y * cmp->recoverSfc->stride + bbox.min.x); @@ -563,9 +563,14 @@ bool effectTritone(SwCompositor* cmp, const RenderEffectTritone* params, bool di for (size_t y = 0; y < h; ++y) { auto dst = dbuffer; auto src = sbuffer; - for (size_t x = 0; x < w; ++x, ++dst, ++src) { - auto tmp = rasterUnpremultiply(*src); - *dst = INTERPOLATE(_trintone(shadow, midtone, highlight, luma((uint8_t*)&tmp)), *dst, MULTIPLY(opacity, A(tmp))); + if (params->blender == 0) { + for (size_t x = 0; x < w; ++x, ++dst, ++src) { + *dst = INTERPOLATE(_trintone(shadow, midtone, highlight, luma((uint8_t*)src)), *dst, MULTIPLY(opacity, A(*src))); + } + } else { + for (size_t x = 0; x < w; ++x, ++dst, ++src) { + *dst = INTERPOLATE(INTERPOLATE(*src, _trintone(shadow, midtone, highlight, luma((uint8_t*)src)), params->blender), *dst, MULTIPLY(opacity, A(*src))); + } } dbuffer += cmp->image.stride; sbuffer += cmp->recoverSfc->stride; @@ -575,9 +580,14 @@ bool effectTritone(SwCompositor* cmp, const RenderEffectTritone* params, bool di auto dbuffer = cmp->image.buf32 + (bbox.min.y * cmp->image.stride + bbox.min.x); for (size_t y = 0; y < h; ++y) { auto dst = dbuffer; - for (size_t x = 0; x < w; ++x, ++dst) { - auto tmp = rasterUnpremultiply(*dst); - *dst = ALPHA_BLEND(_trintone(shadow, midtone, highlight, luma((uint8_t*)&tmp)), A(tmp)); + if (params->blender == 0) { + for (size_t x = 0; x < w; ++x, ++dst) { + *dst = ALPHA_BLEND(_trintone(shadow, midtone, highlight, luma((uint8_t*)dst)), MULTIPLY(A(*dst), opacity)); + } + } else { + for (size_t x = 0; x < w; ++x, ++dst) { + *dst = ALPHA_BLEND(INTERPOLATE(*dst, _trintone(shadow, midtone, highlight, luma((uint8_t*)dst)), params->blender), MULTIPLY(A(*dst), opacity)); + } } dbuffer += cmp->image.stride; } diff --git a/src/renderer/tvgRender.h b/src/renderer/tvgRender.h index 88a0e08b..3b0e8a8d 100644 --- a/src/renderer/tvgRender.h +++ b/src/renderer/tvgRender.h @@ -479,6 +479,7 @@ struct RenderEffectTritone : RenderEffect uint8_t shadow[3]; //rgb uint8_t midtone[3]; //rgb uint8_t highlight[3]; //rgb + uint8_t blender = 0; //0 ~ 255 static RenderEffectTritone* gen(va_list& args) { @@ -492,6 +493,7 @@ struct RenderEffectTritone : RenderEffect inst->highlight[0] = va_arg(args, int); inst->highlight[1] = va_arg(args, int); inst->highlight[2] = va_arg(args, int); + inst->blender = va_arg(args, int); inst->type = SceneEffect::Tritone; return inst; } diff --git a/src/renderer/wg_engine/tvgWgShaderSrc.cpp b/src/renderer/wg_engine/tvgWgShaderSrc.cpp index 8890062e..e1d5b3fc 100644 --- a/src/renderer/wg_engine/tvgWgShaderSrc.cpp +++ b/src/renderer/wg_engine/tvgWgShaderSrc.cpp @@ -874,11 +874,14 @@ fn cs_main_tritone(@builtin(global_invocation_id) gid: vec3u) { let shadow = settings[0]; let midtone = settings[1]; let highlight = settings[2]; - let color = select( - mix(shadow, midtone, luma * 2.0f), - mix(midtone, highlight, (luma - 0.5f)*2.0f), - luma >= 0.5f - ) * orig.a; - textureStore(imageTrg, uid.xy, color); + + var color = select(mix(shadow, midtone, luma * 2.0f), mix(midtone, highlight, (luma - 0.5f)*2.0f), luma >= 0.5f); + + // blending + if (highlight.a > 0.0f) { + color = mix(color, orig, highlight.a); + } + + textureStore(imageTrg, uid.xy, color * orig.a); } )"; \ No newline at end of file diff --git a/src/renderer/wg_engine/tvgWgShaderTypes.cpp b/src/renderer/wg_engine/tvgWgShaderTypes.cpp index a1a501e7..71f51c6b 100644 --- a/src/renderer/wg_engine/tvgWgShaderTypes.cpp +++ b/src/renderer/wg_engine/tvgWgShaderTypes.cpp @@ -294,8 +294,8 @@ bool WgShaderTypeEffectParams::update(RenderEffectTritone* tritone) params[8] = tritone->highlight[0] / 255.0f; params[9] = tritone->highlight[1] / 255.0f; params[10] = tritone->highlight[2] / 255.0f; - params[11] = 0.0f; + params[11] = tritone->blender / 255.0f; - tritone->valid = true; + tritone->valid = tritone->blender < 255; return true; }