mirror of
https://github.com/thorvg/thorvg.git
synced 2025-07-23 14:48:24 +00:00
sw_engine: improved the dropshadow effect support
- shadow rendering was skipped when the blur value was 0. it now correctly renders shadows without blur. - this also fixes the distance offset scalability. issue: https://github.com/thorvg/thorvg/issues/3602
This commit is contained in:
parent
8c9c2888cc
commit
5abccb2091
1 changed files with 76 additions and 25 deletions
|
@ -265,26 +265,78 @@ static void _dropShadowFilter(uint32_t* dst, uint32_t* src, int stride, int w, i
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static void _dropShadowShift(uint32_t* dst, uint32_t* src, int dstride, int sstride, SwBBox& region, SwPoint& offset, uint8_t opacity)
|
||||
static void _shift(uint32_t** dst, uint32_t** src, int dstride, int sstride, int wmax, int hmax, const SwBBox& bbox, const SwPoint& offset, SwSize& size)
|
||||
{
|
||||
src += (region.min.y * sstride + region.min.x);
|
||||
dst += (region.min.y * dstride + region.min.x);
|
||||
size.w = bbox.max.x - bbox.min.x;
|
||||
size.h = bbox.max.y - bbox.min.y;
|
||||
|
||||
auto w = region.max.x - region.min.x;
|
||||
auto h = region.max.y - region.min.y;
|
||||
auto translucent = opacity < 255;
|
||||
//shift
|
||||
if (bbox.min.x + offset.x < 0) *src -= offset.x;
|
||||
else *dst += offset.x;
|
||||
|
||||
//shift offset
|
||||
if (region.min.x + offset.x < 0) src -= offset.x;
|
||||
else dst += offset.x;
|
||||
if (bbox.min.y + offset.y < 0) *src -= (offset.y * sstride);
|
||||
else *dst += (offset.y * dstride);
|
||||
|
||||
if (region.min.y + offset.y < 0) src -= (offset.y * sstride);
|
||||
else dst += (offset.y * dstride);
|
||||
if (size.w + bbox.min.x + offset.x > wmax) size.w -= (size.w + bbox.min.x + offset.x - wmax);
|
||||
if (size.h + bbox.min.y + offset.y > hmax) size.h -= (size.h + bbox.min.y + offset.y - hmax);
|
||||
}
|
||||
|
||||
for (auto y = 0; y < h; ++y) {
|
||||
if (translucent) rasterTranslucentPixel32(dst, src, w, opacity);
|
||||
else rasterPixel32(dst, src, w, opacity);
|
||||
|
||||
static void _dropShadowNoFilter(SwImage* dimg, SwImage* simg, const SwBBox& bbox, const SwPoint& offset, uint32_t color)
|
||||
{
|
||||
int dstride = dimg->stride;
|
||||
int sstride = simg->stride;
|
||||
|
||||
auto src = simg->buf32 + (bbox.min.y * sstride + bbox.min.x);
|
||||
auto dst = dimg->buf32 + (bbox.min.y * dstride + bbox.min.x);
|
||||
|
||||
//for shadow
|
||||
auto src2 = src;
|
||||
auto dst2 = dst;
|
||||
|
||||
SwSize size;
|
||||
_shift(&dst2, &src2, dimg->stride, simg->stride, dimg->w, dimg->h, bbox, offset, size);
|
||||
|
||||
//shadow
|
||||
for (auto y = 0; y < size.h; ++y) {
|
||||
auto s2 = src2;
|
||||
auto d2 = dst2;
|
||||
for (int x = 0; x < size.w; ++x, ++d2, ++s2) {
|
||||
*d2 = ALPHA_BLEND(color, A(*s2));
|
||||
}
|
||||
src2 += sstride;
|
||||
dst2 += dstride;
|
||||
}
|
||||
|
||||
//original
|
||||
for (auto y = 0; y < (bbox.max.y - bbox.min.y); ++y) {
|
||||
auto s = src;
|
||||
auto d = dst;
|
||||
for (int x = 0; x < (bbox.max.x - bbox.min.x); ++x, ++d, ++s) {
|
||||
*d = *s + ALPHA_BLEND(*d, IA(*s));
|
||||
}
|
||||
src += sstride;
|
||||
dst += dstride;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void _dropShadowShift(SwImage* dimg, SwImage* simg, SwBBox& bbox, const SwPoint& offset, uint8_t opacity)
|
||||
{
|
||||
int dstride = dimg->stride;
|
||||
int sstride = simg->stride;
|
||||
|
||||
auto src = simg->buf32 + (bbox.min.y * sstride + bbox.min.x);
|
||||
auto dst = dimg->buf32 + (bbox.min.y * dstride + bbox.min.x);
|
||||
|
||||
auto translucent = (opacity < 255);
|
||||
|
||||
SwSize size;
|
||||
_shift(&dst, &src, dimg->stride, simg->stride, dimg->w, dimg->h, bbox, offset, size);
|
||||
|
||||
for (auto y = 0; y < size.h; ++y) {
|
||||
if (translucent) rasterTranslucentPixel32(dst, src, size.w, opacity);
|
||||
else rasterPixel32(dst, src, size.w, opacity);
|
||||
src += sstride;
|
||||
dst += dstride;
|
||||
}
|
||||
|
@ -322,7 +374,7 @@ void effectDropShadowUpdate(RenderEffectDropShadow* params, const Matrix& transf
|
|||
rd->extends = _gaussianInit(rd, std::pow(params->sigma * scale, 2), params->quality);
|
||||
|
||||
//invalid
|
||||
if (rd->extends == 0 || params->color[3] == 0) {
|
||||
if (params->color[3] == 0) {
|
||||
params->valid = false;
|
||||
return;
|
||||
}
|
||||
|
@ -330,7 +382,7 @@ void effectDropShadowUpdate(RenderEffectDropShadow* params, const Matrix& transf
|
|||
//offset
|
||||
if (params->distance > 0.0f) {
|
||||
auto radian = tvg::deg2rad(90.0f - params->angle);
|
||||
rd->offset = {(SwCoord)(params->distance * cosf(radian)), (SwCoord)(-1.0f * params->distance * sinf(radian))};
|
||||
rd->offset = {(int32_t)((params->distance * scale) * cosf(radian)), (int32_t)(-1.0f * (params->distance * scale) * sinf(radian))};
|
||||
} else {
|
||||
rd->offset = {0, 0};
|
||||
}
|
||||
|
@ -362,6 +414,12 @@ bool effectDropShadow(SwCompositor* cmp, SwSurface* surface[2], const RenderEffe
|
|||
|
||||
TVGLOG("SW_ENGINE", "DropShadow region(%ld, %ld, %ld, %ld) params(%f %f %f), level(%d)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->angle, params->distance, params->sigma, data->level);
|
||||
|
||||
//no filter required
|
||||
if (params->sigma == 0.0f) {
|
||||
_dropShadowNoFilter(buffer[1], &cmp->image, bbox, data->offset, color);
|
||||
std::swap(cmp->image.buf32, buffer[1]->buf32);
|
||||
return true;
|
||||
}
|
||||
//saving the original image in order to overlay it into the filtered image.
|
||||
_dropShadowFilter(back, front, stride, w, h, bbox, data->kernel[0], color, false);
|
||||
std::swap(front, buffer[0]->buf32);
|
||||
|
@ -386,7 +444,7 @@ bool effectDropShadow(SwCompositor* cmp, SwSurface* surface[2], const RenderEffe
|
|||
std::swap(cmp->image.buf32, back);
|
||||
//draw to the intermediate surface
|
||||
rasterClear(surface[1], bbox.min.x, bbox.min.y, w, h);
|
||||
_dropShadowShift(buffer[1]->buf32, cmp->image.buf32, stride, stride, bbox, data->offset, params->color[3]);
|
||||
_dropShadowShift(buffer[1], &cmp->image, bbox, data->offset, params->color[3]);
|
||||
std::swap(cmp->image.buf32, buffer[1]->buf32);
|
||||
|
||||
//compositing shadow and body
|
||||
|
@ -475,8 +533,6 @@ 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, %d)", 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) {
|
||||
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);
|
||||
|
@ -515,11 +571,6 @@ bool effectTint(SwCompositor* cmp, const RenderEffectTint* params, bool direct)
|
|||
|
||||
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);
|
||||
|
|
Loading…
Add table
Reference in a new issue