mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
sw_engine: code chores & fix gradient filling bugs.
renaming internal methods for integrating with upcoming blending features. this also fixes minor wrong gradient filling blending equations.
This commit is contained in:
parent
b60a291edc
commit
eea54f5fea
3 changed files with 66 additions and 47 deletions
|
@ -239,6 +239,7 @@ struct SwImage
|
|||
bool scaled = false; //draw scaled image
|
||||
};
|
||||
|
||||
typedef uint32_t(*SwBlender)(uint32_t s, uint32_t d, uint8_t sa); //src, dst, alpha
|
||||
typedef uint32_t(*SwJoin)(uint8_t r, uint8_t g, uint8_t b, uint8_t a); //color channel join
|
||||
typedef uint8_t(*SwAlpha)(uint8_t*); //blending alpha
|
||||
|
||||
|
@ -314,48 +315,66 @@ static inline uint8_t IALPHA(uint32_t c)
|
|||
return (~c >> 24);
|
||||
}
|
||||
|
||||
static inline uint32_t opBlendInterp(uint32_t s, uint32_t d, uint8_t a)
|
||||
{
|
||||
return INTERPOLATE(s, d, a);
|
||||
}
|
||||
|
||||
typedef uint32_t(*SwBlendOp)(uint32_t s, uint32_t d, uint8_t a); //src, dst, alpha
|
||||
|
||||
static inline uint32_t opAlphaBlend(uint32_t s, uint32_t d, uint8_t a)
|
||||
static inline uint32_t opBlendNormal(uint32_t s, uint32_t d, uint8_t a)
|
||||
{
|
||||
auto t = ALPHA_BLEND(s, a);
|
||||
return t + ALPHA_BLEND(d, IALPHA(t));
|
||||
}
|
||||
|
||||
static inline uint32_t opBlend(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
|
||||
static inline uint32_t opBlendPreNormal(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
|
||||
{
|
||||
return s + ALPHA_BLEND(d, IALPHA(s));
|
||||
}
|
||||
|
||||
static inline uint32_t opDirect(uint32_t s, TVG_UNUSED uint32_t d, TVG_UNUSED uint8_t a)
|
||||
static inline uint32_t opBlendSrcOver(uint32_t s, TVG_UNUSED uint32_t d, TVG_UNUSED uint8_t a)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
static inline uint32_t opAddMask(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
|
||||
static inline uint32_t opMaskAdd(uint32_t s, uint32_t d, uint8_t a)
|
||||
{
|
||||
return opBlend(s, d, a);
|
||||
return opBlendNormal(s, d, a);
|
||||
}
|
||||
|
||||
static inline uint32_t opSubMask(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
|
||||
static inline uint32_t opMaskSubtract(uint32_t s, uint32_t d, uint8_t a)
|
||||
{
|
||||
return ALPHA_BLEND(d, MULTIPLY(IALPHA(s), a));
|
||||
}
|
||||
|
||||
static inline uint32_t opMaskDifference(uint32_t s, uint32_t d, uint8_t a)
|
||||
{
|
||||
auto t = ALPHA_BLEND(s, a);
|
||||
return ALPHA_BLEND(t, IALPHA(d)) + ALPHA_BLEND(d, IALPHA(t));
|
||||
}
|
||||
|
||||
static inline uint32_t opMaskIntersect(uint32_t s, uint32_t d, uint8_t a)
|
||||
{
|
||||
return ALPHA_BLEND(d, MULTIPLY(IALPHA(s), a));
|
||||
}
|
||||
|
||||
static inline uint32_t opMaskPreAdd(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
|
||||
{
|
||||
return opBlendPreNormal(s, d, a);
|
||||
}
|
||||
|
||||
static inline uint32_t opMaskPreSubtract(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
|
||||
{
|
||||
return ALPHA_BLEND(d, IALPHA(s));
|
||||
}
|
||||
|
||||
static inline uint32_t opIntMask(TVG_UNUSED uint32_t s, uint32_t d, uint8_t a)
|
||||
{
|
||||
return ALPHA_BLEND(d, a);
|
||||
}
|
||||
|
||||
static inline uint32_t opDifMask(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
|
||||
static inline uint32_t opMaskPreDifference(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
|
||||
{
|
||||
return ALPHA_BLEND(s, IALPHA(d)) + ALPHA_BLEND(d, IALPHA(s));
|
||||
}
|
||||
|
||||
static inline uint32_t opInterpolate(uint32_t s, uint32_t d, uint8_t a)
|
||||
static inline uint32_t opMaskPreIntersect(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
|
||||
{
|
||||
return INTERPOLATE(s, d, a);
|
||||
return ALPHA_BLEND(d, MULTIPLY(a, IALPHA(s)));
|
||||
}
|
||||
|
||||
|
||||
|
@ -407,9 +426,9 @@ bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform,
|
|||
void fillReset(SwFill* fill);
|
||||
void fillFree(SwFill* fill);
|
||||
//OPTIMIZE_ME: Skip the function pointer access
|
||||
void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlendOp op, uint8_t a); //blending ver.
|
||||
void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a); //blending ver.
|
||||
void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwAlpha alpha, uint8_t csize, uint8_t opacity); //masking ver.
|
||||
void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlendOp op, uint8_t a); //blending ver.
|
||||
void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a); //blending ver.
|
||||
void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwAlpha alpha, uint8_t csize, uint8_t opacity); //masking ver.
|
||||
|
||||
SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& renderRegion, bool antiAlias);
|
||||
|
|
|
@ -246,13 +246,13 @@ void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3
|
|||
|
||||
if (opacity == 255) {
|
||||
for (uint32_t i = 0 ; i < len ; ++i, ++dst, cmp += csize) {
|
||||
*dst = opAlphaBlend(_pixel(fill, sqrtf(det)), *dst, alpha(cmp));
|
||||
*dst = opBlendNormal(_pixel(fill, sqrtf(det)), *dst, alpha(cmp));
|
||||
det += detFirstDerivative;
|
||||
detFirstDerivative += detSecondDerivative;
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i = 0 ; i < len ; ++i, ++dst, cmp += csize) {
|
||||
*dst = opAlphaBlend(_pixel(fill, sqrtf(det)), *dst, MULTIPLY(opacity, alpha(cmp)));
|
||||
*dst = opBlendNormal(_pixel(fill, sqrtf(det)), *dst, MULTIPLY(opacity, alpha(cmp)));
|
||||
det += detFirstDerivative;
|
||||
detFirstDerivative += detSecondDerivative;
|
||||
}
|
||||
|
@ -260,7 +260,7 @@ void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3
|
|||
}
|
||||
|
||||
|
||||
void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlendOp op, uint8_t a)
|
||||
void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a)
|
||||
{
|
||||
auto rx = (x + 0.5f) * fill->radial.a11 + (y + 0.5f) * fill->radial.a12 + fill->radial.shiftX;
|
||||
auto ry = (x + 0.5f) * fill->radial.a21 + (y + 0.5f) * fill->radial.a22 + fill->radial.shiftY;
|
||||
|
@ -291,7 +291,7 @@ void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3
|
|||
if (mathZero(inc)) {
|
||||
auto color = _fixedPixel(fill, static_cast<int32_t>(t * FIXPT_SIZE));
|
||||
for (uint32_t i = 0; i < len; ++i, ++dst, cmp += csize) {
|
||||
*dst = opAlphaBlend(color, *dst, alpha(cmp));
|
||||
*dst = opBlendNormal(color, *dst, alpha(cmp));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -305,14 +305,14 @@ void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3
|
|||
auto t2 = static_cast<int32_t>(t * FIXPT_SIZE);
|
||||
auto inc2 = static_cast<int32_t>(inc * FIXPT_SIZE);
|
||||
for (uint32_t j = 0; j < len; ++j, ++dst, cmp += csize) {
|
||||
*dst = opAlphaBlend(_fixedPixel(fill, t2), *dst, alpha(cmp));
|
||||
*dst = opBlendNormal(_fixedPixel(fill, t2), *dst, alpha(cmp));
|
||||
t2 += inc2;
|
||||
}
|
||||
//we have to fallback to float math
|
||||
} else {
|
||||
uint32_t counter = 0;
|
||||
while (counter++ < len) {
|
||||
*dst = opAlphaBlend(_pixel(fill, t / GRADIENT_STOP_SIZE), *dst, alpha(cmp));
|
||||
*dst = opBlendNormal(_pixel(fill, t / GRADIENT_STOP_SIZE), *dst, alpha(cmp));
|
||||
++dst;
|
||||
t += inc;
|
||||
cmp += csize;
|
||||
|
@ -322,7 +322,7 @@ void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3
|
|||
if (mathZero(inc)) {
|
||||
auto color = _fixedPixel(fill, static_cast<int32_t>(t * FIXPT_SIZE));
|
||||
for (uint32_t i = 0; i < len; ++i, ++dst, cmp += csize) {
|
||||
*dst = opAlphaBlend(color, *dst, MULTIPLY(alpha(cmp), opacity));
|
||||
*dst = opBlendNormal(color, *dst, MULTIPLY(alpha(cmp), opacity));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -336,14 +336,14 @@ void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3
|
|||
auto t2 = static_cast<int32_t>(t * FIXPT_SIZE);
|
||||
auto inc2 = static_cast<int32_t>(inc * FIXPT_SIZE);
|
||||
for (uint32_t j = 0; j < len; ++j, ++dst, cmp += csize) {
|
||||
*dst = opAlphaBlend(_fixedPixel(fill, t2), *dst, MULTIPLY(alpha(cmp), opacity));
|
||||
*dst = opBlendNormal(_fixedPixel(fill, t2), *dst, MULTIPLY(alpha(cmp), opacity));
|
||||
t2 += inc2;
|
||||
}
|
||||
//we have to fallback to float math
|
||||
} else {
|
||||
uint32_t counter = 0;
|
||||
while (counter++ < len) {
|
||||
*dst = opAlphaBlend(_pixel(fill, t / GRADIENT_STOP_SIZE), *dst, MULTIPLY(opacity, alpha(cmp)));
|
||||
*dst = opBlendNormal(_pixel(fill, t / GRADIENT_STOP_SIZE), *dst, MULTIPLY(opacity, alpha(cmp)));
|
||||
++dst;
|
||||
t += inc;
|
||||
cmp += csize;
|
||||
|
@ -353,7 +353,7 @@ void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3
|
|||
}
|
||||
|
||||
|
||||
void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlendOp op, uint8_t a)
|
||||
void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a)
|
||||
{
|
||||
//Rotation
|
||||
float rx = x + 0.5f;
|
||||
|
|
|
@ -39,7 +39,7 @@ constexpr auto DOWN_SCALE_TOLERANCE = 0.5f;
|
|||
|
||||
struct FillLinear
|
||||
{
|
||||
void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlendOp op, uint8_t a)
|
||||
void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a)
|
||||
{
|
||||
fillLinear(fill, dst, y, x, len, op, a);
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ struct FillLinear
|
|||
|
||||
struct FillRadial
|
||||
{
|
||||
void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlendOp op, uint8_t a)
|
||||
void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a)
|
||||
{
|
||||
fillRadial(fill, dst, y, x, len, op, a);
|
||||
}
|
||||
|
@ -694,7 +694,7 @@ static bool _rasterScaledMaskedRleRGBAImage(SwSurface* surface, const SwImage* i
|
|||
|
||||
if (method == CompositeMethod::AddMask) _rasterScaledMaskedRleRGBAImageDup<AddMaskOp, AddMaskAOp>(surface, image, itransform, region, opacity, halfScale);
|
||||
else if (method == CompositeMethod::SubtractMask) _rasterScaledMaskedRleRGBAImageDup<SubMaskOp, SubMaskAOp>(surface, image, itransform, region, opacity, halfScale);
|
||||
else if (method == CompositeMethod::IntersectMask) _rasterScaledMaskedRleRGBAImageDup<DifMaskOp, DifMaskAOp>(surface, image, itransform, region, opacity, halfScale);
|
||||
else if (method == CompositeMethod::DifferenceMask) _rasterScaledMaskedRleRGBAImageDup<DifMaskOp, DifMaskAOp>(surface, image, itransform, region, opacity, halfScale);
|
||||
else if (method == CompositeMethod::IntersectMask) _rasterScaledMaskedRleRGBAImageInt(surface, image, itransform, region, opacity, halfScale);
|
||||
else return false;
|
||||
|
||||
|
@ -1341,7 +1341,7 @@ static bool _rasterRGBAImage(SwSurface* surface, SwImage* image, const Matrix* t
|
|||
/************************************************************************/
|
||||
|
||||
template<typename fillMethod>
|
||||
static void _rasterGradientMaskedRectDup(SwSurface* surface, const SwBBox& region, const SwFill* fill, SwBlendOp maskOp)
|
||||
static void _rasterGradientMaskedRectDup(SwSurface* surface, const SwBBox& region, const SwFill* fill, SwBlender maskOp)
|
||||
{
|
||||
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
|
||||
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
|
||||
|
@ -1370,7 +1370,7 @@ static void _rasterGradientMaskedRectInt(SwSurface* surface, const SwBBox& regio
|
|||
auto x = surface->compositor->bbox.min.x;
|
||||
while (x < surface->compositor->bbox.max.x) {
|
||||
if (x == region.min.x) {
|
||||
fillMethod()(fill, tmp, y2, x, w, opIntMask, 255);
|
||||
fillMethod()(fill, tmp, y2, x, w, opMaskPreIntersect, 255);
|
||||
x += w;
|
||||
tmp += w;
|
||||
} else {
|
||||
|
@ -1397,9 +1397,9 @@ static bool _rasterGradientMaskedRect(SwSurface* surface, const SwBBox& region,
|
|||
|
||||
TVGLOG("SW_ENGINE", "Masked(%d) Gradient [Region: %lu %lu %lu %lu]", (int)surface->compositor->method, region.min.x, region.min.y, region.max.x - region.min.x, region.max.y - region.min.y);
|
||||
|
||||
if (method == CompositeMethod::AddMask) _rasterGradientMaskedRectDup<fillMethod>(surface, region, fill, opAddMask);
|
||||
else if (method == CompositeMethod::SubtractMask) _rasterGradientMaskedRectDup<fillMethod>(surface, region, fill, opSubMask);
|
||||
else if (method == CompositeMethod::DifferenceMask) _rasterGradientMaskedRectDup<fillMethod>(surface, region, fill, opDifMask);
|
||||
if (method == CompositeMethod::AddMask) _rasterGradientMaskedRectDup<fillMethod>(surface, region, fill, opMaskPreAdd);
|
||||
else if (method == CompositeMethod::SubtractMask) _rasterGradientMaskedRectDup<fillMethod>(surface, region, fill, opMaskPreSubtract);
|
||||
else if (method == CompositeMethod::DifferenceMask) _rasterGradientMaskedRectDup<fillMethod>(surface, region, fill, opMaskPreDifference);
|
||||
else if (method == CompositeMethod::IntersectMask) _rasterGradientMaskedRectInt<fillMethod>(surface, region, fill);
|
||||
else return false;
|
||||
|
||||
|
@ -1437,7 +1437,7 @@ static bool _rasterTranslucentGradientRect(SwSurface* surface, const SwBBox& reg
|
|||
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
|
||||
|
||||
for (uint32_t y = 0; y < h; ++y) {
|
||||
fillMethod()(fill, buffer, region.min.y + y, region.min.x, w, opBlend, 255);
|
||||
fillMethod()(fill, buffer, region.min.y + y, region.min.x, w, opBlendPreNormal, 255);
|
||||
buffer += surface->stride;
|
||||
}
|
||||
return true;
|
||||
|
@ -1452,7 +1452,7 @@ static bool _rasterSolidGradientRect(SwSurface* surface, const SwBBox& region, c
|
|||
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
|
||||
|
||||
for (uint32_t y = 0; y < h; ++y) {
|
||||
fillMethod()(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w, opDirect, 0);
|
||||
fillMethod()(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w, opBlendSrcOver, 255);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1494,7 +1494,7 @@ static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region,
|
|||
/************************************************************************/
|
||||
|
||||
template<typename fillMethod>
|
||||
static void _rasterGradientMaskedRleDup(SwSurface* surface, const SwRleData* rle, const SwFill* fill, SwBlendOp maskOp)
|
||||
static void _rasterGradientMaskedRleDup(SwSurface* surface, const SwRleData* rle, const SwFill* fill, SwBlender maskOp)
|
||||
{
|
||||
auto span = rle->spans;
|
||||
auto cstride = surface->compositor->image.stride;
|
||||
|
@ -1519,7 +1519,7 @@ static void _rasterGradientMaskedRleInt(SwSurface* surface, const SwRleData* rle
|
|||
uint32_t x = surface->compositor->bbox.min.x;
|
||||
while (x < surface->compositor->bbox.max.x) {
|
||||
if (y == span->y && x == span->x && x + span->len <= surface->compositor->bbox.max.x) {
|
||||
fillMethod()(fill, cmp, span->y, span->x, span->len, opIntMask, span->coverage);
|
||||
fillMethod()(fill, cmp, span->y, span->x, span->len, opMaskIntersect, span->coverage);
|
||||
x += span->len;
|
||||
++span;
|
||||
} else {
|
||||
|
@ -1538,9 +1538,9 @@ static bool _rasterGradientMaskedRle(SwSurface* surface, const SwRleData* rle, c
|
|||
|
||||
auto method = surface->compositor->method;
|
||||
|
||||
if (method == CompositeMethod::AddMask) _rasterGradientMaskedRleDup<fillMethod>(surface, rle, fill, opAddMask);
|
||||
else if (method == CompositeMethod::SubtractMask) _rasterGradientMaskedRleDup<fillMethod>(surface, rle, fill, opSubMask);
|
||||
else if (method == CompositeMethod::DifferenceMask) _rasterGradientMaskedRleDup<fillMethod>(surface, rle, fill, opDifMask);
|
||||
if (method == CompositeMethod::AddMask) _rasterGradientMaskedRleDup<fillMethod>(surface, rle, fill, opMaskAdd);
|
||||
else if (method == CompositeMethod::SubtractMask) _rasterGradientMaskedRleDup<fillMethod>(surface, rle, fill, opMaskSubtract);
|
||||
else if (method == CompositeMethod::DifferenceMask) _rasterGradientMaskedRleDup<fillMethod>(surface, rle, fill, opMaskDifference);
|
||||
else if (method == CompositeMethod::IntersectMask) _rasterGradientMaskedRleInt<fillMethod>(surface, rle, fill);
|
||||
else return false;
|
||||
|
||||
|
@ -1575,8 +1575,8 @@ static bool _rasterTranslucentGradientRle(SwSurface* surface, const SwRleData* r
|
|||
|
||||
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
|
||||
auto dst = &surface->buf32[span->y * surface->stride + span->x];
|
||||
if (span->coverage == 255) fillMethod()(fill, dst, span->y, span->x, span->len, opBlend, 255);
|
||||
else fillMethod()(fill, dst, span->y, span->x, span->len, opAlphaBlend, span->coverage);
|
||||
if (span->coverage == 255) fillMethod()(fill, dst, span->y, span->x, span->len, opBlendPreNormal, 255);
|
||||
else fillMethod()(fill, dst, span->y, span->x, span->len, opBlendNormal, span->coverage);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1589,8 +1589,8 @@ static bool _rasterSolidGradientRle(SwSurface* surface, const SwRleData* rle, co
|
|||
|
||||
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
|
||||
auto dst = &surface->buf32[span->y * surface->stride + span->x];
|
||||
if (span->coverage == 255) fillMethod()(fill, dst, span->y, span->x, span->len, opDirect, 0);
|
||||
else fillMethod()(fill, dst, span->y, span->x, span->len, opInterpolate, span->coverage);
|
||||
if (span->coverage == 255) fillMethod()(fill, dst, span->y, span->x, span->len, opBlendSrcOver, 255);
|
||||
else fillMethod()(fill, dst, span->y, span->x, span->len, opBlendInterp, span->coverage);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue