sw_engine: unification of mask and inv mask functions

The function pointers used to pass the proper blending method - mask
or inverse mask.
This commit is contained in:
Mira Grudzinska 2021-11-09 02:39:59 +01:00 committed by Hermet Park
parent 097e10fea4
commit 8c4b679fb7
2 changed files with 71 additions and 342 deletions

View file

@ -230,6 +230,7 @@ struct SwBlender
{
uint32_t (*join)(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
uint32_t (*alpha)(uint32_t rgba);
uint32_t (*invAlpha)(uint32_t rgba);
};
struct SwCompositor;

View file

@ -36,6 +36,12 @@ static uint32_t _colorAlpha(uint32_t c)
}
static uint32_t _colorInvAlpha(uint32_t c)
{
return (~c >> 24);
}
static uint32_t _abgrJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
return (a << 24 | b << 16 | g << 8 | r);
@ -98,13 +104,13 @@ static uint32_t _average2Nx2NPixel(SwSurface* surface, const uint32_t *img, uint
/* Rect */
/************************************************************************/
static bool _translucentRectAlphaMask(SwSurface* surface, const SwBBox& region, uint32_t color)
static bool _translucentRectMask(SwSurface* surface, const SwBBox& region, uint32_t color, uint32_t (*blendMethod)(uint32_t rgba))
{
auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
TVGLOG("SW_ENGINE", "Rectangle Alpha Mask Composition");
TVGLOG("SW_ENGINE", "Rectangle Alpha Mask / Inverse Alpha Mask Composition");
auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x; //compositor buffer
@ -112,30 +118,8 @@ static bool _translucentRectAlphaMask(SwSurface* surface, const SwBBox& region,
auto dst = &buffer[y * surface->stride];
auto cmp = &cbuffer[y * surface->stride];
for (uint32_t x = 0; x < w; ++x) {
auto tmp = ALPHA_BLEND(color, surface->blender.alpha(*cmp));
dst[x] = tmp + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(tmp));
++cmp;
}
}
return true;
}
static bool _translucentRectInvAlphaMask(SwSurface* surface, const SwBBox& region, uint32_t color)
{
auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
TVGLOG("SW_ENGINE", "Rectangle Inverse Alpha Mask Composition");
auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x; //compositor buffer
for (uint32_t y = 0; y < h; ++y) {
auto dst = &buffer[y * surface->stride];
auto cmp = &cbuffer[y * surface->stride];
for (uint32_t x = 0; x < w; ++x) {
auto tmp = ALPHA_BLEND(color, 255 - surface->blender.alpha(*cmp));
dst[x] = tmp + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(tmp));
auto tmp = ALPHA_BLEND(color, blendMethod(*cmp));
dst[x] = tmp + ALPHA_BLEND(dst[x], surface->blender.invAlpha(tmp));
++cmp;
}
}
@ -146,10 +130,10 @@ static bool _rasterTranslucentRect(SwSurface* surface, const SwBBox& region, uin
{
if (surface->compositor) {
if (surface->compositor->method == CompositeMethod::AlphaMask) {
return _translucentRectAlphaMask(surface, region, color);
return _translucentRectMask(surface, region, color, surface->blender.alpha);
}
if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _translucentRectInvAlphaMask(surface, region, color);
return _translucentRectMask(surface, region, color, surface->blender.invAlpha);
}
}
@ -180,10 +164,9 @@ static bool _rasterSolidRect(SwSurface* surface, const SwBBox& region, uint32_t
/* Rle */
/************************************************************************/
static bool _translucentRleAlphaMask(SwSurface* surface, const SwRleData* rle, uint32_t color)
static bool _translucentRleMask(SwSurface* surface, SwRleData* rle, uint32_t color, uint32_t (*blendMethod)(uint32_t rgba))
{
TVGLOG("SW_ENGINE", "Rle Alpha Mask Composition");
TVGLOG("SW_ENGINE", "Rle Alpha Mask / Inverse Alpha Mask Composition");
auto span = rle->spans;
uint32_t src;
@ -195,31 +178,8 @@ static bool _translucentRleAlphaMask(SwSurface* surface, const SwRleData* rle, u
if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage);
else src = color;
for (uint32_t x = 0; x < span->len; ++x) {
auto tmp = ALPHA_BLEND(src, surface->blender.alpha(*cmp));
dst[x] = tmp + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(tmp));
++cmp;
}
++span;
}
return true;
}
static bool _translucentRleInvAlphaMask(SwSurface* surface, SwRleData* rle, uint32_t color)
{
TVGLOG("SW_ENGINE", "Rle Inverse Alpha Mask Composition");
auto span = rle->spans;
uint32_t src;
auto cbuffer = surface->compositor->image.data;
for (uint32_t i = 0; i < rle->size; ++i) {
auto dst = &surface->buffer[span->y * surface->stride + span->x];
auto cmp = &cbuffer[span->y * surface->stride + span->x];
if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage);
else src = color;
for (uint32_t x = 0; x < span->len; ++x) {
auto tmp = ALPHA_BLEND(src, 255 - surface->blender.alpha(*cmp));
dst[x] = tmp + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(tmp));
auto tmp = ALPHA_BLEND(src, blendMethod(*cmp));
dst[x] = tmp + ALPHA_BLEND(dst[x], surface->blender.invAlpha(tmp));
++cmp;
}
++span;
@ -233,10 +193,10 @@ static bool _rasterTranslucentRle(SwSurface* surface, SwRleData* rle, uint32_t c
if (surface->compositor) {
if (surface->compositor->method == CompositeMethod::AlphaMask) {
return _translucentRleAlphaMask(surface, rle, color);
return _translucentRleMask(surface, rle, color, surface->blender.alpha);
}
if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _translucentRleInvAlphaMask(surface, rle, color);
return _translucentRleMask(surface, rle, color, surface->blender.invAlpha);
}
}
@ -530,9 +490,9 @@ static bool _translucentImage(SwSurface* surface, const uint32_t *img, uint32_t
}
static bool _translucentImageAlphaMask(SwSurface* surface, const uint32_t *img, uint32_t w, TVG_UNUSED uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform)
static bool _translucentImageMask(SwSurface* surface, const uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform, uint32_t (*blendMethod)(uint32_t rgba))
{
TVGLOG("SW_ENGINE", "Transformed Image Alpha Mask Composition");
TVGLOG("SW_ENGINE", "Transformed Image AlphaMask / Inverse Alpha Mask Composition");
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];
@ -546,33 +506,8 @@ static bool _translucentImageAlphaMask(SwSurface* surface, const uint32_t *img,
auto rX = static_cast<uint32_t>(roundf(x * invTransform->e11 + ey1));
auto rY = static_cast<uint32_t>(roundf(x * invTransform->e21 + ey2));
if (rX >= w || rY >= h) continue;
auto src = ALPHA_BLEND(img[rX + (rY * w)], ALPHA_MULTIPLY(opacity, surface->blender.alpha(*cmp))); //TODO: need to use image's stride
*dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
}
dbuffer += surface->stride;
cbuffer += surface->stride;
}
return true;
}
static bool _translucentImageInvAlphaMask(SwSurface* surface, const uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform)
{
TVGLOG("SW_ENGINE", "Transformed Image Inverse Alpha Mask Composition");
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 * 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<uint32_t>(roundf(x * invTransform->e11 + ey1));
auto rY = static_cast<uint32_t>(roundf(x * invTransform->e21 + ey2));
if (rX >= w || rY >= h) continue;
auto src = ALPHA_BLEND(img[rX + (rY * w)], ALPHA_MULTIPLY(opacity, 255 - surface->blender.alpha(*cmp))); //TODO: need to use image's stride
*dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
auto src = ALPHA_BLEND(img[rX + (rY * w)], ALPHA_MULTIPLY(opacity, blendMethod(*cmp))); //TODO: need to use image's stride
*dst = src + ALPHA_BLEND(*dst, surface->blender.invAlpha(src));
}
dbuffer += surface->stride;
cbuffer += surface->stride;
@ -585,10 +520,10 @@ static bool _rasterTranslucentImage(SwSurface* surface, const uint32_t *img, uin
{
if (surface->compositor) {
if (surface->compositor->method == CompositeMethod::AlphaMask) {
return _translucentImageAlphaMask(surface, img, w, h, opacity, region, invTransform);
return _translucentImageMask(surface, img, w, h, opacity, region, invTransform, surface->blender.alpha);
}
if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _translucentImageInvAlphaMask(surface, img, w, h, opacity, region, invTransform);
return _translucentImageMask(surface, img, w, h, opacity, region, invTransform, surface->blender.invAlpha);
}
}
return _translucentImage(surface, img, w, h, opacity, region, invTransform);
@ -620,9 +555,9 @@ static bool _translucentUpScaleImage(SwSurface* surface, const uint32_t *img, ui
}
static bool _translucentUpScaleImageAlphaMask(SwSurface* surface, const uint32_t *img, uint32_t w, TVG_UNUSED uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform)
static bool _translucentUpScaleImageMask(SwSurface* surface, const uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform, uint32_t (*blendMethod)(uint32_t rgba))
{
TVGLOG("SW_ENGINE", "Transformed Image Alpha Mask Composition");
TVGLOG("SW_ENGINE", "Transformed Image Alpha Mask / Inverse Alpha Mask Composition");
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];
@ -639,39 +574,9 @@ static bool _translucentUpScaleImageAlphaMask(SwSurface* surface, const uint32_t
auto rY = static_cast<uint32_t>(roundf(fY));
if (rX >= w || rY >= h) continue;
uint32_t src;
if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rX + (rY * w)], ALPHA_MULTIPLY(opacity, surface->blender.alpha(*cmp))); //TODO: need to use image's stride
else src = ALPHA_BLEND(_applyBilinearInterpolation(img, w, h, fX, fY), ALPHA_MULTIPLY(opacity, surface->blender.alpha(*cmp))); //TODO: need to use image's stride
*dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
}
dbuffer += surface->stride;
cbuffer += surface->stride;
}
return true;
}
static bool _translucentUpScaleImageInvAlphaMask(SwSurface* surface, const uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform)
{
TVGLOG("SW_ENGINE", "Transformed Image Inverse Alpha Mask Composition");
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 * 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 fX = x * invTransform->e11 + ey1;
auto fY = x * invTransform->e21 + ey2;
auto rX = static_cast<uint32_t>(roundf(fX));
auto rY = static_cast<uint32_t>(roundf(fY));
if (rX >= w || rY >= h) continue;
uint32_t src;
if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rX + (rY * w)], ALPHA_MULTIPLY(opacity, 255 - surface->blender.alpha(*cmp))); //TODO: need to use image's stride
else src = ALPHA_BLEND(_applyBilinearInterpolation(img, w, h, fX, fY), ALPHA_MULTIPLY(opacity, 255 - surface->blender.alpha(*cmp))); //TODO: need to use image's stride
*dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rX + (rY * w)], ALPHA_MULTIPLY(opacity, blendMethod(*cmp))); //TODO: need to use image's stride
else src = ALPHA_BLEND(_applyBilinearInterpolation(img, w, h, fX, fY), ALPHA_MULTIPLY(opacity, blendMethod(*cmp))); //TODO: need to use image's stride
*dst = src + ALPHA_BLEND(*dst, surface->blender.invAlpha(src));
}
dbuffer += surface->stride;
cbuffer += surface->stride;
@ -684,10 +589,10 @@ static bool _rasterTranslucentUpScaleImage(SwSurface* surface, const uint32_t *i
{
if (surface->compositor) {
if (surface->compositor->method == CompositeMethod::AlphaMask) {
return _translucentUpScaleImageAlphaMask(surface, img, w, h, opacity, region, invTransform);
return _translucentUpScaleImageMask(surface, img, w, h, opacity, region, invTransform, surface->blender.alpha);
}
if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _translucentUpScaleImageInvAlphaMask(surface, img, w, h, opacity, region, invTransform);
return _translucentUpScaleImageMask(surface, img, w, h, opacity, region, invTransform, surface->blender.invAlpha);
}
}
return _translucentUpScaleImage(surface, img, w, h, opacity, region, invTransform);
@ -719,9 +624,9 @@ static bool _translucentDownScaleImage(SwSurface* surface, const uint32_t *img,
}
static bool _translucentDownScaleImageAlphaMask(SwSurface* surface, const uint32_t *img, uint32_t w, TVG_UNUSED uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform, float scaling)
static bool _translucentDownScaleImageMask(SwSurface* surface, const uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform, float scaling, uint32_t (*blendMethod)(uint32_t rgba))
{
TVGLOG("SW_ENGINE", "Transformed Image Alpha Mask Composition");
TVGLOG("SW_ENGINE", "Transformed Image Alpha Mask / Inverse Alpha Mask Composition");
uint32_t halfScaling = static_cast<uint32_t>(0.5f / scaling);
if (halfScaling == 0) halfScaling = 1;
@ -738,39 +643,9 @@ static bool _translucentDownScaleImageAlphaMask(SwSurface* surface, const uint32
auto rY = static_cast<uint32_t>(roundf(x * invTransform->e21 + ey2));
if (rX >= w || rY >= h) continue;
uint32_t src;
if (rX < halfScaling || rY < halfScaling || rX >= w - halfScaling || rY >= h - halfScaling) src = ALPHA_BLEND(img[rX + (rY * w)], ALPHA_MULTIPLY(opacity, surface->blender.alpha(*cmp))); //TODO: need to use image's stride
else src = ALPHA_BLEND(_average2Nx2NPixel(surface, img, w, h, rX, rY, halfScaling), ALPHA_MULTIPLY(opacity, surface->blender.alpha(*cmp))); //TODO: need to use image's stride
*dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
}
dbuffer += surface->stride;
cbuffer += surface->stride;
}
return true;
}
static bool _translucentDownScaleImageInvAlphaMask(SwSurface* surface, const uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform, float scaling)
{
TVGLOG("SW_ENGINE", "Transformed Image Inverse Alpha Mask Composition");
uint32_t halfScaling = static_cast<uint32_t>(0.5f / scaling);
if (halfScaling == 0) halfScaling = 1;
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 * 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<uint32_t>(roundf(x * invTransform->e11 + ey1));
auto rY = static_cast<uint32_t>(roundf(x * invTransform->e21 + ey2));
if (rX >= w || rY >= h) continue;
uint32_t src;
if (rX < halfScaling || rY < halfScaling || rX >= w - halfScaling || rY >= h - halfScaling) src = ALPHA_BLEND(img[rX + (rY * w)], ALPHA_MULTIPLY(opacity, 255 - surface->blender.alpha(*cmp))); //TODO: need to use image's stride
else src = ALPHA_BLEND(_average2Nx2NPixel(surface, img, w, h, rX, rY, halfScaling), ALPHA_MULTIPLY(opacity, 255 - surface->blender.alpha(*cmp))); //TODO: need to use image's stride
*dst = src + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(src));
if (rX < halfScaling || rY < halfScaling || rX >= w - halfScaling || rY >= h - halfScaling) src = ALPHA_BLEND(img[rX + (rY * w)], ALPHA_MULTIPLY(opacity, blendMethod(*cmp))); //TODO: need to use image's stride
else src = ALPHA_BLEND(_average2Nx2NPixel(surface, img, w, h, rX, rY, halfScaling), ALPHA_MULTIPLY(opacity, blendMethod(*cmp))); //TODO: need to use image's stride
*dst = src + ALPHA_BLEND(*dst, surface->blender.invAlpha(src));
}
dbuffer += surface->stride;
cbuffer += surface->stride;
@ -783,10 +658,10 @@ static bool _rasterTranslucentDownScaleImage(SwSurface* surface, const uint32_t
{
if (surface->compositor) {
if (surface->compositor->method == CompositeMethod::AlphaMask) {
return _translucentDownScaleImageAlphaMask(surface, img, w, h, opacity, region, invTransform, scaling);
return _translucentDownScaleImageMask(surface, img, w, h, opacity, region, invTransform, scaling, surface->blender.alpha);
}
if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _translucentDownScaleImageInvAlphaMask(surface, img, w, h, opacity, region, invTransform, scaling);
return _translucentDownScaleImageMask(surface, img, w, h, opacity, region, invTransform, scaling, surface->blender.invAlpha);
}
}
return _translucentDownScaleImage(surface, img, w, h, opacity, region, invTransform, scaling);
@ -812,13 +687,13 @@ static bool _translucentImage(SwSurface* surface, uint32_t *img, uint32_t w, uin
}
static bool _translucentImageAlphaMask(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region)
static bool _translucentImageMask(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region, uint32_t (*blendMethod)(uint32_t rgba))
{
auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
auto h2 = static_cast<uint32_t>(region.max.y - region.min.y);
auto w2 = static_cast<uint32_t>(region.max.x - region.min.x);
TVGLOG("SW_ENGINE", "Image Alpha Mask Composition");
TVGLOG("SW_ENGINE", "Image Alpha Mask / Inverse Alpha Mask Composition");
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
@ -828,35 +703,8 @@ static bool _translucentImageAlphaMask(SwSurface* surface, uint32_t *img, uint32
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, surface->blender.alpha(*cmp)));
*dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
}
buffer += surface->stride;
cbuffer += surface->stride;
sbuffer += w; //TODO: need to use image's stride
}
return true;
}
static bool _translucentImageInvAlphaMask(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<uint32_t>(region.max.y - region.min.y);
auto w2 = static_cast<uint32_t>(region.max.x - region.min.x);
TVGLOG("SW_ENGINE", "Image Inverse Alpha Mask Composition");
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;
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, 255 - surface->blender.alpha(*cmp)));
*dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
auto tmp = ALPHA_BLEND(*src, ALPHA_MULTIPLY(opacity, blendMethod(*cmp)));
*dst = tmp + ALPHA_BLEND(*dst, surface->blender.invAlpha(tmp));
}
buffer += surface->stride;
cbuffer += surface->stride;
@ -870,10 +718,10 @@ static bool _rasterTranslucentImage(SwSurface* surface, uint32_t *img, uint32_t
{
if (surface->compositor) {
if (surface->compositor->method == CompositeMethod::AlphaMask) {
return _translucentImageAlphaMask(surface, img, w, h, opacity, region);
return _translucentImageMask(surface, img, w, h, opacity, region, surface->blender.alpha);
}
if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _translucentImageInvAlphaMask(surface, img, w, h, opacity, region);
return _translucentImageMask(surface, img, w, h, opacity, region, surface->blender.invAlpha);
}
}
return _translucentImage(surface, img, w, h, opacity, region);
@ -988,7 +836,7 @@ static bool _translucentLinearGradientRect(SwSurface* surface, const SwBBox& reg
}
static bool _translucentLinearGradientRectAlphaMask(SwSurface* surface, const SwBBox& region, const SwFill* fill)
static bool _translucentLinearGradientRectMask(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t rgba))
{
if (fill->linear.len < FLT_EPSILON) return false;
@ -1006,36 +854,8 @@ static bool _translucentLinearGradientRectAlphaMask(SwSurface* surface, const Sw
auto cmp = cbuffer;
auto src = sbuffer;
for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) {
auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp));
*dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
}
buffer += surface->stride;
cbuffer += surface->stride;
}
return true;
}
static bool _translucentLinearGradientRectInvAlphaMask(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<uint32_t>(region.max.y - region.min.y);
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x;
auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
if (!sbuffer) return false;
for (uint32_t y = 0; y < h; ++y) {
fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w);
auto dst = buffer;
auto cmp = cbuffer;
auto src = sbuffer;
for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) {
auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp));
*dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
*dst = tmp + ALPHA_BLEND(*dst, surface->blender.invAlpha(tmp));
}
buffer += surface->stride;
cbuffer += surface->stride;
@ -1048,10 +868,10 @@ static bool _rasterTranslucentLinearGradientRect(SwSurface* surface, const SwBBo
{
if (surface->compositor) {
if (surface->compositor->method == CompositeMethod::AlphaMask) {
return _translucentLinearGradientRectAlphaMask(surface, region, fill);
return _translucentLinearGradientRectMask(surface, region, fill, surface->blender.alpha);
}
if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _translucentLinearGradientRectInvAlphaMask(surface, region, fill);
return _translucentLinearGradientRectMask(surface, region, fill, surface->blender.invAlpha);
}
}
return _translucentLinearGradientRect(surface, region, fill);
@ -1096,7 +916,7 @@ static bool _translucentRadialGradientRect(SwSurface* surface, const SwBBox& reg
}
static bool _translucentRadialGradientRectAlphaMask(SwSurface* surface, const SwBBox& region, const SwFill* fill)
static bool _translucentRadialGradientRectMask(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t rgba))
{
if (fill->radial.a < FLT_EPSILON) return false;
@ -1114,36 +934,8 @@ static bool _translucentRadialGradientRectAlphaMask(SwSurface* surface, const Sw
auto cmp = cbuffer;
auto src = sbuffer;
for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) {
auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp));
*dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
}
buffer += surface->stride;
cbuffer += surface->stride;
}
return true;
}
static bool _translucentRadialGradientRectInvAlphaMask(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<uint32_t>(region.max.y - region.min.y);
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x;
auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
if (!sbuffer) return false;
for (uint32_t y = 0; y < h; ++y) {
fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w);
auto dst = buffer;
auto cmp = cbuffer;
auto src = sbuffer;
for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) {
auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp));
*dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
*dst = tmp + ALPHA_BLEND(*dst, surface->blender.invAlpha(tmp));
}
buffer += surface->stride;
cbuffer += surface->stride;
@ -1156,10 +948,10 @@ static bool _rasterTranslucentRadialGradientRect(SwSurface* surface, const SwBBo
{
if (surface->compositor) {
if (surface->compositor->method == CompositeMethod::AlphaMask) {
return _translucentRadialGradientRectAlphaMask(surface, region, fill);
return _translucentRadialGradientRectMask(surface, region, fill, surface->blender.alpha);
}
if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _translucentRadialGradientRectInvAlphaMask(surface, region, fill);
return _translucentRadialGradientRectMask(surface, region, fill, surface->blender.invAlpha);
}
}
return _translucentRadialGradientRect(surface, region, fill);
@ -1208,7 +1000,7 @@ static bool _translucentLinearGradientRle(SwSurface* surface, const SwRleData* r
}
static bool _translucentLinearGradientRleAlphaMask(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
static bool _translucentLinearGradientRleMask(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t rgba))
{
if (fill->linear.len < FLT_EPSILON) return false;
@ -1224,47 +1016,15 @@ static bool _translucentLinearGradientRleAlphaMask(SwSurface* surface, const SwR
auto src = buffer;
if (span->coverage == 255) {
for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp));
*dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
*dst = tmp + ALPHA_BLEND(*dst, surface->blender.invAlpha(tmp));
}
} else {
auto ialpha = 255 - span->coverage;
for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp));
auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha);
*dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
}
}
}
return true;
}
static bool _translucentLinearGradientRleInvAlphaMask(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
{
if (fill->linear.len < FLT_EPSILON) return false;
auto span = rle->spans;
auto cbuffer = surface->compositor->image.data;
auto buffer = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
if (!buffer) return false;
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, 255 - surface->blender.alpha(*cmp));
*dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
}
} else {
auto ialpha = 255 - span->coverage;
for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp));
tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha);
*dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
*dst = tmp + ALPHA_BLEND(*dst, surface->blender.invAlpha(tmp));
}
}
}
@ -1278,10 +1038,10 @@ static bool _rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleD
if (surface->compositor) {
if (surface->compositor->method == CompositeMethod::AlphaMask) {
return _translucentLinearGradientRleAlphaMask(surface, rle, fill);
return _translucentLinearGradientRleMask(surface, rle, fill, surface->blender.alpha);
}
if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _translucentLinearGradientRleInvAlphaMask(surface, rle, fill);
return _translucentLinearGradientRleMask(surface, rle, fill, surface->blender.invAlpha);
}
}
return _translucentLinearGradientRle(surface, rle, fill);
@ -1339,7 +1099,7 @@ static bool _translucentRadialGradientRle(SwSurface* surface, const SwRleData* r
}
static bool _translucentRadialGradientRleAlphaMask(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
static bool _translucentRadialGradientRleMask(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t rgba))
{
if (fill->radial.a < FLT_EPSILON) return false;
@ -1355,47 +1115,15 @@ static bool _translucentRadialGradientRleAlphaMask(SwSurface* surface, const SwR
auto src = buffer;
if (span->coverage == 255) {
for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp));
*dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
*dst = tmp + ALPHA_BLEND(*dst, surface->blender.invAlpha(tmp));
}
} else {
auto ialpha = 255 - span->coverage;
for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp));
auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp));
tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha);
*dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
}
}
}
return true;
}
static bool _translucentRadialGradientRleInvAlphaMask(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
{
if (fill->radial.a < FLT_EPSILON) return false;
auto span = rle->spans;
auto cbuffer = surface->compositor->image.data;
auto buffer = static_cast<uint32_t*>(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, 255 - surface->blender.alpha(*cmp));
*dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
}
} else {
auto ialpha = 255 - span->coverage;
for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) {
auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp));
tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha);
*dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
*dst = tmp + ALPHA_BLEND(*dst, surface->blender.invAlpha(tmp));
}
}
}
@ -1409,10 +1137,10 @@ static bool _rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleD
if (surface->compositor) {
if (surface->compositor->method == CompositeMethod::AlphaMask) {
return _translucentRadialGradientRleAlphaMask(surface, rle, fill);
return _translucentRadialGradientRleMask(surface, rle, fill, surface->blender.alpha);
}
if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _translucentRadialGradientRleInvAlphaMask(surface, rle, fill);
return _translucentRadialGradientRleMask(surface, rle, fill, surface->blender.invAlpha);
}
}
return _translucentRadialGradientRle(surface, rle, fill);
@ -1463,15 +1191,15 @@ void rasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len)
bool rasterCompositor(SwSurface* surface)
{
if (surface->cs == SwCanvas::ABGR8888 || surface->cs == SwCanvas::ABGR8888_STRAIGHT) {
surface->blender.alpha = _colorAlpha;
surface->blender.join = _abgrJoin;
} else if (surface->cs == SwCanvas::ARGB8888 || surface->cs == SwCanvas::ARGB8888_STRAIGHT) {
surface->blender.alpha = _colorAlpha;
surface->blender.join = _argbJoin;
} else {
//What Color Space ???
return false;
}
surface->blender.alpha = _colorAlpha;
surface->blender.invAlpha = _colorInvAlpha;
return true;
}