mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-07 21:23:32 +00:00
renderer: support Trintone SceneEffect
The Tritone effect maps the scene's shadows, midtones, and highlights to three specific colors, allowing for more complex and artistic color grading. Applied Tritone Formula: if (L < 0.5) Result = (1 - 2L) * Shadow + 2L * Midtone else Result = (1 - 2(L - 0.5)) * Midtone + (2(L - 0.5)) * Highlight Where the L is Luminance. issue: https://github.com/thorvg/thorvg/issues/2718
This commit is contained in:
parent
1eff126b40
commit
e9fb478471
6 changed files with 107 additions and 2 deletions
|
@ -232,7 +232,8 @@ enum class SceneEffect : uint8_t
|
||||||
GaussianBlur, ///< Apply a blur effect with a Gaussian filter. Param(3) = {sigma(float)[> 0], direction(int)[both: 0 / horizontal: 1 / vertical: 2], border(int)[duplicate: 0 / wrap: 1], quality(int)[0 - 100]}
|
GaussianBlur, ///< Apply a blur effect with a Gaussian filter. Param(3) = {sigma(float)[> 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(float)[0 - 360], distance(float), blur_sigma(float)[> 0], 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(float)[0 - 360], distance(float), blur_sigma(float)[> 0], quality(int)[0 - 100]}
|
||||||
Fill, ///< Override the scene content color with a given fill information (Experimental API). Param(5) = {color_R(int)[0 - 255], color_G(int)[0 - 255], color_B(int)[0 - 255], opacity(int)[0 - 255]}
|
Fill, ///< Override the scene content color with a given fill information (Experimental API). Param(5) = {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 paramters (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(float)[0 - 100]}
|
Tint, ///< Tinting the current scene color with a given black, white color paramters (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(float)[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]}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -581,6 +581,7 @@ bool effectFillPrepare(RenderEffectFill* effect);
|
||||||
bool effectFill(SwCompositor* cmp, const RenderEffectFill* params, bool direct);
|
bool effectFill(SwCompositor* cmp, const RenderEffectFill* params, bool direct);
|
||||||
bool effectTintPrepare(RenderEffectTint* effect);
|
bool effectTintPrepare(RenderEffectTint* effect);
|
||||||
bool effectTint(SwCompositor* cmp, const RenderEffectTint* params, bool direct);
|
bool effectTint(SwCompositor* cmp, const RenderEffectTint* params, bool direct);
|
||||||
|
bool effectTritonePrepare(RenderEffectTritone* effect);
|
||||||
|
bool effectTritone(SwCompositor* cmp, const RenderEffectTritone* params, bool direct);
|
||||||
|
|
||||||
#endif /* _TVG_SW_COMMON_H_ */
|
#endif /* _TVG_SW_COMMON_H_ */
|
||||||
|
|
|
@ -475,6 +475,8 @@ bool effectTint(SwCompositor* cmp, const RenderEffectTint* params, bool direct)
|
||||||
|
|
||||||
TVGLOG("SW_ENGINE", "Tint region(%ld, %ld, %ld, %ld), param(%d %d %d, %d %d %d, %f)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->black[0], params->black[1], params->black[2], params->white[0], params->white[1], params->white[2], params->intensity);
|
TVGLOG("SW_ENGINE", "Tint region(%ld, %ld, %ld, %ld), param(%d %d %d, %d %d %d, %f)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->black[0], params->black[1], params->black[2], params->white[0], params->white[1], params->white[2], params->intensity);
|
||||||
|
|
||||||
|
/* Tint Formula: (1 - L) * Black + L * White, where the L is Luminance. */
|
||||||
|
|
||||||
if (direct) {
|
if (direct) {
|
||||||
auto dbuffer = cmp->recoverSfc->buf32 + (bbox.min.y * cmp->recoverSfc->stride + bbox.min.x);
|
auto dbuffer = cmp->recoverSfc->buf32 + (bbox.min.y * cmp->recoverSfc->stride + bbox.min.x);
|
||||||
auto sbuffer = cmp->image.buf32 + (bbox.min.y * cmp->image.stride + bbox.min.x);
|
auto sbuffer = cmp->image.buf32 + (bbox.min.y * cmp->image.stride + bbox.min.x);
|
||||||
|
@ -503,5 +505,75 @@ bool effectTint(SwCompositor* cmp, const RenderEffectTint* params, bool direct)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************************/
|
||||||
|
/* Tritone Implementation */
|
||||||
|
/************************************************************************/
|
||||||
|
|
||||||
|
static uint32_t _trintone(uint32_t s, uint32_t m, uint32_t h, int l)
|
||||||
|
{
|
||||||
|
/* Tritone Formula:
|
||||||
|
if (L < 0.5) { (1 - 2L) * Shadow + 2L * Midtone }
|
||||||
|
else { (1 - 2(L - 0.5)) * Midtone + (2(L - 0.5)) * Highlight }
|
||||||
|
Where the L is Luminance. */
|
||||||
|
|
||||||
|
if (l < 128) {
|
||||||
|
auto a = std::min(l * 2, 255);
|
||||||
|
return ALPHA_BLEND(s, 255 - a) + ALPHA_BLEND(m, a);
|
||||||
|
} else {
|
||||||
|
auto a = 2 * std::max(0, l - 128);
|
||||||
|
return ALPHA_BLEND(m, 255 - a) + ALPHA_BLEND(h, a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool effectTritonePrepare(RenderEffectTritone* params)
|
||||||
|
{
|
||||||
|
params->valid = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool effectTritone(SwCompositor* cmp, const RenderEffectTritone* params, bool direct)
|
||||||
|
{
|
||||||
|
auto& bbox = cmp->bbox;
|
||||||
|
auto w = size_t(bbox.max.x - bbox.min.x);
|
||||||
|
auto h = size_t(bbox.max.y - bbox.min.y);
|
||||||
|
auto shadow = cmp->recoverSfc->join(params->shadow[0], params->shadow[1], params->shadow[2], 255);
|
||||||
|
auto midtone = cmp->recoverSfc->join(params->midtone[0], params->midtone[1], params->midtone[2], 255);
|
||||||
|
auto highlight = cmp->recoverSfc->join(params->highlight[0], params->highlight[1], params->highlight[2], 255);
|
||||||
|
auto opacity = cmp->opacity;
|
||||||
|
auto luma = cmp->recoverSfc->alphas[2]; //luma function
|
||||||
|
|
||||||
|
TVGLOG("SW_ENGINE", "Tritone region(%ld, %ld, %ld, %ld), 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]);
|
||||||
|
|
||||||
|
if (direct) {
|
||||||
|
auto dbuffer = cmp->recoverSfc->buf32 + (bbox.min.y * cmp->recoverSfc->stride + bbox.min.x);
|
||||||
|
auto sbuffer = cmp->image.buf32 + (bbox.min.y * cmp->image.stride + bbox.min.x);
|
||||||
|
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)));
|
||||||
|
}
|
||||||
|
dbuffer += cmp->image.stride;
|
||||||
|
sbuffer += cmp->recoverSfc->stride;
|
||||||
|
}
|
||||||
|
cmp->valid = true; //no need the subsequent composition
|
||||||
|
} else {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
dbuffer += cmp->image.stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
|
@ -656,6 +656,7 @@ bool SwRenderer::prepare(RenderEffect* effect)
|
||||||
case SceneEffect::DropShadow: return effectDropShadowPrepare(static_cast<RenderEffectDropShadow*>(effect));
|
case SceneEffect::DropShadow: return effectDropShadowPrepare(static_cast<RenderEffectDropShadow*>(effect));
|
||||||
case SceneEffect::Fill: return effectFillPrepare(static_cast<RenderEffectFill*>(effect));
|
case SceneEffect::Fill: return effectFillPrepare(static_cast<RenderEffectFill*>(effect));
|
||||||
case SceneEffect::Tint: return effectTintPrepare(static_cast<RenderEffectTint*>(effect));
|
case SceneEffect::Tint: return effectTintPrepare(static_cast<RenderEffectTint*>(effect));
|
||||||
|
case SceneEffect::Tritone: return effectTritonePrepare(static_cast<RenderEffectTritone*>(effect));
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -691,6 +692,9 @@ bool SwRenderer::effect(RenderCompositor* cmp, const RenderEffect* effect, bool
|
||||||
case SceneEffect::Tint: {
|
case SceneEffect::Tint: {
|
||||||
return effectTint(p, static_cast<const RenderEffectTint*>(effect), direct);
|
return effectTint(p, static_cast<const RenderEffectTint*>(effect), direct);
|
||||||
}
|
}
|
||||||
|
case SceneEffect::Tritone: {
|
||||||
|
return effectTritone(p, static_cast<const RenderEffectTritone*>(effect), direct);
|
||||||
|
}
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -348,6 +348,29 @@ struct RenderEffectTint : RenderEffect
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RenderEffectTritone : RenderEffect
|
||||||
|
{
|
||||||
|
uint8_t shadow[3]; //rgb
|
||||||
|
uint8_t midtone[3]; //rgb
|
||||||
|
uint8_t highlight[3]; //rgb
|
||||||
|
|
||||||
|
static RenderEffectTritone* gen(va_list& args)
|
||||||
|
{
|
||||||
|
auto inst = new RenderEffectTritone;
|
||||||
|
inst->shadow[0] = va_arg(args, int);
|
||||||
|
inst->shadow[1] = va_arg(args, int);
|
||||||
|
inst->shadow[2] = va_arg(args, int);
|
||||||
|
inst->midtone[0] = va_arg(args, int);
|
||||||
|
inst->midtone[1] = va_arg(args, int);
|
||||||
|
inst->midtone[2] = va_arg(args, int);
|
||||||
|
inst->highlight[0] = va_arg(args, int);
|
||||||
|
inst->highlight[1] = va_arg(args, int);
|
||||||
|
inst->highlight[2] = va_arg(args, int);
|
||||||
|
inst->type = SceneEffect::Tritone;
|
||||||
|
return inst;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class RenderMethod
|
class RenderMethod
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -330,6 +330,10 @@ struct Scene::Impl : Paint::Impl
|
||||||
re = RenderEffectTint::gen(args);
|
re = RenderEffectTint::gen(args);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SceneEffect::Tritone: {
|
||||||
|
re = RenderEffectTritone::gen(args);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue