mirror of
https://github.com/thorvg/thorvg.git
synced 2025-07-28 17:15:57 +00:00
loader/lottie: introduce chaining maskings more effectively.
This commit is contained in:
parent
21413b1872
commit
07069f6640
5 changed files with 165 additions and 121 deletions
1
src/examples/images/like.json
Normal file
1
src/examples/images/like.json
Normal file
File diff suppressed because one or more lines are too long
|
@ -512,15 +512,19 @@ void imageFree(SwImage* image);
|
||||||
bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, SwSurface* surface, uint8_t opacity, bool ctable);
|
bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, SwSurface* surface, uint8_t opacity, bool ctable);
|
||||||
void fillReset(SwFill* fill);
|
void fillReset(SwFill* fill);
|
||||||
void fillFree(SwFill* fill);
|
void fillFree(SwFill* fill);
|
||||||
|
|
||||||
//OPTIMIZE_ME: Skip the function pointer access
|
//OPTIMIZE_ME: Skip the function pointer access
|
||||||
|
void fillLinear(const SwFill* fill, uint8_t* dst, uint32_t y, uint32_t x, uint32_t len, SwMask maskOp, uint8_t opacity); //composite masking ver.
|
||||||
|
void fillLinear(const SwFill* fill, uint8_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwMask maskOp, uint8_t opacity); //direct masking 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, SwBlender 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, SwBlender op2, uint8_t a); //blending + BlendingMethod(op2) ver.
|
void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, SwBlender op2, uint8_t a); //blending + BlendingMethod(op2) ver.
|
||||||
void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint32_t* cmp, SwBlender op, uint8_t a); //direct masking 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); //matting 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, uint8_t* dst, uint32_t y, uint32_t x, uint32_t len, SwMask op, uint8_t a); //composite masking ver.
|
||||||
|
void fillRadial(const SwFill* fill, uint8_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwMask op, uint8_t a) ; //direct masking 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, SwBlender 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, SwBlender op2, uint8_t a); //blending + BlendingMethod(op2) ver.
|
void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, SwBlender op2, uint8_t a); //blending + BlendingMethod(op2) ver.
|
||||||
void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint32_t* cmp, SwBlender op, uint8_t a) ; //direct masking 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); //matting 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);
|
SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& renderRegion, bool antiAlias);
|
||||||
SwRleData* rleRender(const SwBBox* bbox);
|
SwRleData* rleRender(const SwBBox* bbox);
|
||||||
|
|
|
@ -279,7 +279,27 @@ 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, uint32_t* cmp, SwBlender op, uint8_t a)
|
void fillRadial(const SwFill* fill, uint8_t* dst, uint32_t y, uint32_t x, uint32_t len, SwMask maskOp, 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;
|
||||||
|
|
||||||
|
// detSecondDerivative = d(detFirstDerivative)/dx = d( d(det)/dx )/dx
|
||||||
|
auto detSecondDerivative = fill->radial.detSecDeriv;
|
||||||
|
// detFirstDerivative = d(det)/dx
|
||||||
|
auto detFirstDerivative = 2.0f * (fill->radial.a11 * rx + fill->radial.a21 * ry) + 0.5f * detSecondDerivative;
|
||||||
|
auto det = rx * rx + ry * ry;
|
||||||
|
|
||||||
|
for (uint32_t i = 0 ; i < len ; ++i, ++dst) {
|
||||||
|
auto src = MULTIPLY(a, A(_pixel(fill, sqrtf(det))));
|
||||||
|
*dst = maskOp(src, *dst, ~src);
|
||||||
|
det += detFirstDerivative;
|
||||||
|
detFirstDerivative += detSecondDerivative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void fillRadial(const SwFill* fill, uint8_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwMask maskOp, uint8_t a)
|
||||||
{
|
{
|
||||||
auto rx = (x + 0.5f) * fill->radial.a11 + (y + 0.5f) * fill->radial.a12 + fill->radial.shiftX;
|
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;
|
auto ry = (x + 0.5f) * fill->radial.a21 + (y + 0.5f) * fill->radial.a22 + fill->radial.shiftY;
|
||||||
|
@ -291,15 +311,15 @@ void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3
|
||||||
auto det = rx * rx + ry * ry;
|
auto det = rx * rx + ry * ry;
|
||||||
|
|
||||||
for (uint32_t i = 0 ; i < len ; ++i, ++dst, ++cmp) {
|
for (uint32_t i = 0 ; i < len ; ++i, ++dst, ++cmp) {
|
||||||
auto tmp = op(_pixel(fill, sqrtf(det)), *cmp, a);
|
auto src = MULTIPLY(A(_pixel(fill, sqrtf(det))), a);
|
||||||
*dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
|
auto tmp = maskOp(src, *cmp, 0);
|
||||||
|
*dst = tmp + MULTIPLY(*dst, ~tmp);
|
||||||
det += detFirstDerivative;
|
det += detFirstDerivative;
|
||||||
detFirstDerivative += detSecondDerivative;
|
detFirstDerivative += detSecondDerivative;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, SwBlender op2, uint8_t a)
|
void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, SwBlender op2, uint8_t a)
|
||||||
{
|
{
|
||||||
auto rx = (x + 0.5f) * fill->radial.a11 + (y + 0.5f) * fill->radial.a12 + fill->radial.shiftX;
|
auto rx = (x + 0.5f) * fill->radial.a11 + (y + 0.5f) * fill->radial.a12 + fill->radial.shiftX;
|
||||||
|
@ -404,6 +424,95 @@ void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void fillLinear(const SwFill* fill, uint8_t* dst, uint32_t y, uint32_t x, uint32_t len, SwMask maskOp, uint8_t a)
|
||||||
|
{
|
||||||
|
//Rotation
|
||||||
|
float rx = x + 0.5f;
|
||||||
|
float ry = y + 0.5f;
|
||||||
|
float t = (fill->linear.dx * rx + fill->linear.dy * ry + fill->linear.offset) * (GRADIENT_STOP_SIZE - 1);
|
||||||
|
float inc = (fill->linear.dx) * (GRADIENT_STOP_SIZE - 1);
|
||||||
|
|
||||||
|
if (mathZero(inc)) {
|
||||||
|
auto src = MULTIPLY(a, A(_fixedPixel(fill, static_cast<int32_t>(t * FIXPT_SIZE))));
|
||||||
|
for (uint32_t i = 0; i < len; ++i, ++dst) {
|
||||||
|
*dst = maskOp(src, *dst, ~src);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto vMax = static_cast<float>(INT32_MAX >> (FIXPT_BITS + 1));
|
||||||
|
auto vMin = -vMax;
|
||||||
|
auto v = t + (inc * len);
|
||||||
|
|
||||||
|
//we can use fixed point math
|
||||||
|
if (v < vMax && v > vMin) {
|
||||||
|
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) {
|
||||||
|
auto src = MULTIPLY(_fixedPixel(fill, t2), a);
|
||||||
|
*dst = maskOp(src, *dst, ~src);
|
||||||
|
t2 += inc2;
|
||||||
|
}
|
||||||
|
//we have to fallback to float math
|
||||||
|
} else {
|
||||||
|
uint32_t counter = 0;
|
||||||
|
while (counter++ < len) {
|
||||||
|
auto src = MULTIPLY(_pixel(fill, t / GRADIENT_STOP_SIZE), a);
|
||||||
|
*dst = maskOp(src, *dst, ~src);
|
||||||
|
++dst;
|
||||||
|
t += inc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void fillLinear(const SwFill* fill, uint8_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwMask maskOp, uint8_t a)
|
||||||
|
{
|
||||||
|
//Rotation
|
||||||
|
float rx = x + 0.5f;
|
||||||
|
float ry = y + 0.5f;
|
||||||
|
float t = (fill->linear.dx * rx + fill->linear.dy * ry + fill->linear.offset) * (GRADIENT_STOP_SIZE - 1);
|
||||||
|
float inc = (fill->linear.dx) * (GRADIENT_STOP_SIZE - 1);
|
||||||
|
|
||||||
|
if (mathZero(inc)) {
|
||||||
|
auto src = A(_fixedPixel(fill, static_cast<int32_t>(t * FIXPT_SIZE)));
|
||||||
|
src = MULTIPLY(src, a);
|
||||||
|
for (uint32_t i = 0; i < len; ++i, ++dst, ++cmp) {
|
||||||
|
auto tmp = maskOp(src, *cmp, 0);
|
||||||
|
*dst = tmp + MULTIPLY(*dst, ~tmp);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto vMax = static_cast<float>(INT32_MAX >> (FIXPT_BITS + 1));
|
||||||
|
auto vMin = -vMax;
|
||||||
|
auto v = t + (inc * len);
|
||||||
|
|
||||||
|
//we can use fixed point math
|
||||||
|
if (v < vMax && v > vMin) {
|
||||||
|
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) {
|
||||||
|
auto src = MULTIPLY(a, A(_fixedPixel(fill, t2)));
|
||||||
|
auto tmp = maskOp(src, *cmp, 0);
|
||||||
|
*dst = tmp + MULTIPLY(*dst, ~tmp);
|
||||||
|
t2 += inc2;
|
||||||
|
}
|
||||||
|
//we have to fallback to float math
|
||||||
|
} else {
|
||||||
|
uint32_t counter = 0;
|
||||||
|
while (counter++ < len) {
|
||||||
|
auto src = MULTIPLY(A(_pixel(fill, t / GRADIENT_STOP_SIZE)), a);
|
||||||
|
auto tmp = maskOp(src, *cmp, 0);
|
||||||
|
*dst = tmp + MULTIPLY(*dst, ~tmp);
|
||||||
|
++dst;
|
||||||
|
++cmp;
|
||||||
|
t += inc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender 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
|
//Rotation
|
||||||
|
@ -444,51 +553,6 @@ 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, uint32_t* cmp, SwBlender op, uint8_t a)
|
|
||||||
{
|
|
||||||
//Rotation
|
|
||||||
float rx = x + 0.5f;
|
|
||||||
float ry = y + 0.5f;
|
|
||||||
float t = (fill->linear.dx * rx + fill->linear.dy * ry + fill->linear.offset) * (GRADIENT_STOP_SIZE - 1);
|
|
||||||
float inc = (fill->linear.dx) * (GRADIENT_STOP_SIZE - 1);
|
|
||||||
|
|
||||||
if (mathZero(inc)) {
|
|
||||||
auto color = _fixedPixel(fill, static_cast<int32_t>(t * FIXPT_SIZE));
|
|
||||||
for (uint32_t i = 0; i < len; ++i, ++dst, ++cmp) {
|
|
||||||
auto tmp = op(color, *cmp, a);
|
|
||||||
*dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto vMax = static_cast<float>(INT32_MAX >> (FIXPT_BITS + 1));
|
|
||||||
auto vMin = -vMax;
|
|
||||||
auto v = t + (inc * len);
|
|
||||||
|
|
||||||
//we can use fixed point math
|
|
||||||
if (v < vMax && v > vMin) {
|
|
||||||
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) {
|
|
||||||
auto tmp = op(_fixedPixel(fill, t2), *cmp, a);
|
|
||||||
*dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
|
|
||||||
t2 += inc2;
|
|
||||||
}
|
|
||||||
//we have to fallback to float math
|
|
||||||
} else {
|
|
||||||
uint32_t counter = 0;
|
|
||||||
while (counter++ < len) {
|
|
||||||
auto tmp = op(_pixel(fill, t / GRADIENT_STOP_SIZE), *cmp, a);
|
|
||||||
*dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
|
|
||||||
++dst;
|
|
||||||
++cmp;
|
|
||||||
t += inc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, SwBlender op2, uint8_t a)
|
void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, SwBlender op2, uint8_t a)
|
||||||
{
|
{
|
||||||
//Rotation
|
//Rotation
|
||||||
|
|
|
@ -39,16 +39,21 @@ constexpr auto DOWN_SCALE_TOLERANCE = 0.5f;
|
||||||
|
|
||||||
struct FillLinear
|
struct FillLinear
|
||||||
{
|
{
|
||||||
void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a)
|
void operator()(const SwFill* fill, uint8_t* dst, uint32_t y, uint32_t x, uint32_t len, SwMask op, uint8_t a)
|
||||||
{
|
{
|
||||||
fillLinear(fill, dst, y, x, len, op, a);
|
fillLinear(fill, dst, y, x, len, op, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint32_t* cmp, SwBlender op, uint8_t a)
|
void operator()(const SwFill* fill, uint8_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwMask op, uint8_t a)
|
||||||
{
|
{
|
||||||
fillLinear(fill, dst, y, x, len, cmp, op, a);
|
fillLinear(fill, dst, y, x, len, cmp, op, 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);
|
||||||
|
}
|
||||||
|
|
||||||
void operator()(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)
|
void operator()(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)
|
||||||
{
|
{
|
||||||
fillLinear(fill, dst, y, x, len, cmp, alpha, csize, opacity);
|
fillLinear(fill, dst, y, x, len, cmp, alpha, csize, opacity);
|
||||||
|
@ -63,16 +68,21 @@ struct FillLinear
|
||||||
|
|
||||||
struct FillRadial
|
struct FillRadial
|
||||||
{
|
{
|
||||||
void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a)
|
void operator()(const SwFill* fill, uint8_t* dst, uint32_t y, uint32_t x, uint32_t len, SwMask op, uint8_t a)
|
||||||
{
|
{
|
||||||
fillRadial(fill, dst, y, x, len, op, a);
|
fillRadial(fill, dst, y, x, len, op, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint32_t* cmp, SwBlender op, uint8_t a)
|
void operator()(const SwFill* fill, uint8_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwMask op, uint8_t a)
|
||||||
{
|
{
|
||||||
fillRadial(fill, dst, y, x, len, cmp, op, a);
|
fillRadial(fill, dst, y, x, len, cmp, op, 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);
|
||||||
|
}
|
||||||
|
|
||||||
void operator()(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)
|
void operator()(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)
|
||||||
{
|
{
|
||||||
fillRadial(fill, dst, y, x, len, cmp, alpha, csize, opacity);
|
fillRadial(fill, dst, y, x, len, cmp, alpha, csize, opacity);
|
||||||
|
@ -187,33 +197,6 @@ static inline uint8_t _opMaskDifference(uint8_t s, uint8_t d, uint8_t a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline uint8_t _opAMaskAdd(uint8_t s, uint8_t d, uint8_t a)
|
|
||||||
{
|
|
||||||
return INTERPOLATE8(s, d, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline uint8_t _opAMaskSubtract(TVG_UNUSED uint8_t s, uint8_t d, uint8_t a)
|
|
||||||
{
|
|
||||||
return s;
|
|
||||||
//return ALPHA_BLEND(s, MULTIPLY(IA(d), a));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline uint8_t _opAMaskDifference(uint8_t s, uint8_t d, uint8_t a)
|
|
||||||
{
|
|
||||||
auto t = MULTIPLY(s, a);
|
|
||||||
return MULTIPLY(t, 255 - d) + MULTIPLY(d, 255 - t);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline uint8_t _opAMaskIntersect(uint8_t s, uint8_t d, uint8_t a)
|
|
||||||
{
|
|
||||||
return s;
|
|
||||||
//return ALPHA_BLEND(s, MULTIPLY(A(d), a));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline bool _direct(CompositeMethod method)
|
static inline bool _direct(CompositeMethod method)
|
||||||
{
|
{
|
||||||
//subtract & Intersect allows the direct composition
|
//subtract & Intersect allows the direct composition
|
||||||
|
@ -234,18 +217,6 @@ static inline SwMask _getMaskOp(CompositeMethod method)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline SwMask _getAMaskOp(CompositeMethod method)
|
|
||||||
{
|
|
||||||
switch (method) {
|
|
||||||
case CompositeMethod::AddMask: return _opAMaskAdd;
|
|
||||||
case CompositeMethod::SubtractMask: return _opAMaskSubtract;
|
|
||||||
case CompositeMethod::DifferenceMask: return _opAMaskDifference;
|
|
||||||
case CompositeMethod::IntersectMask: return _opAMaskIntersect;
|
|
||||||
default: return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static bool _compositeMaskImage(SwSurface* surface, const SwImage* image, const SwBBox& region)
|
static bool _compositeMaskImage(SwSurface* surface, const SwImage* image, const SwBBox& region)
|
||||||
{
|
{
|
||||||
auto dbuffer = &surface->buf8[region.min.y * surface->stride + region.min.x];
|
auto dbuffer = &surface->buf8[region.min.y * surface->stride + region.min.x];
|
||||||
|
@ -1492,9 +1463,9 @@ static bool _rasterImage(SwSurface* surface, SwImage* image, const Matrix* trans
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/* Rect Gradient */
|
/* Rect Gradient */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
#if 0
|
|
||||||
template<typename fillMethod>
|
template<typename fillMethod>
|
||||||
static bool _rasterCompositeGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, SwBlender maskOp)
|
static bool _rasterCompositeGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, SwMask maskOp)
|
||||||
{
|
{
|
||||||
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
|
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 w = static_cast<uint32_t>(region.max.x - region.min.x);
|
||||||
|
@ -1510,13 +1481,13 @@ static bool _rasterCompositeGradientMaskedRect(SwSurface* surface, const SwBBox&
|
||||||
|
|
||||||
|
|
||||||
template<typename fillMethod>
|
template<typename fillMethod>
|
||||||
static bool _rasterDirectGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, SwBlender maskOp)
|
static bool _rasterDirectGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, SwMask maskOp)
|
||||||
{
|
{
|
||||||
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
|
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 w = static_cast<uint32_t>(region.max.x - region.min.x);
|
||||||
auto cstride = surface->compositor->image.stride;
|
auto cstride = surface->compositor->image.stride;
|
||||||
auto cbuffer = surface->compositor->image.buf32 + (region.min.y * cstride + region.min.x);
|
auto cbuffer = surface->compositor->image.buf8 + (region.min.y * cstride + region.min.x);
|
||||||
auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x);
|
auto dbuffer = surface->buf8 + (region.min.y * surface->stride + region.min.x);
|
||||||
|
|
||||||
for (uint32_t y = 0; y < h; ++y) {
|
for (uint32_t y = 0; y < h; ++y) {
|
||||||
fillMethod()(fill, dbuffer, region.min.y + y, region.min.x, w, cbuffer, maskOp, 255);
|
fillMethod()(fill, dbuffer, region.min.y + y, region.min.x, w, cbuffer, maskOp, 255);
|
||||||
|
@ -1525,12 +1496,11 @@ static bool _rasterDirectGradientMaskedRect(SwSurface* surface, const SwBBox& re
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
template<typename fillMethod>
|
template<typename fillMethod>
|
||||||
static bool _rasterGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
|
static bool _rasterGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
auto method = surface->compositor->method;
|
auto method = surface->compositor->method;
|
||||||
|
|
||||||
TVGLOG("SW_ENGINE", "Masked(%d) Gradient [Region: %lu %lu %lu %lu]", (int)method, region.min.x, region.min.y, region.max.x - region.min.x, region.max.y - region.min.y);
|
TVGLOG("SW_ENGINE", "Masked(%d) Gradient [Region: %lu %lu %lu %lu]", (int)method, region.min.x, region.min.y, region.max.x - region.min.x, region.max.y - region.min.y);
|
||||||
|
@ -1539,7 +1509,7 @@ static bool _rasterGradientMaskedRect(SwSurface* surface, const SwBBox& region,
|
||||||
|
|
||||||
if (_direct(method)) return _rasterDirectGradientMaskedRect<fillMethod>(surface, region, fill, maskOp);
|
if (_direct(method)) return _rasterDirectGradientMaskedRect<fillMethod>(surface, region, fill, maskOp);
|
||||||
else return _rasterCompositeGradientMaskedRect<fillMethod>(surface, region, fill, maskOp);
|
else return _rasterCompositeGradientMaskedRect<fillMethod>(surface, region, fill, maskOp);
|
||||||
#endif
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1651,29 +1621,29 @@ static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region,
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/* Rle Gradient */
|
/* Rle Gradient */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
#if 0
|
|
||||||
template<typename fillMethod>
|
template<typename fillMethod>
|
||||||
static bool _rasterCompositeGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, SwBlender maskOp)
|
static bool _rasterCompositeGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, SwMask maskOp)
|
||||||
{
|
{
|
||||||
auto span = rle->spans;
|
auto span = rle->spans;
|
||||||
auto cstride = surface->compositor->image.stride;
|
auto cstride = surface->compositor->image.stride;
|
||||||
auto cbuffer = surface->compositor->image.buf32;
|
auto cbuffer = surface->compositor->image.buf8;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
|
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
|
||||||
auto cmp = &cbuffer[span->y * cstride + span->x];
|
auto cmp = &cbuffer[span->y * cstride + span->x];
|
||||||
fillMethod()(fill, cmp, span->y, span->x, span->len, maskOp, span->coverage);
|
fillMethod()(fill, cmp, span->y, span->x, span->len, maskOp, span->coverage);
|
||||||
}
|
}
|
||||||
return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox, 255);
|
return _compositeMaskImage(surface, &surface->compositor->image, surface->compositor->bbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename fillMethod>
|
template<typename fillMethod>
|
||||||
static bool _rasterDirectGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, SwBlender maskOp)
|
static bool _rasterDirectGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, SwMask maskOp)
|
||||||
{
|
{
|
||||||
auto span = rle->spans;
|
auto span = rle->spans;
|
||||||
auto cstride = surface->compositor->image.stride;
|
auto cstride = surface->compositor->image.stride;
|
||||||
auto cbuffer = surface->compositor->image.buf32;
|
auto cbuffer = surface->compositor->image.buf8;
|
||||||
auto dbuffer = surface->buf32;
|
auto dbuffer = surface->buf8;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
|
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
|
||||||
auto cmp = &cbuffer[span->y * cstride + span->x];
|
auto cmp = &cbuffer[span->y * cstride + span->x];
|
||||||
|
@ -1682,7 +1652,7 @@ static bool _rasterDirectGradientMaskedRle(SwSurface* surface, const SwRleData*
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
template<typename fillMethod>
|
template<typename fillMethod>
|
||||||
static bool _rasterGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
|
static bool _rasterGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
|
||||||
|
@ -1691,10 +1661,10 @@ static bool _rasterGradientMaskedRle(SwSurface* surface, const SwRleData* rle, c
|
||||||
|
|
||||||
TVGLOG("SW_ENGINE", "Masked(%d) Rle Linear Gradient", (int)method);
|
TVGLOG("SW_ENGINE", "Masked(%d) Rle Linear Gradient", (int)method);
|
||||||
|
|
||||||
auto amaskOp = _getAMaskOp(method);
|
auto maskOp = _getMaskOp(method);
|
||||||
|
|
||||||
//if (_direct(method)) return _rasterDirectGradientMaskedRle<fillMethod>(surface, rle, fill, amaskOp);
|
if (_direct(method)) return _rasterDirectGradientMaskedRle<fillMethod>(surface, rle, fill, maskOp);
|
||||||
//else return _rasterCompositeGradientMaskedRle<fillMethod>(surface, rle, fill, amaskOp);
|
else return _rasterCompositeGradientMaskedRle<fillMethod>(surface, rle, fill, maskOp);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -558,6 +558,8 @@ static void _updateMaskings(LottieLayer* layer, int32_t frameNo)
|
||||||
//maskings+clipping
|
//maskings+clipping
|
||||||
Shape* mergingMask = nullptr;
|
Shape* mergingMask = nullptr;
|
||||||
|
|
||||||
|
auto pmethod = CompositeMethod::AlphaMask;
|
||||||
|
|
||||||
for (auto m = layer->masks.data; m < layer->masks.end(); ++m) {
|
for (auto m = layer->masks.data; m < layer->masks.end(); ++m) {
|
||||||
auto mask = static_cast<LottieMask*>(*m);
|
auto mask = static_cast<LottieMask*>(*m);
|
||||||
auto shape = Shape::gen().release();
|
auto shape = Shape::gen().release();
|
||||||
|
@ -567,14 +569,17 @@ static void _updateMaskings(LottieLayer* layer, int32_t frameNo)
|
||||||
P(shape)->update(RenderUpdateFlag::Path);
|
P(shape)->update(RenderUpdateFlag::Path);
|
||||||
}
|
}
|
||||||
if (mergingMask) {
|
if (mergingMask) {
|
||||||
mergingMask->composite(cast<Shape>(shape), mask->method);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
auto method = mask->method;
|
auto method = mask->method;
|
||||||
if (method == CompositeMethod::AddMask) method = CompositeMethod::AlphaMask;
|
if (method == CompositeMethod::SubtractMask && pmethod == method) {
|
||||||
if (method == CompositeMethod::SubtractMask) method = CompositeMethod::InvAlphaMask;
|
method = CompositeMethod::AddMask;
|
||||||
layer->scene->composite(cast<Shape>(shape), method);
|
} else if (pmethod == CompositeMethod::DifferenceMask && pmethod == method) {
|
||||||
|
method = CompositeMethod::IntersectMask;
|
||||||
|
}
|
||||||
|
mergingMask->composite(cast<Shape>(shape), method);
|
||||||
|
} else {
|
||||||
|
layer->scene->composite(cast<Shape>(shape), CompositeMethod::AlphaMask);
|
||||||
}
|
}
|
||||||
|
pmethod = mask->method;
|
||||||
mergingMask = shape;
|
mergingMask = shape;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue