diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index a4c69926..e0db06b6 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -280,11 +280,6 @@ static inline uint32_t COLOR_INTERPOLATE(uint32_t c1, uint32_t a1, uint32_t c2, return (c1 |= t); } -static inline uint32_t ALPHA_MULTIPLY(uint32_t c, uint32_t a) -{ - return ((c * a + 0xff) >> 8); -} - static inline SwCoord HALF_STROKE(float width) { return TO_SWCOORD(width * 0.5f); diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 2b4c755b..39d01b41 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -29,6 +29,14 @@ /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ +constexpr auto DOWN_SCALE_TOLERANCE = 0.5f; + + +static inline uint32_t _multiplyAlpha(uint32_t c, uint32_t a) +{ + return ((c * a + 0xff) >> 8); +} + static uint32_t _colorAlpha(uint32_t c) { @@ -79,6 +87,7 @@ static uint32_t _applyBilinearInterpolation(const uint32_t *img, uint32_t w, uin return COLOR_INTERPOLATE(COLOR_INTERPOLATE(c1, 255 - dX, c2, dX), 255 - dY, COLOR_INTERPOLATE(c4, 255 - dX, c3, dX), dY); } + static uint32_t _average2Nx2NPixel(SwSurface* surface, const uint32_t *img, uint32_t w, uint32_t h, uint32_t rX, uint32_t rY, uint32_t n) { uint32_t c[4] = { 0 }; @@ -104,7 +113,7 @@ static uint32_t _average2Nx2NPixel(SwSurface* surface, const uint32_t *img, uint /* Rect */ /************************************************************************/ -static bool _translucentRectMask(SwSurface* surface, const SwBBox& region, uint32_t color, uint32_t (*blendMethod)(uint32_t)) +static bool _rasterTranslucentMaskedRect(SwSurface* surface, const SwBBox& region, uint32_t color, uint32_t (*blendMethod)(uint32_t)) { auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; auto h = static_cast(region.max.y - region.min.y); @@ -130,10 +139,10 @@ static bool _rasterTranslucentRect(SwSurface* surface, const SwBBox& region, uin { if (surface->compositor) { if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _translucentRectMask(surface, region, color, surface->blender.alpha); + return _rasterTranslucentMaskedRect(surface, region, color, surface->blender.alpha); } if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _translucentRectMask(surface, region, color, surface->blender.ialpha); + return _rasterTranslucentMaskedRect(surface, region, color, surface->blender.ialpha); } } @@ -164,7 +173,7 @@ static bool _rasterSolidRect(SwSurface* surface, const SwBBox& region, uint32_t /* Rle */ /************************************************************************/ -static bool _translucentRleMask(SwSurface* surface, SwRleData* rle, uint32_t color, uint32_t (*blendMethod)(uint32_t)) +static bool _rasterTranslucentMaskedRle(SwSurface* surface, SwRleData* rle, uint32_t color, uint32_t (*blendMethod)(uint32_t)) { TVGLOG("SW_ENGINE", "Rle Alpha Mask / Inverse Alpha Mask Composition"); @@ -193,10 +202,10 @@ static bool _rasterTranslucentRle(SwSurface* surface, SwRleData* rle, uint32_t c if (surface->compositor) { if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _translucentRleMask(surface, rle, color, surface->blender.alpha); + return _rasterTranslucentMaskedRle(surface, rle, color, surface->blender.alpha); } if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _translucentRleMask(surface, rle, color, surface->blender.ialpha); + return _rasterTranslucentMaskedRle(surface, rle, color, surface->blender.ialpha); } } @@ -234,93 +243,10 @@ static bool _rasterSolidRle(SwSurface* surface, const SwRleData* rle, uint32_t c /************************************************************************/ -/* Image */ +/* RLE Transformed Translucent Image */ /************************************************************************/ -static bool _translucentImageRle(SwSurface* surface, const SwImage* image, uint32_t opacity) -{ - auto span = image->rle->spans; - - for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto img = image->data + (span->y + image->y) * image->stride + (span->x + image->x); - auto alpha = ALPHA_MULTIPLY(span->coverage, opacity); - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) { - auto src = ALPHA_BLEND(*img, alpha); - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - } - return true; -} - - -static bool _translucentImageRleMask(SwSurface* surface, const SwImage* image, uint32_t opacity, uint32_t (*blendMethod)(uint32_t)) -{ - TVGLOG("SW_ENGINE", "Image Rle Alpha Mask / Inverse Alpha Mask Composition"); - - auto span = image->rle->spans; - auto cbuffer = surface->compositor->image.data; - - for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto cmp = &cbuffer[span->y * surface->stride + span->x]; - auto img = image->data + (span->y + image->y) * image->stride + (span->x + image->x); - auto alpha = ALPHA_MULTIPLY(span->coverage, opacity); - if (alpha == 255) { - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) { - auto tmp = ALPHA_BLEND(*img, blendMethod(*cmp)); - *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); - } - } else { - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) { - auto tmp = ALPHA_BLEND(*img, ALPHA_MULTIPLY(alpha, blendMethod(*cmp))); - *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); - } - } - } - return true; -} - - -static bool _rasterTranslucentImageRle(SwSurface* surface, const SwImage* image, uint32_t opacity) -{ - if (surface->compositor) { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _translucentImageRleMask(surface, image, opacity, surface->blender.alpha); - } - if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _translucentImageRleMask(surface, image, opacity, surface->blender.ialpha); - } - } - return _translucentImageRle(surface, image, opacity); -} - - -static bool _translucentImageRle(SwSurface* surface, const SwImage* image, uint32_t opacity, const Matrix* itransform) -{ - auto span = image->rle->spans; - auto img = image->data; - auto w = image->w; - auto h = image->h; - - for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto ey1 = span->y * itransform->e12 + itransform->e13; - auto ey2 = span->y * itransform->e22 + itransform->e23; - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto alpha = ALPHA_MULTIPLY(span->coverage, opacity); - for (uint32_t x = 0; x < span->len; ++x, ++dst) { - auto rX = static_cast(roundf((span->x + x) * itransform->e11 + ey1)); - auto rY = static_cast(roundf((span->x + x) * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - auto src = ALPHA_BLEND(img[rY * image->stride + rX], alpha); - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - } - return true; -} - - -static bool _translucentImageRleMask(SwSurface* surface, const SwImage* image, uint32_t opacity, const Matrix* itransform, uint32_t (*blendMethod)(uint32_t)) +static bool _rasterTransformedMaskedRleImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const Matrix* itransform, uint32_t (*blendMethod)(uint32_t)) { TVGLOG("SW_ENGINE", "Transformed Image Rle Alpha Mask / Inverse Alpha Mask Composition"); @@ -335,7 +261,7 @@ static bool _translucentImageRleMask(SwSurface* surface, const SwImage* image, u auto ey2 = span->y * itransform->e22 + itransform->e23; auto dst = &surface->buffer[span->y * surface->stride + span->x]; auto cmp = &cbuffer[span->y * surface->stride + span->x]; - auto alpha = ALPHA_MULTIPLY(span->coverage, opacity); + auto alpha = _multiplyAlpha(span->coverage, opacity); if (alpha == 255) { for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) { auto rX = static_cast(roundf((span->x + x) * itransform->e11 + ey1)); @@ -359,21 +285,7 @@ static bool _translucentImageRleMask(SwSurface* surface, const SwImage* image, u } -static bool _rasterTranslucentImageRle(SwSurface* surface, const SwImage* image, uint32_t opacity, const Matrix* itransform) -{ - if (surface->compositor) { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _translucentImageRleMask(surface, image, opacity, itransform, surface->blender.alpha); - } - if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _translucentImageRleMask(surface, image, opacity, itransform, surface->blender.ialpha); - } - } - return _translucentImageRle(surface, image, opacity, itransform); -} - - -static bool _translucentUpScaleImageRle(SwSurface* surface, const SwImage* image, uint32_t opacity, const Matrix* itransform) +static bool _rasterTransformedTranslucentRleImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const Matrix* itransform) { auto span = image->rle->spans; auto img = image->data; @@ -384,7 +296,150 @@ static bool _translucentUpScaleImageRle(SwSurface* surface, const SwImage* image auto ey1 = span->y * itransform->e12 + itransform->e13; auto ey2 = span->y * itransform->e22 + itransform->e23; auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto alpha = ALPHA_MULTIPLY(span->coverage, opacity); + auto alpha = _multiplyAlpha(span->coverage, opacity); + for (uint32_t x = 0; x < span->len; ++x, ++dst) { + auto rX = static_cast(roundf((span->x + x) * itransform->e11 + ey1)); + auto rY = static_cast(roundf((span->x + x) * itransform->e21 + ey2)); + if (rX >= w || rY >= h) continue; + auto src = ALPHA_BLEND(img[rY * image->stride + rX], alpha); + *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); + } + } + return true; +} + + +static bool _rasterDownScaledMaskedRleImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const Matrix* itransform, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t)) +{ + TVGLOG("SW_ENGINE", "Image Rle Alpha Mask / Inverse Alpha Mask Composition"); + + auto span = image->rle->spans; + auto img = image->data; + auto w = image->w; + auto h = image->h; + auto cbuffer = surface->compositor->image.data; + + for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { + auto ey1 = span->y * itransform->e12 + itransform->e13; + auto ey2 = span->y * itransform->e22 + itransform->e23; + auto dst = &surface->buffer[span->y * surface->stride + span->x]; + auto cmp = &cbuffer[span->y * surface->stride + span->x]; + auto alpha = _multiplyAlpha(span->coverage, opacity); + + if (alpha == 255) { + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) { + auto rX = static_cast(roundf((span->x + x) * itransform->e11 + ey1)); + auto rY = static_cast(roundf((span->x + x) * itransform->e21 + ey2)); + if (rX >= w || rY >= h) continue; + uint32_t src; + if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha); + else src = ALPHA_BLEND(_average2Nx2NPixel(surface, img, image->stride, h, rX, rY, halfScale), alpha); + auto tmp = ALPHA_BLEND(src, blendMethod(*cmp)); + *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); + } + } else { + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) { + auto rX = static_cast(roundf((span->x + x) * itransform->e11 + ey1)); + auto rY = static_cast(roundf((span->x + x) * itransform->e21 + ey2)); + if (rX >= w || rY >= h) continue; + uint32_t src; + if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha); + else src = ALPHA_BLEND(_average2Nx2NPixel(surface, img, image->stride, h, rX, rY, halfScale), alpha); + auto tmp = ALPHA_BLEND(src, _multiplyAlpha(alpha, blendMethod(*cmp))); + *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); + } + } + } + return true; +} + + +static bool _rasterDownScaledTranslucentRleImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const Matrix* itransform, uint32_t halfScale) +{ + auto span = image->rle->spans; + auto img = image->data; + auto w = image->w; + auto h = image->h; + + for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { + auto ey1 = span->y * itransform->e12 + itransform->e13; + auto ey2 = span->y * itransform->e22 + itransform->e23; + auto dst = &surface->buffer[span->y * surface->stride + span->x]; + auto alpha = _multiplyAlpha(span->coverage, opacity); + for (uint32_t x = 0; x < span->len; ++x, ++dst) { + auto rX = static_cast(roundf((span->x + x) * itransform->e11 + ey1)); + auto rY = static_cast(roundf((span->x + x) * itransform->e21 + ey2)); + if (rX >= w || rY >= h) continue; + uint32_t src; + if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha); + else src = ALPHA_BLEND(_average2Nx2NPixel(surface, img, image->stride, h, rX, rY, halfScale), alpha); + *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); + } + } + return true; +} + + +static bool _rasterUpScaledMaskedRleImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const Matrix* itransform, uint32_t (*blendMethod)(uint32_t)) +{ + TVGLOG("SW_ENGINE", "Image Rle Alpha Mask / Inverse Alpha Mask Composition"); + + auto span = image->rle->spans; + auto img = image->data; + auto w = image->w; + auto h = image->h; + auto cbuffer = surface->compositor->image.data; + + for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { + auto ey1 = span->y * itransform->e12 + itransform->e13; + auto ey2 = span->y * itransform->e22 + itransform->e23; + auto dst = &surface->buffer[span->y * surface->stride + span->x]; + auto cmp = &cbuffer[span->y * surface->stride + span->x]; + auto alpha = _multiplyAlpha(span->coverage, opacity); + if (alpha == 255) { + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) { + auto fX = (span->x + x) * itransform->e11 + ey1; + auto fY = (span->x + x) * itransform->e21 + ey2; + auto rX = static_cast(roundf(fX)); + auto rY = static_cast(roundf(fY)); + if (rX >= w || rY >= h) continue; + uint32_t src; + if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha); + else src = ALPHA_BLEND(_applyBilinearInterpolation(img, image->stride, h, fX, fY), alpha); + auto tmp = ALPHA_BLEND(src, blendMethod(*cmp)); + *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); + } + } else { + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) { + auto fX = (span->x + x) * itransform->e11 + ey1; + auto fY = (span->x + x) * itransform->e21 + ey2; + auto rX = static_cast(roundf(fX)); + auto rY = static_cast(roundf(fY)); + if (rX >= w || rY >= h) continue; + uint32_t src; + if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha); + else src = ALPHA_BLEND(_applyBilinearInterpolation(img, image->stride, h, fX, fY), alpha); + auto tmp = ALPHA_BLEND(src, _multiplyAlpha(alpha, blendMethod(*cmp))); + *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); + } + } + } + return true; +} + + +static bool _rasterUpScaledTranslucentRleImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const Matrix* itransform) +{ + auto span = image->rle->spans; + auto img = image->data; + auto w = image->w; + auto h = image->h; + + for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { + auto ey1 = span->y * itransform->e12 + itransform->e13; + auto ey2 = span->y * itransform->e22 + itransform->e23; + auto dst = &surface->buffer[span->y * surface->stride + span->x]; + auto alpha = _multiplyAlpha(span->coverage, opacity); for (uint32_t x = 0; x < span->len; ++x, ++dst) { auto fX = (span->x + x) * itransform->e11 + ey1; auto fY = (span->x + x) * itransform->e21 + ey2; @@ -401,69 +456,47 @@ static bool _translucentUpScaleImageRle(SwSurface* surface, const SwImage* image } -static bool _translucentUpScaleImageRleMask(SwSurface* surface, const SwImage* image, uint32_t opacity, const Matrix* itransform, uint32_t (*blendMethod)(uint32_t)) +static bool _rasterTransformedTranslucentRleImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const Matrix* itransform, uint32_t halfScale) { - TVGLOG("SW_ENGINE", "Image Rle Alpha Mask / Inverse Alpha Mask Composition"); - - auto span = image->rle->spans; - auto img = image->data; - auto w = image->w; - auto h = image->h; - auto cbuffer = surface->compositor->image.data; - - for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto ey1 = span->y * itransform->e12 + itransform->e13; - auto ey2 = span->y * itransform->e22 + itransform->e23; - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto cmp = &cbuffer[span->y * surface->stride + span->x]; - auto alpha = ALPHA_MULTIPLY(span->coverage, opacity); - if (alpha == 255) { - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) { - auto fX = (span->x + x) * itransform->e11 + ey1; - auto fY = (span->x + x) * itransform->e21 + ey2; - auto rX = static_cast(roundf(fX)); - auto rY = static_cast(roundf(fY)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha); - else src = ALPHA_BLEND(_applyBilinearInterpolation(img, image->stride, h, fX, fY), alpha); - auto tmp = ALPHA_BLEND(src, blendMethod(*cmp)); - *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); - } - } else { - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) { - auto fX = (span->x + x) * itransform->e11 + ey1; - auto fY = (span->x + x) * itransform->e21 + ey2; - auto rX = static_cast(roundf(fX)); - auto rY = static_cast(roundf(fY)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha); - else src = ALPHA_BLEND(_applyBilinearInterpolation(img, image->stride, h, fX, fY), alpha); - auto tmp = ALPHA_BLEND(src, ALPHA_MULTIPLY(alpha, blendMethod(*cmp))); - *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); + //Transformed + if (mathEqual(image->scale, 1.0f)) { + if (surface->compositor) { + if (surface->compositor->method == CompositeMethod::AlphaMask) { + return _rasterTransformedMaskedRleImage(surface, image, opacity, itransform, surface->blender.alpha); + } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { + return _rasterTransformedMaskedRleImage(surface, image, opacity, itransform, surface->blender.ialpha); } } + return _rasterTransformedTranslucentRleImage(surface, image, opacity, itransform); + //Transformed + Down Scaled + } else if (image->scale < DOWN_SCALE_TOLERANCE) { + if (surface->compositor) { + if (surface->compositor->method == CompositeMethod::AlphaMask) { + return _rasterDownScaledMaskedRleImage(surface, image, opacity, itransform, halfScale, surface->blender.alpha); + } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { + return _rasterDownScaledMaskedRleImage(surface, image, opacity, itransform, halfScale, surface->blender.ialpha); + } + } + return _rasterDownScaledTranslucentRleImage(surface, image, opacity, itransform, halfScale); + //Transformed + Up Scaled + } else { + if (surface->compositor) { + if (surface->compositor->method == CompositeMethod::AlphaMask) { + return _rasterUpScaledMaskedRleImage(surface, image, opacity, itransform, surface->blender.alpha); + } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { + return _rasterUpScaledMaskedRleImage(surface, image, opacity, itransform, surface->blender.ialpha); + } + } + return _rasterUpScaledTranslucentRleImage(surface, image, opacity, itransform); } - return true; } -static bool _rasterTranslucentUpScaleImageRle(SwSurface* surface, const SwImage* image, uint32_t opacity, const Matrix* itransform) -{ - if (surface->compositor) { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _translucentUpScaleImageRleMask(surface, image, opacity, itransform, surface->blender.alpha); - } - if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _translucentUpScaleImageRleMask(surface, image, opacity, itransform, surface->blender.ialpha); - } - } - return _translucentUpScaleImageRle(surface, image, opacity, itransform); -} +/************************************************************************/ +/* RLE Transformed Solid Image */ +/************************************************************************/ - -static bool _translucentDownScaleImageRle(SwSurface* surface, const SwImage* image, uint32_t opacity, const Matrix* itransform, uint32_t halfScale) +static bool _rasterSolidRleImage(SwSurface* surface, const SwImage* image, const Matrix* itransform) { auto span = image->rle->spans; auto img = image->data; @@ -474,112 +507,7 @@ static bool _translucentDownScaleImageRle(SwSurface* surface, const SwImage* ima auto ey1 = span->y * itransform->e12 + itransform->e13; auto ey2 = span->y * itransform->e22 + itransform->e23; auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto alpha = ALPHA_MULTIPLY(span->coverage, opacity); - for (uint32_t x = 0; x < span->len; ++x, ++dst) { - auto rX = static_cast(roundf((span->x + x) * itransform->e11 + ey1)); - auto rY = static_cast(roundf((span->x + x) * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha); - else src = ALPHA_BLEND(_average2Nx2NPixel(surface, img, image->stride, h, rX, rY, halfScale), alpha); - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - } - return true; -} -static bool _translucentDownScaleImageRleMask(SwSurface* surface, const SwImage* image, uint32_t opacity, const Matrix* itransform, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t)) -{ - TVGLOG("SW_ENGINE", "Image Rle Alpha Mask / Inverse Alpha Mask Composition"); - - auto span = image->rle->spans; - auto img = image->data; - auto w = image->w; - auto h = image->h; - auto cbuffer = surface->compositor->image.data; - - for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto ey1 = span->y * itransform->e12 + itransform->e13; - auto ey2 = span->y * itransform->e22 + itransform->e23; - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto cmp = &cbuffer[span->y * surface->stride + span->x]; - auto alpha = ALPHA_MULTIPLY(span->coverage, opacity); - - if (alpha == 255) { - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) { - auto rX = static_cast(roundf((span->x + x) * itransform->e11 + ey1)); - auto rY = static_cast(roundf((span->x + x) * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha); - else src = ALPHA_BLEND(_average2Nx2NPixel(surface, img, image->stride, h, rX, rY, halfScale), alpha); - auto tmp = ALPHA_BLEND(src, blendMethod(*cmp)); - *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); - } - } else { - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) { - auto rX = static_cast(roundf((span->x + x) * itransform->e11 + ey1)); - auto rY = static_cast(roundf((span->x + x) * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha); - else src = ALPHA_BLEND(_average2Nx2NPixel(surface, img, image->stride, h, rX, rY, halfScale), alpha); - auto tmp = ALPHA_BLEND(src, ALPHA_MULTIPLY(alpha, blendMethod(*cmp))); - *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); - } - } - } - return true; -} - - -static bool _rasterTranslucentDownScaleImageRle(SwSurface* surface, const SwImage* image, uint32_t opacity, const Matrix* itransform, uint32_t halfScale) -{ - if (surface->compositor) { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _translucentDownScaleImageRleMask(surface, image, opacity, itransform, halfScale, surface->blender.alpha); - } - if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _translucentDownScaleImageRleMask(surface, image, opacity, itransform, halfScale, surface->blender.ialpha); - } - } - return _translucentDownScaleImageRle(surface, image, opacity, itransform, halfScale); -} - - -static bool _rasterImageRle(SwSurface* surface, const SwImage* image) -{ - auto span = image->rle->spans; - - for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto img = image->data + (span->y + image->y) * image->stride + (span->x + image->x); - if (span->coverage == 255) { - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) { - *dst = *img; - } - } else { - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) { - auto src = ALPHA_BLEND(*img, span->coverage); - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - } - } - return true; -} - - -static bool _rasterImageRle(SwSurface* surface, const SwImage* image, const Matrix* itransform) -{ - auto span = image->rle->spans; - auto img = image->data; - auto w = image->w; - auto h = image->h; - - for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto ey1 = span->y * itransform->e12 + itransform->e13; - auto ey2 = span->y * itransform->e22 + itransform->e23; - auto dst = &surface->buffer[span->y * surface->stride + span->x]; for (uint32_t x = 0; x < span->len; ++x, ++dst) { auto rX = static_cast(roundf((span->x + x) * itransform->e11 + ey1)); auto rY = static_cast(roundf((span->x + x) * itransform->e21 + ey2)); @@ -592,7 +520,33 @@ static bool _rasterImageRle(SwSurface* surface, const SwImage* image, const Matr } -static bool _rasterUpScaleImageRle(SwSurface* surface, const SwImage* image, const Matrix* itransform) +static bool _rasterDownScaledSolidRleImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t halfScale) +{ + auto span = image->rle->spans; + auto img = image->data; + auto w = image->w; + auto h = image->h; + + for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { + auto ey1 = span->y * itransform->e12 + itransform->e13; + auto ey2 = span->y * itransform->e22 + itransform->e23; + auto dst = &surface->buffer[span->y * surface->stride + span->x]; + for (uint32_t x = 0; x < span->len; ++x, ++dst) { + auto rX = static_cast(roundf((span->x + x) * itransform->e11 + ey1)); + auto rY = static_cast(roundf((span->x + x) * itransform->e21 + ey2)); + if (rX >= w || rY >= h) continue; + + uint32_t src; + if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rY * image->stride + rX], span->coverage); + else src = ALPHA_BLEND(_average2Nx2NPixel(surface, img, image->stride, h, rX, rY, halfScale), span->coverage); + *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); + } + } + return true; +} + + +static bool _rasterUpScaledSolidRleImage(SwSurface* surface, const SwImage* image, const Matrix* itransform) { auto span = image->rle->spans; auto img = image->data; @@ -619,56 +573,103 @@ static bool _rasterUpScaleImageRle(SwSurface* surface, const SwImage* image, con } -static bool _rasterDownScaleImageRle(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t halfScale) +static bool _rasterTransformedSolidRleImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t halfScale) +{ + if (mathEqual(image->scale, 1.0f)) return _rasterSolidRleImage(surface, image, itransform); + else if (image->scale < DOWN_SCALE_TOLERANCE) return _rasterDownScaledSolidRleImage(surface, image, itransform, halfScale); + else return _rasterUpScaledSolidRleImage(surface, image, itransform); +} + + +/************************************************************************/ +/* RLE Direct (Solid + Translucent) Image */ +/************************************************************************/ + +static bool _rasterDirectMaskedRleImage(SwSurface* surface, const SwImage* image, uint32_t opacity, uint32_t (*blendMethod)(uint32_t)) { + TVGLOG("SW_ENGINE", "Image Rle Alpha Mask / Inverse Alpha Mask Composition"); + auto span = image->rle->spans; - auto img = image->data; - auto w = image->w; - auto h = image->h; + auto cbuffer = surface->compositor->image.data; for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto ey1 = span->y * itransform->e12 + itransform->e13; - auto ey2 = span->y * itransform->e22 + itransform->e23; auto dst = &surface->buffer[span->y * surface->stride + span->x]; - for (uint32_t x = 0; x < span->len; ++x, ++dst) { - auto rX = static_cast(roundf((span->x + x) * itransform->e11 + ey1)); - auto rY = static_cast(roundf((span->x + x) * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rY * image->stride + rX], span->coverage); - else src = ALPHA_BLEND(_average2Nx2NPixel(surface, img, image->stride, h, rX, rY, halfScale), span->coverage); - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); + auto cmp = &cbuffer[span->y * surface->stride + span->x]; + auto img = image->data + (span->y + image->y) * image->stride + (span->x + image->x); + auto alpha = _multiplyAlpha(span->coverage, opacity); + if (alpha == 255) { + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) { + auto tmp = ALPHA_BLEND(*img, blendMethod(*cmp)); + *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); + } + } else { + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++img) { + auto tmp = ALPHA_BLEND(*img, _multiplyAlpha(alpha, blendMethod(*cmp))); + *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); + } } } return true; } -static bool _translucentImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform) +static bool __rasterDirectTranslucentRleImage(SwSurface* surface, const SwImage* image, uint32_t opacity) { - auto img = image->data; - auto w = image->w; - auto h = image->h; - auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x]; + auto span = image->rle->spans; - for (auto y = region.min.y; y < region.max.y; ++y) { - auto dst = dbuffer; - auto ey1 = y * itransform->e12 + itransform->e13; - auto ey2 = y * itransform->e22 + itransform->e23; - for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { - auto rX = static_cast(roundf(x * itransform->e11 + ey1)); - auto rY = static_cast(roundf(x * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - auto src = ALPHA_BLEND(img[rX + (rY * image->stride)], opacity); + for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { + auto dst = &surface->buffer[span->y * surface->stride + span->x]; + auto img = image->data + (span->y + image->y) * image->stride + (span->x + image->x); + auto alpha = _multiplyAlpha(span->coverage, opacity); + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) { + auto src = ALPHA_BLEND(*img, alpha); *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); } - dbuffer += surface->stride; } return true; } -static bool _translucentImageMask(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform, uint32_t (*blendMethod)(uint32_t)) +static bool _rasterDirectTranslucentRleImage(SwSurface* surface, const SwImage* image, uint32_t opacity) +{ + if (surface->compositor) { + if (surface->compositor->method == CompositeMethod::AlphaMask) { + return _rasterDirectMaskedRleImage(surface, image, opacity, surface->blender.alpha); + } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { + return _rasterDirectMaskedRleImage(surface, image, opacity, surface->blender.ialpha); + } + } + return __rasterDirectTranslucentRleImage(surface, image, opacity); +} + + +static bool _rasterDirectSolidRleImage(SwSurface* surface, const SwImage* image) +{ + auto span = image->rle->spans; + + for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { + auto dst = &surface->buffer[span->y * surface->stride + span->x]; + auto img = image->data + (span->y + image->y) * image->stride + (span->x + image->x); + if (span->coverage == 255) { + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) { + *dst = *img; + } + } else { + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) { + auto src = ALPHA_BLEND(*img, span->coverage); + *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); + } + } + } + return true; +} + + +/************************************************************************/ +/* Whole Transformed Translucent Image */ +/************************************************************************/ + +static bool _rasterTransformedMaskedImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform, uint32_t (*blendMethod)(uint32_t)) { TVGLOG("SW_ENGINE", "Transformed Image AlphaMask / Inverse Alpha Mask Composition"); @@ -687,7 +688,7 @@ static bool _translucentImageMask(SwSurface* surface, const SwImage* image, uint auto rX = static_cast(roundf(x * itransform->e11 + ey1)); auto rY = static_cast(roundf(x * itransform->e21 + ey2)); if (rX >= w || rY >= h) continue; - auto src = ALPHA_BLEND(img[rX + (rY * image->stride)], ALPHA_MULTIPLY(opacity, blendMethod(*cmp))); + auto src = ALPHA_BLEND(img[rX + (rY * image->stride)], _multiplyAlpha(opacity, blendMethod(*cmp))); *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); } dbuffer += surface->stride; @@ -697,21 +698,125 @@ static bool _translucentImageMask(SwSurface* surface, const SwImage* image, uint } -static bool _rasterTranslucentImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform) +static bool _rasterTransformedTranslucentImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform) { - if (surface->compositor) { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _translucentImageMask(surface, image, opacity, region, itransform, surface->blender.alpha); - } - if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _translucentImageMask(surface, image, opacity, region, itransform, surface->blender.ialpha); + auto img = image->data; + auto w = image->w; + auto h = image->h; + auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x]; + + for (auto y = region.min.y; y < region.max.y; ++y) { + auto dst = dbuffer; + auto ey1 = y * itransform->e12 + itransform->e13; + auto ey2 = y * itransform->e22 + itransform->e23; + for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { + auto rX = static_cast(roundf(x * itransform->e11 + ey1)); + auto rY = static_cast(roundf(x * itransform->e21 + ey2)); + if (rX >= w || rY >= h) continue; + + auto src = ALPHA_BLEND(img[rX + (rY * image->stride)], opacity); + *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); } + dbuffer += surface->stride; } - return _translucentImage(surface, image, opacity, region, itransform); + return true; } -static bool _translucentUpScaleImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform) +static bool _rasterDownScaledMaskedImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t)) +{ + TVGLOG("SW_ENGINE", "Transformed Image Alpha Mask / Inverse Alpha Mask Composition"); + + auto img = image->data; + auto w = image->w; + auto h = image->h; + auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x]; + auto cbuffer = &surface->compositor->image.data[region.min.y * surface->stride + region.min.x]; + + for (auto y = region.min.y; y < region.max.y; ++y) { + auto dst = dbuffer; + auto cmp = cbuffer; + float ey1 = y * itransform->e12 + itransform->e13; + float ey2 = y * itransform->e22 + itransform->e23; + for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) { + auto rX = static_cast(roundf(x * itransform->e11 + ey1)); + auto rY = static_cast(roundf(x * itransform->e21 + ey2)); + if (rX >= w || rY >= h) continue; + uint32_t src; + if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) { + src = ALPHA_BLEND(img[rX + (rY * image->stride)], _multiplyAlpha(opacity, blendMethod(*cmp))); + } else { + src = ALPHA_BLEND(_average2Nx2NPixel(surface, img, image->stride, h, rX, rY, halfScale), _multiplyAlpha(opacity, blendMethod(*cmp))); + } + *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); + } + dbuffer += surface->stride; + cbuffer += surface->stride; + } + return true; +} + + +static bool _rasterDownScaledTranslucentImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform, uint32_t halfScale) +{ + auto img = image->data; + auto w = image->w; + auto h = image->h; + auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x]; + + for (auto y = region.min.y; y < region.max.y; ++y) { + auto dst = dbuffer; + auto ey1 = y * itransform->e12 + itransform->e13; + auto ey2 = y * itransform->e22 + itransform->e23; + for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { + auto rX = static_cast(roundf(x * itransform->e11 + ey1)); + auto rY = static_cast(roundf(x * itransform->e21 + ey2)); + if (rX >= w || rY >= h) continue; + uint32_t src; + if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rX + (rY * w)], opacity); + else src = ALPHA_BLEND(_average2Nx2NPixel(surface, img, w, h, rX, rY, halfScale), opacity); + *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); + } + dbuffer += surface->stride; + } + return true; +} + + +static bool _rasterUpScaledMaskedImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform, uint32_t (*blendMethod)(uint32_t)) +{ + TVGLOG("SW_ENGINE", "Transformed Image Alpha Mask / Inverse Alpha Mask Composition"); + + auto img = image->data; + auto w = image->w; + auto h = image->h; + auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x]; + auto cbuffer = &surface->compositor->image.data[region.min.y * surface->stride + region.min.x]; + + for (auto y = region.min.y; y < region.max.y; ++y) { + auto dst = dbuffer; + auto cmp = cbuffer; + float ey1 = y * itransform->e12 + itransform->e13; + float ey2 = y * itransform->e22 + itransform->e23; + for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) { + auto fX = x * itransform->e11 + ey1; + auto fY = x * itransform->e21 + ey2; + auto rX = static_cast(roundf(fX)); + auto rY = static_cast(roundf(fY)); + if (rX >= w || rY >= h) continue; + uint32_t src; + if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rX + (rY * image->stride)], _multiplyAlpha(opacity, blendMethod(*cmp))); + else src = ALPHA_BLEND(_applyBilinearInterpolation(img, image->stride, h, fX, fY), _multiplyAlpha(opacity, blendMethod(*cmp))); + *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); + } + dbuffer += surface->stride; + cbuffer += surface->stride; + } + return true; +} + + +static bool _rasterUpScaledTranslucentImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform) { auto img = image->data; auto w = image->w; @@ -739,206 +844,48 @@ static bool _translucentUpScaleImage(SwSurface* surface, const SwImage* image, u } -static bool _translucentUpScaleImageMask(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform, uint32_t (*blendMethod)(uint32_t)) +static bool _rasterTransformedTranslucentImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform, uint32_t halfScale) { - TVGLOG("SW_ENGINE", "Transformed Image Alpha Mask / Inverse Alpha Mask Composition"); - - auto img = image->data; - auto w = image->w; - auto h = image->h; - auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x]; - auto cbuffer = &surface->compositor->image.data[region.min.y * surface->stride + region.min.x]; - - for (auto y = region.min.y; y < region.max.y; ++y) { - auto dst = dbuffer; - auto cmp = cbuffer; - float ey1 = y * itransform->e12 + itransform->e13; - float ey2 = y * itransform->e22 + itransform->e23; - for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) { - auto fX = x * itransform->e11 + ey1; - auto fY = x * itransform->e21 + ey2; - auto rX = static_cast(roundf(fX)); - auto rY = static_cast(roundf(fY)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rX + (rY * image->stride)], ALPHA_MULTIPLY(opacity, blendMethod(*cmp))); - else src = ALPHA_BLEND(_applyBilinearInterpolation(img, image->stride, h, fX, fY), ALPHA_MULTIPLY(opacity, blendMethod(*cmp))); - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - dbuffer += surface->stride; - cbuffer += surface->stride; - } - return true; -} - - -static bool _rasterTranslucentUpScaleImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform) -{ - if (surface->compositor) { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _translucentUpScaleImageMask(surface, image, opacity, region, itransform, surface->blender.alpha); - } - if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _translucentUpScaleImageMask(surface, image, opacity, region, itransform, surface->blender.ialpha); - } - } - return _translucentUpScaleImage(surface, image, opacity, region, itransform); -} - - -static bool _translucentDownScaleImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform, uint32_t halfScale) -{ - auto img = image->data; - auto w = image->w; - auto h = image->h; - auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x]; - - for (auto y = region.min.y; y < region.max.y; ++y) { - auto dst = dbuffer; - auto ey1 = y * itransform->e12 + itransform->e13; - auto ey2 = y * itransform->e22 + itransform->e23; - for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { - auto rX = static_cast(roundf(x * itransform->e11 + ey1)); - auto rY = static_cast(roundf(x * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rX + (rY * w)], opacity); - else src = ALPHA_BLEND(_average2Nx2NPixel(surface, img, w, h, rX, rY, halfScale), opacity); - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - dbuffer += surface->stride; - } - return true; -} - - -static bool _translucentDownScaleImageMask(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t)) -{ - TVGLOG("SW_ENGINE", "Transformed Image Alpha Mask / Inverse Alpha Mask Composition"); - - auto img = image->data; - auto w = image->w; - auto h = image->h; - auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x]; - auto cbuffer = &surface->compositor->image.data[region.min.y * surface->stride + region.min.x]; - - for (auto y = region.min.y; y < region.max.y; ++y) { - auto dst = dbuffer; - auto cmp = cbuffer; - float ey1 = y * itransform->e12 + itransform->e13; - float ey2 = y * itransform->e22 + itransform->e23; - for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) { - auto rX = static_cast(roundf(x * itransform->e11 + ey1)); - auto rY = static_cast(roundf(x * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) { - src = ALPHA_BLEND(img[rX + (rY * image->stride)], ALPHA_MULTIPLY(opacity, blendMethod(*cmp))); - } else { - src = ALPHA_BLEND(_average2Nx2NPixel(surface, img, image->stride, h, rX, rY, halfScale), ALPHA_MULTIPLY(opacity, blendMethod(*cmp))); + //Transformd + if (mathEqual(image->scale, 1.0f)) { + if (surface->compositor) { + if (surface->compositor->method == CompositeMethod::AlphaMask) { + return _rasterTransformedMaskedImage(surface, image, opacity, region, itransform, surface->blender.alpha); + } + if (surface->compositor->method == CompositeMethod::InvAlphaMask) { + return _rasterTransformedMaskedImage(surface, image, opacity, region, itransform, surface->blender.ialpha); } - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); } - dbuffer += surface->stride; - cbuffer += surface->stride; + return _rasterTransformedTranslucentImage(surface, image, opacity, region, itransform); + //Transformed + DownScaled + } else if (image->scale < DOWN_SCALE_TOLERANCE) { + if (surface->compositor) { + if (surface->compositor->method == CompositeMethod::AlphaMask) { + return _rasterDownScaledMaskedImage(surface, image, opacity, region, itransform, halfScale, surface->blender.alpha); + } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { + return _rasterDownScaledMaskedImage(surface, image, opacity, region, itransform, halfScale, surface->blender.ialpha); + } + } + return _rasterDownScaledTranslucentImage(surface, image, opacity, region, itransform, halfScale); + //Transformed + UpScaled + } else { + if (surface->compositor) { + if (surface->compositor->method == CompositeMethod::AlphaMask) { + return _rasterUpScaledMaskedImage(surface, image, opacity, region, itransform, surface->blender.alpha); + }else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { + return _rasterUpScaledMaskedImage(surface, image, opacity, region, itransform, surface->blender.ialpha); + } + } + return _rasterUpScaledTranslucentImage(surface, image, opacity, region, itransform); } - return true; } -static bool _rasterTranslucentDownScaleImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, const Matrix* itransform, uint32_t halfScale) -{ - if (surface->compositor) { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _translucentDownScaleImageMask(surface, image, opacity, region, itransform, halfScale, surface->blender.alpha); - } - if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _translucentDownScaleImageMask(surface, image, opacity, region, itransform, halfScale, surface->blender.ialpha); - } - } - return _translucentDownScaleImage(surface, image, opacity, region, itransform, halfScale); -} +/************************************************************************/ +/* Whole Transformed Solid Image */ +/************************************************************************/ - -static bool _translucentImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region) -{ - auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x]; - auto sbuffer = image->data + (region.min.y + image->y) * image->stride + (region.min.x + image->x); - - for (auto y = region.min.y; y < region.max.y; ++y) { - auto dst = dbuffer; - auto src = sbuffer; - for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) { - auto p = ALPHA_BLEND(*src, opacity); - *dst = p + ALPHA_BLEND(*dst, surface->blender.ialpha(p)); - } - dbuffer += surface->stride; - sbuffer += image->stride; - } - return true; -} - - -static bool _translucentImageMask(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, uint32_t (*blendMethod)(uint32_t)) -{ - 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); - - TVGLOG("SW_ENGINE", "Image Alpha Mask / Inverse Alpha Mask Composition"); - - auto sbuffer = image->data + (region.min.y + image->y) * image->stride + (region.min.x + image->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; - auto cmp = cbuffer; - auto src = sbuffer; - for (uint32_t x = 0; x < w2; ++x, ++dst, ++src, ++cmp) { - auto tmp = ALPHA_BLEND(*src, ALPHA_MULTIPLY(opacity, blendMethod(*cmp))); - *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); - } - buffer += surface->stride; - cbuffer += surface->stride; - sbuffer += image->stride; - } - return true; -} - - -static bool _rasterTranslucentImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region) -{ - if (surface->compositor) { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _translucentImageMask(surface, image, opacity, region, surface->blender.alpha); - } - if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _translucentImageMask(surface, image, opacity, region, surface->blender.ialpha); - } - } - return _translucentImage(surface, image, opacity, region); -} - - -static bool _rasterImage(SwSurface* surface, const SwImage* image, const SwBBox& region) -{ - auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x]; - auto sbuffer = image->data + (region.min.y + image->y) * image->stride + (region.min.x + image->x); - - for (auto y = region.min.y; y < region.max.y; ++y) { - auto dst = dbuffer; - auto src = sbuffer; - for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) { - *dst = *src + ALPHA_BLEND(*dst, surface->blender.ialpha(*src)); - } - dbuffer += surface->stride; - sbuffer += image->stride; - } - return true; -} - - -static bool _rasterImage(SwSurface* surface, const SwImage* image, const SwBBox& region, const Matrix* itransform) +static bool _rasterTransformedSolidImage(SwSurface* surface, const SwImage* image, const SwBBox& region, const Matrix* itransform) { auto img = image->data; auto w = image->w; @@ -960,7 +907,31 @@ static bool _rasterImage(SwSurface* surface, const SwImage* image, const SwBBox& } -static bool _rasterUpScaleImage(SwSurface* surface, const SwImage* image, const SwBBox& region, const Matrix* itransform) +static bool _rasterDownScaledSolidImage(SwSurface* surface, const SwImage* image, const SwBBox& region, const Matrix* itransform, uint32_t halfScale) +{ + auto img = image->data; + auto w = image->w; + auto h = image->h; + + for (auto y = region.min.y; y < region.max.y; ++y) { + auto dst = &surface->buffer[y * surface->stride + region.min.x]; + auto ey1 = y * itransform->e12 + itransform->e13; + auto ey2 = y * itransform->e22 + itransform->e23; + for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { + auto rX = static_cast(roundf(x * itransform->e11 + ey1)); + auto rY = static_cast(roundf(x * itransform->e21 + ey2)); + if (rX >= w || rY >= h) continue; + uint32_t src; + if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = img[rX + (rY * w)]; + else src = _average2Nx2NPixel(surface, img, w, h, rX, rY, halfScale); + *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); + } + } + return true; +} + + +static bool _rasterUpScaledSolidImage(SwSurface* surface, const SwImage* image, const SwBBox& region, const Matrix* itransform) { auto img = image->data; auto w = image->w; @@ -986,61 +957,100 @@ static bool _rasterUpScaleImage(SwSurface* surface, const SwImage* image, const } -static bool _rasterDownScaleImage(SwSurface* surface, const SwImage* image, const SwBBox& region, const Matrix* itransform, float scale) -{ - auto img = image->data; - auto w = image->w; - auto h = image->h; +static bool _rasterTransformedSolidImage(SwSurface* surface, const SwImage* image, const SwBBox& region, const Matrix* itransform, uint32_t halfScale) +{ + if (mathEqual(image->scale, 1.0f)) return _rasterTransformedSolidImage(surface, image, region, itransform); + else if (image->scale < DOWN_SCALE_TOLERANCE) return _rasterDownScaledSolidImage(surface, image, region, itransform, halfScale); + else return _rasterUpScaledSolidImage(surface, image, region, itransform); +} - auto halfScale = static_cast(0.5f / scale); - if (halfScale == 0) halfScale = 1; + +/************************************************************************/ +/* Whole (Solid + Translucent) Direct Image */ +/************************************************************************/ + +static bool _rasterDirectMaskedImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region, uint32_t (*blendMethod)(uint32_t)) +{ + 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); + + TVGLOG("SW_ENGINE", "Image Alpha Mask / Inverse Alpha Mask Composition"); + + auto sbuffer = image->data + (region.min.y + image->y) * image->stride + (region.min.x + image->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; + auto cmp = cbuffer; + auto src = sbuffer; + for (uint32_t x = 0; x < w2; ++x, ++dst, ++src, ++cmp) { + auto tmp = ALPHA_BLEND(*src, _multiplyAlpha(opacity, blendMethod(*cmp))); + *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); + } + buffer += surface->stride; + cbuffer += surface->stride; + sbuffer += image->stride; + } + return true; +} + + +static bool __rasterDirectTranslucentImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region) +{ + auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x]; + auto sbuffer = image->data + (region.min.y + image->y) * image->stride + (region.min.x + image->x); for (auto y = region.min.y; y < region.max.y; ++y) { - auto dst = &surface->buffer[y * surface->stride + region.min.x]; - auto ey1 = y * itransform->e12 + itransform->e13; - auto ey2 = y * itransform->e22 + itransform->e23; - for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { - auto rX = static_cast(roundf(x * itransform->e11 + ey1)); - auto rY = static_cast(roundf(x * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = img[rX + (rY * w)]; - else src = _average2Nx2NPixel(surface, img, w, h, rX, rY, halfScale); - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); + auto dst = dbuffer; + auto src = sbuffer; + for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) { + auto p = ALPHA_BLEND(*src, opacity); + *dst = p + ALPHA_BLEND(*dst, surface->blender.ialpha(p)); } + dbuffer += surface->stride; + sbuffer += image->stride; } return true; } -/************************************************************************/ -/* Gradient */ -/************************************************************************/ - -static bool _translucentLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) +static bool _rasterDirectTranslucentImage(SwSurface* surface, const SwImage* image, uint32_t opacity, const SwBBox& region) { - if (fill->linear.len < FLT_EPSILON) return false; - - auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; - auto h = static_cast(region.max.y - region.min.y); - auto w = static_cast(region.max.x - region.min.x); - - auto sbuffer = static_cast(alloca(w * sizeof(uint32_t))); - if (!sbuffer) return false; - - auto dst = buffer; - for (uint32_t y = 0; y < h; ++y) { - fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w); - for (uint32_t x = 0; x < w; ++x) { - dst[x] = sbuffer[x] + ALPHA_BLEND(dst[x], surface->blender.ialpha(sbuffer[x])); + if (surface->compositor) { + if (surface->compositor->method == CompositeMethod::AlphaMask) { + return _rasterDirectMaskedImage(surface, image, opacity, region, surface->blender.alpha); + } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { + return _rasterDirectMaskedImage(surface, image, opacity, region, surface->blender.ialpha); } - dst += surface->stride; + } + return __rasterDirectTranslucentImage(surface, image, opacity, region); +} + + +static bool _rasterDirectSolidImage(SwSurface* surface, const SwImage* image, const SwBBox& region) +{ + auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x]; + auto sbuffer = image->data + (region.min.y + image->y) * image->stride + (region.min.x + image->x); + + for (auto y = region.min.y; y < region.max.y; ++y) { + auto dst = dbuffer; + auto src = sbuffer; + for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) { + *dst = *src + ALPHA_BLEND(*dst, surface->blender.ialpha(*src)); + } + dbuffer += surface->stride; + sbuffer += image->stride; } return true; } -static bool _translucentLinearGradientRectMask(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t)) +/************************************************************************/ +/* Rect Linear Gradient */ +/************************************************************************/ + +static bool _rasterTranslucentLinearGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t)) { if (fill->linear.len < FLT_EPSILON) return false; @@ -1068,21 +1078,44 @@ static bool _translucentLinearGradientRectMask(SwSurface* surface, const SwBBox& } +static bool __rasterTranslucentLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) +{ + if (fill->linear.len < FLT_EPSILON) return false; + + auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; + auto h = static_cast(region.max.y - region.min.y); + auto w = static_cast(region.max.x - region.min.x); + + auto sbuffer = static_cast(alloca(w * sizeof(uint32_t))); + if (!sbuffer) return false; + + auto dst = buffer; + for (uint32_t y = 0; y < h; ++y) { + fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w); + for (uint32_t x = 0; x < w; ++x) { + dst[x] = sbuffer[x] + ALPHA_BLEND(dst[x], surface->blender.ialpha(sbuffer[x])); + } + dst += surface->stride; + } + return true; +} + + static bool _rasterTranslucentLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) { if (surface->compositor) { if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _translucentLinearGradientRectMask(surface, region, fill, surface->blender.alpha); + return _rasterTranslucentLinearGradientMaskedRect(surface, region, fill, surface->blender.alpha); } if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _translucentLinearGradientRectMask(surface, region, fill, surface->blender.ialpha); + return _rasterTranslucentLinearGradientMaskedRect(surface, region, fill, surface->blender.ialpha); } } - return _translucentLinearGradientRect(surface, region, fill); + return __rasterTranslucentLinearGradientRect(surface, region, fill); } -static bool _rasterOpaqueLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) +static bool _rasterSolidLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) { if (fill->linear.len < FLT_EPSILON) return false; @@ -1097,30 +1130,114 @@ static bool _rasterOpaqueLinearGradientRect(SwSurface* surface, const SwBBox& re } -static bool _translucentRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) +/************************************************************************/ +/* Rle Linear Gradient */ +/************************************************************************/ + + +static bool _rasterTranslucentLinearGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t)) { - if (fill->radial.a < FLT_EPSILON) return false; + if (fill->linear.len < FLT_EPSILON) return false; - auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; - auto h = static_cast(region.max.y - region.min.y); - auto w = static_cast(region.max.x - region.min.x); + auto span = rle->spans; + auto cbuffer = surface->compositor->image.data; + auto buffer = static_cast(alloca(surface->w * sizeof(uint32_t))); + if (!buffer) return false; - auto sbuffer = static_cast(alloca(w * sizeof(uint32_t))); - if (!sbuffer) return false; - - auto dst = buffer; - for (uint32_t y = 0; y < h; ++y) { - fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w); - for (uint32_t x = 0; x < w; ++x) { - dst[x] = sbuffer[x] + ALPHA_BLEND(dst[x], surface->blender.ialpha(sbuffer[x])); + for (uint32_t i = 0; i < rle->size; ++i, ++span) { + fillFetchLinear(fill, buffer, span->y, span->x, span->len); + auto dst = &surface->buffer[span->y * surface->stride + span->x]; + auto cmp = &cbuffer[span->y * surface->stride + span->x]; + auto src = buffer; + if (span->coverage == 255) { + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { + auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp)); + *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); + } + } else { + auto ialpha = 255 - span->coverage; + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { + auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp)); + tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha); + *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); + } } - dst += surface->stride; } return true; } -static bool _translucentRadialGradientRectMask(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t)) +static bool __rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) +{ + if (fill->linear.len < FLT_EPSILON) return false; + + auto span = rle->spans; + auto buffer = static_cast(alloca(surface->w * sizeof(uint32_t))); + if (!buffer) return false; + + for (uint32_t i = 0; i < rle->size; ++i, ++span) { + auto dst = &surface->buffer[span->y * surface->stride + span->x]; + fillFetchLinear(fill, buffer, span->y, span->x, span->len); + if (span->coverage == 255) { + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = buffer[i] + ALPHA_BLEND(dst[i], surface->blender.ialpha(buffer[i])); + } + } else { + for (uint32_t i = 0; i < span->len; ++i) { + auto tmp = ALPHA_BLEND(buffer[i], span->coverage); + dst[i] = tmp + ALPHA_BLEND(dst[i], surface->blender.ialpha(tmp)); + } + } + } + return true; +} + + +static bool _rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) +{ + if (!rle) return false; + + if (surface->compositor) { + if (surface->compositor->method == CompositeMethod::AlphaMask) { + return _rasterTranslucentLinearGradientMaskedRle(surface, rle, fill, surface->blender.alpha); + } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { + return _rasterTranslucentLinearGradientMaskedRle(surface, rle, fill, surface->blender.ialpha); + } + } + return __rasterTranslucentLinearGradientRle(surface, rle, fill); +} + + +static bool _rasterSolidLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) +{ + if (fill->linear.len < FLT_EPSILON) return false; + + auto buf = static_cast(alloca(surface->w * sizeof(uint32_t))); + if (!buf) return false; + + auto span = rle->spans; + + for (uint32_t i = 0; i < rle->size; ++i, ++span) { + if (span->coverage == 255) { + fillFetchLinear(fill, surface->buffer + span->y * surface->stride + span->x, span->y, span->x, span->len); + } else { + fillFetchLinear(fill, buf, span->y, span->x, span->len); + auto ialpha = 255 - span->coverage; + auto dst = &surface->buffer[span->y * surface->stride + span->x]; + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha); + } + } + } + return true; +} + + +/************************************************************************/ +/* Rect Radial Gradient */ +/************************************************************************/ + +static bool _rasterTranslucentRadialGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t)) { if (fill->radial.a < FLT_EPSILON) return false; @@ -1148,21 +1265,43 @@ static bool _translucentRadialGradientRectMask(SwSurface* surface, const SwBBox& } +static bool __rasterTranslucentRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) +{ + if (fill->radial.a < FLT_EPSILON) return false; + + auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; + auto h = static_cast(region.max.y - region.min.y); + auto w = static_cast(region.max.x - region.min.x); + + auto sbuffer = static_cast(alloca(w * sizeof(uint32_t))); + if (!sbuffer) return false; + + auto dst = buffer; + for (uint32_t y = 0; y < h; ++y) { + fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w); + for (uint32_t x = 0; x < w; ++x) { + dst[x] = sbuffer[x] + ALPHA_BLEND(dst[x], surface->blender.ialpha(sbuffer[x])); + } + dst += surface->stride; + } + return true; +} + + static bool _rasterTranslucentRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) { if (surface->compositor) { if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _translucentRadialGradientRectMask(surface, region, fill, surface->blender.alpha); - } - if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _translucentRadialGradientRectMask(surface, region, fill, surface->blender.ialpha); + return _rasterTranslucentRadialGradientMaskedRect(surface, region, fill, surface->blender.alpha); + } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { + return _rasterTranslucentRadialGradientMaskedRect(surface, region, fill, surface->blender.ialpha); } } - return _translucentRadialGradientRect(surface, region, fill); + return __rasterTranslucentRadialGradientRect(surface, region, fill); } -static bool _rasterOpaqueRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) +static bool _rasterSolidRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) { if (fill->radial.a < FLT_EPSILON) return false; @@ -1178,35 +1317,14 @@ static bool _rasterOpaqueRadialGradientRect(SwSurface* surface, const SwBBox& re } -static bool _translucentLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) +/************************************************************************/ +/* RLE Radial Gradient */ +/************************************************************************/ + + +static bool _rasterTranslucentRadialGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t)) { - if (fill->linear.len < FLT_EPSILON) return false; - - auto span = rle->spans; - auto buffer = static_cast(alloca(surface->w * sizeof(uint32_t))); - if (!buffer) return false; - - for (uint32_t i = 0; i < rle->size; ++i, ++span) { - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - fillFetchLinear(fill, buffer, span->y, span->x, span->len); - if (span->coverage == 255) { - for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = buffer[i] + ALPHA_BLEND(dst[i], surface->blender.ialpha(buffer[i])); - } - } else { - for (uint32_t i = 0; i < span->len; ++i) { - auto tmp = ALPHA_BLEND(buffer[i], span->coverage); - dst[i] = tmp + ALPHA_BLEND(dst[i], surface->blender.ialpha(tmp)); - } - } - } - return true; -} - - -static bool _translucentLinearGradientRleMask(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t)) -{ - if (fill->linear.len < FLT_EPSILON) return false; + if (fill->radial.a < FLT_EPSILON) return false; auto span = rle->spans; auto cbuffer = surface->compositor->image.data; @@ -1214,7 +1332,7 @@ static bool _translucentLinearGradientRleMask(SwSurface* surface, const SwRleDat if (!buffer) return false; for (uint32_t i = 0; i < rle->size; ++i, ++span) { - fillFetchLinear(fill, buffer, span->y, span->x, span->len); + fillFetchRadial(fill, buffer, span->y, span->x, span->len); auto dst = &surface->buffer[span->y * surface->stride + span->x]; auto cmp = &cbuffer[span->y * surface->stride + span->x]; auto src = buffer; @@ -1236,48 +1354,7 @@ static bool _translucentLinearGradientRleMask(SwSurface* surface, const SwRleDat } -static bool _rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) -{ - if (!rle) return false; - - if (surface->compositor) { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _translucentLinearGradientRleMask(surface, rle, fill, surface->blender.alpha); - } - if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _translucentLinearGradientRleMask(surface, rle, fill, surface->blender.ialpha); - } - } - return _translucentLinearGradientRle(surface, rle, fill); -} - - -static bool _rasterOpaqueLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) -{ - if (fill->linear.len < FLT_EPSILON) return false; - - auto buf = static_cast(alloca(surface->w * sizeof(uint32_t))); - if (!buf) return false; - - auto span = rle->spans; - - for (uint32_t i = 0; i < rle->size; ++i, ++span) { - if (span->coverage == 255) { - fillFetchLinear(fill, surface->buffer + span->y * surface->stride + span->x, span->y, span->x, span->len); - } else { - fillFetchLinear(fill, buf, span->y, span->x, span->len); - auto ialpha = 255 - span->coverage; - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha); - } - } - } - return true; -} - - -static bool _translucentRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) +static bool __rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) { if (fill->radial.a < FLT_EPSILON) return false; @@ -1303,55 +1380,22 @@ static bool _translucentRadialGradientRle(SwSurface* surface, const SwRleData* r } -static bool _translucentRadialGradientRleMask(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t)) -{ - if (fill->radial.a < FLT_EPSILON) return false; - - auto span = rle->spans; - auto cbuffer = surface->compositor->image.data; - auto buffer = static_cast(alloca(surface->w * sizeof(uint32_t))); - if (!buffer) return false; - - for (uint32_t i = 0; i < rle->size; ++i, ++span) { - fillFetchRadial(fill, buffer, span->y, span->x, span->len); - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto cmp = &cbuffer[span->y * surface->stride + span->x]; - auto src = buffer; - if (span->coverage == 255) { - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { - auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp)); - *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); - } - } else { - auto ialpha = 255 - span->coverage; - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { - auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp)); - tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha); - *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); - } - } - } - return true; -} - - static bool _rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) { if (!rle) return false; if (surface->compositor) { if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _translucentRadialGradientRleMask(surface, rle, fill, surface->blender.alpha); - } - if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _translucentRadialGradientRleMask(surface, rle, fill, surface->blender.ialpha); + return _rasterTranslucentRadialGradientMaskedRle(surface, rle, fill, surface->blender.alpha); + } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { + return _rasterTranslucentRadialGradientMaskedRle(surface, rle, fill, surface->blender.ialpha); } } - return _translucentRadialGradientRle(surface, rle, fill); + return __rasterTranslucentRadialGradientRle(surface, rle, fill); } -static bool _rasterOpaqueRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) +static bool _rasterSolidRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) { if (fill->radial.a < FLT_EPSILON) return false; @@ -1419,19 +1463,19 @@ bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id) if (shape->fastTrack) { if (id == TVG_CLASS_ID_LINEAR) { if (translucent) return _rasterTranslucentLinearGradientRect(surface, shape->bbox, shape->fill); - return _rasterOpaqueLinearGradientRect(surface, shape->bbox, shape->fill); + return _rasterSolidLinearGradientRect(surface, shape->bbox, shape->fill); } else { if (translucent) return _rasterTranslucentRadialGradientRect(surface, shape->bbox, shape->fill); - return _rasterOpaqueRadialGradientRect(surface, shape->bbox, shape->fill); + return _rasterSolidRadialGradientRect(surface, shape->bbox, shape->fill); } } else { if (!shape->rle) return false; if (id == TVG_CLASS_ID_LINEAR) { if (translucent) return _rasterTranslucentLinearGradientRle(surface, shape->rle, shape->fill); - return _rasterOpaqueLinearGradientRle(surface, shape->rle, shape->fill); + return _rasterSolidLinearGradientRle(surface, shape->rle, shape->fill); } else { if (translucent) return _rasterTranslucentRadialGradientRle(surface, shape->rle, shape->fill); - return _rasterOpaqueRadialGradientRle(surface, shape->rle, shape->fill); + return _rasterSolidRadialGradientRle(surface, shape->rle, shape->fill); } } return false; @@ -1441,9 +1485,9 @@ bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id) bool rasterSolidShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { if (a < 255) { - r = ALPHA_MULTIPLY(r, a); - g = ALPHA_MULTIPLY(g, a); - b = ALPHA_MULTIPLY(b, a); + r = _multiplyAlpha(r, a); + g = _multiplyAlpha(g, a); + b = _multiplyAlpha(b, a); } auto color = surface->blender.join(r, g, b, a); @@ -1464,9 +1508,9 @@ bool rasterSolidShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { if (a < 255) { - r = ALPHA_MULTIPLY(r, a); - g = ALPHA_MULTIPLY(g, a); - b = ALPHA_MULTIPLY(b, a); + r = _multiplyAlpha(r, a); + g = _multiplyAlpha(g, a); + b = _multiplyAlpha(b, a); } auto color = surface->blender.join(r, g, b, a); @@ -1485,10 +1529,10 @@ bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id) if (id == TVG_CLASS_ID_LINEAR) { if (translucent) return _rasterTranslucentLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill); - return _rasterOpaqueLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill); + return _rasterSolidLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill); } else { if (translucent) return _rasterTranslucentRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill); - return _rasterOpaqueRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill); + return _rasterSolidRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill); } return false; @@ -1537,9 +1581,10 @@ void rasterUnpremultiply(SwSurface* surface) bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, const SwBBox& bbox, uint32_t opacity) { - static constexpr float DOWN_SCALE_TOLERANCE = 0.5f; + Matrix itransform; + if (transform && !mathInverse(transform, &itransform)) return false; - uint32_t halfScale = static_cast(0.5f / image->scale); + auto halfScale = static_cast(0.5f / image->scale); if (halfScale == 0) halfScale = 1; auto translucent = _translucent(surface, opacity); @@ -1547,40 +1592,20 @@ bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, co //Clipped Image if (image->rle) { if (image->transformed) { - Matrix itransform; - if (!mathInverse(transform, &itransform)) return false; - if (translucent) { - if (mathEqual(image->scale, 1.0f)) return _rasterTranslucentImageRle(surface, image, opacity, &itransform); - else if (image->scale < DOWN_SCALE_TOLERANCE) return _rasterTranslucentDownScaleImageRle(surface, image, opacity, &itransform, halfScale); - else return _rasterTranslucentUpScaleImageRle(surface, image, opacity, &itransform); - } else { - if (mathEqual(image->scale, 1.0f)) return _rasterImageRle(surface, image, &itransform); - else if (image->scale < DOWN_SCALE_TOLERANCE) return _rasterDownScaleImageRle(surface, image, &itransform, halfScale); - else return _rasterUpScaleImageRle(surface, image, &itransform); - } - //Fast track: Only shifted image can go into this routine. + if (translucent) return _rasterTransformedTranslucentRleImage(surface, image, opacity, &itransform, halfScale); + else return _rasterTransformedSolidRleImage(surface, image, &itransform, halfScale); } else { - if (translucent) return _rasterTranslucentImageRle(surface, image, opacity); - return _rasterImageRle(surface, image); + if (translucent) return _rasterDirectTranslucentRleImage(surface, image, opacity); + else return _rasterDirectSolidRleImage(surface, image); } //Whole Image } else { if (image->transformed) { - Matrix itransform; - if (!mathInverse(transform, &itransform)) return false; - if (translucent) { - if (mathEqual(image->scale, 1.0f)) return _rasterTranslucentImage(surface, image, opacity, bbox, &itransform); - else if (image->scale < DOWN_SCALE_TOLERANCE) return _rasterTranslucentDownScaleImage(surface, image, opacity, bbox, &itransform, halfScale); - else return _rasterTranslucentUpScaleImage(surface, image, opacity, bbox, &itransform); - } else { - if (mathEqual(image->scale, 1.0f)) return _rasterImage(surface, image, bbox, &itransform); - else if (image->scale < DOWN_SCALE_TOLERANCE) return _rasterDownScaleImage(surface, image, bbox, &itransform, halfScale); - else return _rasterUpScaleImage(surface, image, bbox, &itransform); - } - //Fast track: Only shifted image can go into this routine. + if (translucent) return _rasterTransformedTranslucentImage(surface, image, opacity, bbox, &itransform, halfScale); + else return _rasterTransformedSolidImage(surface, image, bbox, &itransform, halfScale); } else { - if (translucent) return _rasterTranslucentImage(surface, image, opacity, bbox); - return _rasterImage(surface, image, bbox); + if (translucent) return _rasterDirectTranslucentImage(surface, image, opacity, bbox); + else return _rasterDirectSolidImage(surface, image, bbox); } } -} +} \ No newline at end of file