From: Hermet Park Date: Sun, 10 Jan 2021 11:37:20 +0000 (+0900) Subject: sw_engine composition: enhance image masking X-Git-Tag: submit/tizen/20210117.211744~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7cf2876f81c3f1f01d7834fc2ca021c95bcfece4;p=platform%2Fcore%2Fgraphics%2Ftizenvg.git sw_engine composition: enhance image masking composition alpha masking supports scene/paints targets. @Examples: Masking @Issues: 31 Change-Id: I7aed18172fab54a2e31ccf8894fcb6fb6925a8a8 --- diff --git a/src/examples/Masking.cpp b/src/examples/Masking.cpp index 624ea6f..8d517ef 100644 --- a/src/examples/Masking.cpp +++ b/src/examples/Masking.cpp @@ -26,6 +26,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //SVG auto svg = tvg::Picture::gen(); if (svg->load(EXAMPLE_DIR"/cartman.svg") != tvg::Result::Success) return; + svg->opacity(100); svg->scale(3); svg->translate(50, 400); @@ -35,53 +36,59 @@ void tvgDrawCmds(tvg::Canvas* canvas) mask2->appendRect(150, 500, 200, 200, 30, 30); mask2->fill(255, 255, 255, 255); svg->composite(move(mask2), tvg::CompositeMethod::AlphaMask); - canvas->push(move(svg)); + if (canvas->push(move(svg)) != tvg::Result::Success) return; //Star - -#if 0 - //Appends Paths - shape->moveTo(199, 34); - shape->lineTo(253, 143); - shape->lineTo(374, 160); - shape->lineTo(287, 244); - shape->lineTo(307, 365); - shape->lineTo(199, 309); - shape->lineTo(97, 365); - shape->lineTo(112, 245); - shape->lineTo(26, 161); - shape->lineTo(146, 143); - shape->close(); -#endif - - //shape->opacity(127); - -// scene->push(move(shape)); - -#if 0 - scene->composite(move(mask2), tvg::CompositeMethod::AlphaMask); - if (canvas->push(move(scene)) != tvg::Result::Success) return; - - + auto star = tvg::Shape::gen(); + star->fill(80, 80, 80, 255); + star->moveTo(599, 34); + star->lineTo(653, 143); + star->lineTo(774, 160); + star->lineTo(687, 244); + star->lineTo(707, 365); + star->lineTo(599, 309); + star->lineTo(497, 365); + star->lineTo(512, 245); + star->lineTo(426, 161); + star->lineTo(546, 143); + star->close(); + star->stroke(10); + star->stroke(255, 255, 255, 255); + + //Mask3 + auto mask3 = tvg::Shape::gen(); + mask3->appendCircle(600, 200, 125, 125); + mask3->fill(255, 255, 255, 255); + star->composite(move(mask3), tvg::CompositeMethod::AlphaMask); + if (canvas->push(move(star)) != tvg::Result::Success) return; + + //Image ifstream file(EXAMPLE_DIR"/rawimage_200x300.raw"); if (!file.is_open()) return; data = (uint32_t*) malloc(sizeof(uint32_t) * (200 * 300)); file.read(reinterpret_cast(data), sizeof (data) * 200 * 300); file.close(); - //Mask Target 1 - auto picture = tvg::Picture::gen(); - if (picture->load(data, 200, 300, true) != tvg::Result::Success) return; - picture->translate(500, 400); - - //Alpha Mask - auto mask = tvg::Shape::gen(); - mask->appendCircle(500, 500, 125, 125); - mask->fill(255, 255, 255, 100); - - picture->composite(move(mask), tvg::CompositeMethod::AlphaMask); - if (canvas->push(move(picture)) != tvg::Result::Success) return; -#endif + auto image = tvg::Picture::gen(); + if (image->load(data, 200, 300, true) != tvg::Result::Success) return; + image->translate(500, 400); + + //Mask4 + auto mask4 = tvg::Shape::gen(); + mask4->moveTo(599, 384); + mask4->lineTo(653, 493); + mask4->lineTo(774, 510); + mask4->lineTo(687, 594); + mask4->lineTo(707, 715); + mask4->lineTo(599, 659); + mask4->lineTo(497, 715); + mask4->lineTo(512, 595); + mask4->lineTo(426, 511); + mask4->lineTo(546, 493); + mask4->close(); + mask4->fill(255, 255, 255, 70); + image->composite(move(mask4), tvg::CompositeMethod::AlphaMask); + if (canvas->push(move(image)) != tvg::Result::Success) return; } diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index d33dba2..e0f86bc 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -101,6 +101,11 @@ static bool _translucent(SwSurface* surface, uint8_t a) return true; } + +/************************************************************************/ +/* Rect */ +/************************************************************************/ + static bool _translucentRect(SwSurface* surface, const SwBBox& region, uint32_t color) { auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; @@ -129,17 +134,13 @@ static bool _translucentRectAlphaMask(SwSurface* surface, const SwBBox& region, #endif auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x; //compositor buffer - auto tbuffer = static_cast(alloca(sizeof(uint32_t) * w)); //temp buffer for intermediate processing for (uint32_t y = 0; y < h; ++y) { auto dst = &buffer[y * surface->stride]; auto cmp = &cbuffer[y * surface->stride]; - auto tmp = tbuffer; - //Composition for (uint32_t x = 0; x < w; ++x) { - *tmp = ALPHA_BLEND(color, surface->blender.alpha(*cmp)); - dst[x] = *tmp + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(*tmp)); - ++tmp; + auto tmp = ALPHA_BLEND(color, surface->blender.alpha(*cmp)); + dst[x] = tmp + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(tmp)); ++cmp; } } @@ -171,6 +172,11 @@ static bool _rasterSolidRect(SwSurface* surface, const SwBBox& region, uint32_t } +/************************************************************************/ +/* Rle */ +/************************************************************************/ + + static bool _translucentRle(SwSurface* surface, SwRleData* rle, uint32_t color) { auto span = rle->spans; @@ -231,6 +237,34 @@ static bool _rasterTranslucentRle(SwSurface* surface, SwRleData* rle, uint32_t c } +static bool _rasterSolidRle(SwSurface* surface, SwRleData* rle, uint32_t color) +{ + if (!rle) return false; + + auto span = rle->spans; + + for (uint32_t i = 0; i < rle->size; ++i) { + if (span->coverage == 255) { + rasterRGBA32(surface->buffer + span->y * surface->stride, color, span->x, span->len); + } else { + auto dst = &surface->buffer[span->y * surface->stride + span->x]; + auto src = ALPHA_BLEND(color, span->coverage); + auto ialpha = 255 - span->coverage; + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = src + ALPHA_BLEND(dst[i], ialpha); + } + } + ++span; + } + return true; +} + + +/************************************************************************/ +/* Image */ +/************************************************************************/ + + static bool _rasterTranslucentImageRle(SwSurface* surface, SwRleData* rle, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const Matrix* invTransform) { auto span = rle->spans; @@ -274,7 +308,7 @@ static bool _rasterImageRle(SwSurface* surface, SwRleData* rle, uint32_t *img, u } -static bool _rasterTranslucentImage(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform) +static bool _translucentImage(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform) { for (auto y = region.min.y; y < region.max.y; ++y) { auto dst = &surface->buffer[y * surface->stride + region.min.x]; @@ -292,12 +326,45 @@ static bool _rasterTranslucentImage(SwSurface* surface, uint32_t *img, uint32_t } -static bool _rasterTranslucentImage(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region) +static bool _translucentImageAlphaMask(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform) +{ +#ifdef THORVG_LOG_ENABLED + printf("SW_ENGINE: Transformed Image Alpha Mask Composition\n"); +#endif + for (auto y = region.min.y; y < region.max.y; ++y) { + auto dst = &surface->buffer[y * surface->stride + region.min.x]; + auto cmp = &surface->compositor->image.data[y * surface->stride + region.min.x]; + float ey1 = y * invTransform->e12 + invTransform->e13; + float ey2 = y * invTransform->e22 + invTransform->e23; + for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) { + auto rX = static_cast(roundf(x * invTransform->e11 + ey1)); + auto rY = static_cast(roundf(x * invTransform->e21 + ey2)); + if (rX >= w || rY >= h) continue; + auto tmp = ALPHA_BLEND(img[rX + (rY * w)], ALPHA_MULTIPLY(opacity, surface->blender.alpha(*cmp))); //TODO: need to use image's stride + *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); + } + } + return true; +} + + +static bool _rasterTranslucentImage(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform) +{ + if (surface->compositor) { + if (surface->compositor->method == CompositeMethod::AlphaMask) { + return _translucentImageAlphaMask(surface, img, w, h, opacity, region, invTransform); + } + } + return _translucentImage(surface, img, w, h, opacity, region, invTransform); +} + + +static bool _translucentImage(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region) { for (auto y = region.min.y; y < region.max.y; ++y) { auto dst = &surface->buffer[y * surface->stride + region.min.x]; auto src = img + region.min.x + (y * w); //TODO: need to use image's stride - for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) { + for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) { auto p = ALPHA_BLEND(*src, opacity); *dst = p + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(p)); } @@ -306,6 +373,43 @@ static bool _rasterTranslucentImage(SwSurface* surface, uint32_t *img, uint32_t } +static bool _translucentImageAlphaMask(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region) +{ + auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; + auto h2 = static_cast(region.max.y - region.min.y); + auto w2 = static_cast(region.max.x - region.min.x); + +#ifdef THORVG_LOG_ENABLED + printf("SW_ENGINE: Image Alpha Mask Composition\n"); +#endif + + auto sbuffer = img + (region.min.y * w) + region.min.x; + auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x; //compositor buffer + + for (uint32_t y = 0; y < h2; ++y) { + auto dst = &buffer[y * surface->stride]; + auto cmp = &cbuffer[y * surface->stride]; + auto src = &sbuffer[y * w]; //TODO: need to use image's stride + for (uint32_t x = 0; x < w2; ++x, ++dst, ++src, ++cmp) { + auto tmp = ALPHA_BLEND(*src, ALPHA_MULTIPLY(opacity, surface->blender.alpha(*cmp))); + *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); + } + } + return true; +} + + +static bool _rasterTranslucentImage(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region) +{ + if (surface->compositor) { + if (surface->compositor->method == CompositeMethod::AlphaMask) { + return _translucentImageAlphaMask(surface, img, w, h, opacity, region); + } + } + return _translucentImage(surface, img, w, h, opacity, region); +} + + static bool _rasterImage(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, const SwBBox& region) { for (auto y = region.min.y; y < region.max.y; ++y) { @@ -337,28 +441,9 @@ static bool _rasterImage(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t } -static bool _rasterSolidRle(SwSurface* surface, SwRleData* rle, uint32_t color) -{ - if (!rle) return false; - - auto span = rle->spans; - - for (uint32_t i = 0; i < rle->size; ++i) { - if (span->coverage == 255) { - rasterRGBA32(surface->buffer + span->y * surface->stride, color, span->x, span->len); - } else { - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto src = ALPHA_BLEND(color, span->coverage); - auto ialpha = 255 - span->coverage; - for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = src + ALPHA_BLEND(dst[i], ialpha); - } - } - ++span; - } - return true; -} - +/************************************************************************/ +/* Gradient */ +/************************************************************************/ static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) { @@ -609,6 +694,8 @@ bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, Sw if (transform) _inverse(transform, &invTransform); else invTransform = {1, 0, 0, 0, 1, 0, 0, 0, 1}; + auto translucent = _translucent(surface, opacity); + if (image->rle) { //Fast track if (_identify(transform)) { @@ -616,11 +703,11 @@ bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, Sw #ifdef THORVG_LOG_ENABLED printf("SW_ENGINE: implementation is missing!\n"); #endif - //if (opacity < 255) return _rasterTranslucentImageRle(surface, image->rle, image->data, image->w, image->h, opacity); + //if (translucent) return _rasterTranslucentImageRle(surface, image->rle, image->data, image->w, image->h, opacity); //return _rasterImageRle(surface, image->rle, image->data, image->w, image->h); return false; } else { - if (opacity < 255) return _rasterTranslucentImageRle(surface, image->rle, image->data, image->w, image->h, opacity, &invTransform); + if (translucent) return _rasterTranslucentImageRle(surface, image->rle, image->data, image->w, image->h, opacity, &invTransform); return _rasterImageRle(surface, image->rle, image->data, image->w, image->h, &invTransform); } } @@ -628,10 +715,10 @@ bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, Sw //Fast track if (_identify(transform)) { //OPTIMIZE ME: Support non transformed image. Only shifted image can use these routines. - if (opacity < 255) return _rasterTranslucentImage(surface, image->data, image->w, image->h, opacity, bbox); + if (translucent) return _rasterTranslucentImage(surface, image->data, image->w, image->h, opacity, bbox); else return _rasterImage(surface, image->data, image->w, image->h, bbox); } else { - if (opacity < 255) return _rasterTranslucentImage(surface, image->data, image->w, image->h, opacity, bbox, &invTransform); + if (translucent) return _rasterTranslucentImage(surface, image->data, image->w, image->h, opacity, bbox, &invTransform); else return _rasterImage(surface, image->data, image->w, image->h, bbox, &invTransform); } }