mirror of
https://github.com/thorvg/thorvg.git
synced 2025-07-23 22:58:44 +00:00
sw_engine: support the fast drop shadow version
The direct raster version has been restored with a proper fix
for the out-of-range bug.
see history: 78753eed31
This commit is contained in:
parent
5abccb2091
commit
f0f76884ed
4 changed files with 53 additions and 39 deletions
|
@ -269,7 +269,7 @@ struct SwSurface : RenderSurface
|
||||||
blender = rhs->blender;
|
blender = rhs->blender;
|
||||||
compositor = rhs->compositor;
|
compositor = rhs->compositor;
|
||||||
blendMethod = rhs->blendMethod;
|
blendMethod = rhs->blendMethod;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SwCompositor : RenderCompositor
|
struct SwCompositor : RenderCompositor
|
||||||
|
@ -590,7 +590,7 @@ uint32_t rasterUnpremultiply(uint32_t data);
|
||||||
bool effectGaussianBlur(SwCompositor* cmp, SwSurface* surface, const RenderEffectGaussianBlur* params);
|
bool effectGaussianBlur(SwCompositor* cmp, SwSurface* surface, const RenderEffectGaussianBlur* params);
|
||||||
bool effectGaussianBlurRegion(RenderEffectGaussianBlur* effect);
|
bool effectGaussianBlurRegion(RenderEffectGaussianBlur* effect);
|
||||||
void effectGaussianBlurUpdate(RenderEffectGaussianBlur* effect, const Matrix& transform);
|
void effectGaussianBlurUpdate(RenderEffectGaussianBlur* effect, const Matrix& transform);
|
||||||
bool effectDropShadow(SwCompositor* cmp, SwSurface* surfaces[2], const RenderEffectDropShadow* params);
|
bool effectDropShadow(SwCompositor* cmp, SwSurface* surfaces[2], const RenderEffectDropShadow* params, bool direct);
|
||||||
bool effectDropShadowRegion(RenderEffectDropShadow* effect);
|
bool effectDropShadowRegion(RenderEffectDropShadow* effect);
|
||||||
void effectDropShadowUpdate(RenderEffectDropShadow* effect, const Matrix& transform);
|
void effectDropShadowUpdate(RenderEffectDropShadow* effect, const Matrix& transform);
|
||||||
void effectFillUpdate(RenderEffectFill* effect);
|
void effectFillUpdate(RenderEffectFill* effect);
|
||||||
|
|
|
@ -282,33 +282,40 @@ static void _shift(uint32_t** dst, uint32_t** src, int dstride, int sstride, int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void _dropShadowNoFilter(uint32_t* dst, uint32_t* src, int dstride, int sstride, int dw, int dh, const SwBBox& bbox, const SwPoint& offset, uint32_t color, uint8_t opacity, bool direct)
|
||||||
|
{
|
||||||
|
src += (bbox.min.y * sstride + bbox.min.x);
|
||||||
|
dst += (bbox.min.y * dstride + bbox.min.x);
|
||||||
|
|
||||||
|
SwSize size;
|
||||||
|
_shift(&dst, &src, dstride, sstride, dw, dh, bbox, offset, size);
|
||||||
|
|
||||||
|
for (auto y = 0; y < size.h; ++y) {
|
||||||
|
auto s2 = src;
|
||||||
|
auto d2 = dst;
|
||||||
|
for (int x = 0; x < size.w; ++x, ++d2, ++s2) {
|
||||||
|
auto a = MULTIPLY(opacity, A(*s2));
|
||||||
|
if (!direct || a == 255) *d2 = ALPHA_BLEND(color, a);
|
||||||
|
else *d2 = INTERPOLATE(color, *d2, a);
|
||||||
|
}
|
||||||
|
src += sstride;
|
||||||
|
dst += dstride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _dropShadowNoFilter(SwImage* dimg, SwImage* simg, const SwBBox& bbox, const SwPoint& offset, uint32_t color)
|
static void _dropShadowNoFilter(SwImage* dimg, SwImage* simg, const SwBBox& bbox, const SwPoint& offset, uint32_t color)
|
||||||
{
|
{
|
||||||
int dstride = dimg->stride;
|
int dstride = dimg->stride;
|
||||||
int sstride = simg->stride;
|
int sstride = simg->stride;
|
||||||
|
|
||||||
|
//shadow image
|
||||||
|
_dropShadowNoFilter(dimg->buf32, simg->buf32, dstride, sstride, dimg->w, dimg->h, bbox, offset, color, 255, false);
|
||||||
|
|
||||||
|
//original image
|
||||||
auto src = simg->buf32 + (bbox.min.y * sstride + bbox.min.x);
|
auto src = simg->buf32 + (bbox.min.y * sstride + bbox.min.x);
|
||||||
auto dst = dimg->buf32 + (bbox.min.y * dstride + 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) {
|
for (auto y = 0; y < (bbox.max.y - bbox.min.y); ++y) {
|
||||||
auto s = src;
|
auto s = src;
|
||||||
auto d = dst;
|
auto d = dst;
|
||||||
|
@ -321,21 +328,16 @@ static void _dropShadowNoFilter(SwImage* dimg, SwImage* simg, const SwBBox& bbox
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _dropShadowShift(SwImage* dimg, SwImage* simg, SwBBox& bbox, const SwPoint& offset, uint8_t opacity)
|
static void _dropShadowShift(uint32_t* dst, uint32_t* src, int dstride, int sstride, int dw, int dh, const SwBBox& bbox, const SwPoint& offset, uint8_t opacity, bool direct)
|
||||||
{
|
{
|
||||||
int dstride = dimg->stride;
|
src += (bbox.min.y * sstride + bbox.min.x);
|
||||||
int sstride = simg->stride;
|
dst += (bbox.min.y * dstride + bbox.min.x);
|
||||||
|
|
||||||
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;
|
SwSize size;
|
||||||
_shift(&dst, &src, dimg->stride, simg->stride, dimg->w, dimg->h, bbox, offset, size);
|
_shift(&dst, &src, dstride, sstride, dw, dh, bbox, offset, size);
|
||||||
|
|
||||||
for (auto y = 0; y < size.h; ++y) {
|
for (auto y = 0; y < size.h; ++y) {
|
||||||
if (translucent) rasterTranslucentPixel32(dst, src, size.w, opacity);
|
if (direct) rasterTranslucentPixel32(dst, src, size.w, opacity);
|
||||||
else rasterPixel32(dst, src, size.w, opacity);
|
else rasterPixel32(dst, src, size.w, opacity);
|
||||||
src += sstride;
|
src += sstride;
|
||||||
dst += dstride;
|
dst += dstride;
|
||||||
|
@ -394,7 +396,7 @@ void effectDropShadowUpdate(RenderEffectDropShadow* params, const Matrix& transf
|
||||||
//A quite same integration with effectGaussianBlur(). See it for detailed comments.
|
//A quite same integration with effectGaussianBlur(). See it for detailed comments.
|
||||||
//surface[0]: the original image, to overlay it into the filtered image.
|
//surface[0]: the original image, to overlay it into the filtered image.
|
||||||
//surface[1]: temporary buffer for generating the filtered image.
|
//surface[1]: temporary buffer for generating the filtered image.
|
||||||
bool effectDropShadow(SwCompositor* cmp, SwSurface* surface[2], const RenderEffectDropShadow* params)
|
bool effectDropShadow(SwCompositor* cmp, SwSurface* surface[2], const RenderEffectDropShadow* params, bool direct)
|
||||||
{
|
{
|
||||||
//FIXME: if the body is partially visible due to clipping, the shadow also becomes partially visible.
|
//FIXME: if the body is partially visible due to clipping, the shadow also becomes partially visible.
|
||||||
|
|
||||||
|
@ -412,14 +414,21 @@ bool effectDropShadow(SwCompositor* cmp, SwSurface* surface[2], const RenderEffe
|
||||||
auto front = cmp->image.buf32;
|
auto front = cmp->image.buf32;
|
||||||
auto back = buffer[1]->buf32;
|
auto back = buffer[1]->buf32;
|
||||||
|
|
||||||
|
auto opacity = direct ? MULTIPLY(params->color[3], cmp->opacity) : params->color[3];
|
||||||
|
|
||||||
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);
|
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
|
//no filter required
|
||||||
if (params->sigma == 0.0f) {
|
if (params->sigma == 0.0f) {
|
||||||
_dropShadowNoFilter(buffer[1], &cmp->image, bbox, data->offset, color);
|
if (direct) {
|
||||||
std::swap(cmp->image.buf32, buffer[1]->buf32);
|
_dropShadowNoFilter(cmp->recoverSfc->buf32, cmp->image.buf32, cmp->recoverSfc->stride, cmp->image.stride, cmp->recoverSfc->w, cmp->recoverSfc->h, bbox, data->offset, color, opacity, direct);
|
||||||
|
} else {
|
||||||
|
_dropShadowNoFilter(buffer[1], &cmp->image, bbox, data->offset, color);
|
||||||
|
std::swap(cmp->image.buf32, buffer[1]->buf32);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//saving the original image in order to overlay it into the filtered image.
|
//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);
|
_dropShadowFilter(back, front, stride, w, h, bbox, data->kernel[0], color, false);
|
||||||
std::swap(front, buffer[0]->buf32);
|
std::swap(front, buffer[0]->buf32);
|
||||||
|
@ -442,10 +451,17 @@ bool effectDropShadow(SwCompositor* cmp, SwSurface* surface[2], const RenderEffe
|
||||||
|
|
||||||
rasterXYFlip(front, back, stride, h, w, bbox, true);
|
rasterXYFlip(front, back, stride, h, w, bbox, true);
|
||||||
std::swap(cmp->image.buf32, back);
|
std::swap(cmp->image.buf32, back);
|
||||||
|
|
||||||
|
//draw to the main surface directly
|
||||||
|
if (direct) {
|
||||||
|
_dropShadowShift(cmp->recoverSfc->buf32, cmp->image.buf32, cmp->recoverSfc->stride, cmp->image.stride, cmp->recoverSfc->w, cmp->recoverSfc->h, bbox, data->offset, opacity, direct);
|
||||||
|
std::swap(cmp->image.buf32, buffer[0]->buf32);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
//draw to the intermediate surface
|
//draw to the intermediate surface
|
||||||
rasterClear(surface[1], bbox.min.x, bbox.min.y, w, h);
|
rasterClear(surface[1], bbox.min.x, bbox.min.y, w, h);
|
||||||
_dropShadowShift(buffer[1], &cmp->image, bbox, data->offset, params->color[3]);
|
_dropShadowShift(buffer[1]->buf32, cmp->image.buf32, buffer[1]->stride, cmp->image.stride, buffer[1]->w, buffer[1]->h, bbox, data->offset, opacity, direct);
|
||||||
std::swap(cmp->image.buf32, buffer[1]->buf32);
|
|
||||||
|
|
||||||
//compositing shadow and body
|
//compositing shadow and body
|
||||||
auto s = buffer[0]->buf32 + (bbox.min.y * buffer[0]->stride + bbox.min.x);
|
auto s = buffer[0]->buf32 + (bbox.min.y * buffer[0]->stride + bbox.min.x);
|
||||||
|
|
|
@ -711,7 +711,7 @@ bool SwRenderer::render(RenderCompositor* cmp, const RenderEffect* effect, bool
|
||||||
cmp1->compositor->valid = false;
|
cmp1->compositor->valid = false;
|
||||||
auto cmp2 = request(surface->channelSize, true);
|
auto cmp2 = request(surface->channelSize, true);
|
||||||
SwSurface* surfaces[] = {cmp1, cmp2};
|
SwSurface* surfaces[] = {cmp1, cmp2};
|
||||||
auto ret = effectDropShadow(p, surfaces, static_cast<const RenderEffectDropShadow*>(effect));
|
auto ret = effectDropShadow(p, surfaces, static_cast<const RenderEffectDropShadow*>(effect), direct);
|
||||||
cmp1->compositor->valid = true;
|
cmp1->compositor->valid = true;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,8 +56,6 @@ using namespace tvg;
|
||||||
|
|
||||||
enum class FileType { Png = 0, Jpg, Webp, Tvg, Svg, Lottie, Ttf, Raw, Gif, Unknown };
|
enum class FileType { Png = 0, Jpg, Webp, Tvg, Svg, Lottie, Ttf, Raw, Gif, Unknown };
|
||||||
|
|
||||||
using Size = Point;
|
|
||||||
|
|
||||||
#ifdef THORVG_LOG_ENABLED
|
#ifdef THORVG_LOG_ENABLED
|
||||||
constexpr auto ErrorColor = "\033[31m"; //red
|
constexpr auto ErrorColor = "\033[31m"; //red
|
||||||
constexpr auto ErrorBgColor = "\033[41m";//bg red
|
constexpr auto ErrorBgColor = "\033[41m";//bg red
|
||||||
|
|
Loading…
Add table
Reference in a new issue