diff --git a/src/examples/images/like.json b/src/examples/images/like.json new file mode 100644 index 00000000..95c14168 --- /dev/null +++ b/src/examples/images/like.json @@ -0,0 +1 @@ +{"assets":[],"layers":[{"ddd":0,"ind":0,"ty":1,"nm":"品蓝色 纯色 1","ks":{"o":{"k":[{"i":{"x":[0.667],"y":[0.667]},"o":{"x":[0.167],"y":[0.167]},"n":["0p667_0p667_0p167_0p167"],"t":0,"s":[100],"e":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.537],"y":[0]},"n":["0p667_1_0p537_0"],"t":5,"s":[100],"e":[0]},{"t":17}]},"r":{"k":0},"p":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[400,320,0],"e":[408,274,0],"to":[1.33333337306976,-7.66666650772095,0],"ti":[-1.33333337306976,7.66666650772095,0]},{"t":17}]},"a":{"k":[400,300,0]},"s":{"k":[{"i":{"x":[0.518,0.518,0.667],"y":[1,1,0.667]},"o":{"x":[0.16,0.16,0.333],"y":[0.329,0.329,0.333]},"n":["0p518_1_0p16_0p329","0p518_1_0p16_0p329","0p667_0p667_0p333_0p333"],"t":5,"s":[0,0,100],"e":[160,160,100]},{"t":17}]}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"f","pt":{"k":{"i":[[0,0],[3.675,0],[0,0],[2.623,1.039],[10.49,18.686],[8.393,0],[0,0],[5.767,-5.706],[-0.526,-6.747],[8.391,-4.158],[2.101,0],[0,0],[0,-4.152],[0,0],[-4.196,0],[0,0],[-1.574,1.04],[-1.051,-0.52],[-31.47,0],[-9.441,41.527],[-2.097,6.748],[5.768,7.267]],"o":[[-7.342,-8.823],[0,0],[-12.065,0],[14.688,-23.358],[-5.772,-9.866],[0,0],[-3.671,-0.52],[-3.672,3.633],[4.198,46.715],[-1.572,-1.556],[0,0],[-4.198,0],[0,0],[0,4.155],[0,0],[2.097,0],[0.525,1.036],[0,0],[31.47,0],[2.098,-9.345],[3.671,-14.014],[0,0]],"v":[[521.158,276.64],[498.604,267.817],[454.021,267.817],[433.565,265.741],[435.663,188.92],[414.159,173.864],[413.112,173.864],[395.279,178.534],[390.561,194.626],[337.06,270.932],[331.816,268.856],[280.411,268.856],[272.544,276.642],[272.544,419.386],[280.411,427.172],[332.339,427.172],[338.111,425.096],[340.208,427.172],[464.514,426.652],[517.49,333.736],[523.785,308.82],[521.16,276.637]],"c":true}},"o":{"k":100},"x":{"k":0},"nm":"蒙版 1"}],"sw":800,"sh":600,"sc":"#00b1ff","ip":0,"op":50,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":1,"ty":1,"nm":"品蓝色 纯色 3","ks":{"o":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":11,"s":[0],"e":[100]},{"t":15}]},"r":{"k":0},"p":{"k":[400,300,0]},"a":{"k":[400,300,0]},"s":{"k":[100,100,100]}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"k":{"i":[[0,0],[3.675,0],[0,0],[2.623,1.039],[10.49,18.686],[8.393,0],[0,0],[5.767,-5.706],[-0.526,-6.747],[8.391,-4.158],[2.101,0],[0,0],[0,-4.152],[0,0],[-4.196,0],[0,0],[-1.574,1.04],[-1.051,-0.52],[-31.47,0],[-9.441,41.527],[-2.097,6.748],[5.768,7.267]],"o":[[-7.342,-8.823],[0,0],[-12.065,0],[14.688,-23.358],[-5.772,-9.866],[0,0],[-3.671,-0.52],[-3.672,3.633],[4.198,46.715],[-1.572,-1.556],[0,0],[-4.198,0],[0,0],[0,4.155],[0,0],[2.097,0],[0.525,1.036],[0,0],[31.47,0],[2.098,-9.345],[3.671,-14.014],[0,0]],"v":[[521.158,276.64],[498.604,267.817],[454.021,267.817],[433.565,265.741],[435.663,188.92],[414.159,173.864],[413.112,173.864],[395.279,178.534],[390.561,194.626],[337.06,270.932],[331.816,268.856],[280.411,268.856],[272.544,276.642],[272.544,419.386],[280.411,427.172],[332.339,427.172],[338.111,425.096],[340.208,427.172],[464.514,426.652],[517.49,333.736],[523.785,308.82],[521.16,276.637]],"c":true}},"o":{"k":100},"x":{"k":0},"nm":"蒙版 3"},{"inv":false,"mode":"s","pt":{"k":{"i":[[0,0],[2.097,-9.861],[18.887,0],[6.816,0],[0,0],[-1.052,0.52],[5.769,62.291],[0.525,0],[-3.147,0],[0,0],[-2.098,-4.669],[12.067,-18.166],[-1.052,-2.596],[-21.503,0],[0,0],[-2.101,-2.597],[2.618,-8.822]],"o":[[-2.098,7.267],[-7.343,32.183],[-30.419,0],[0,0],[1.047,0],[2.624,-1.036],[0,-2.597],[0.525,-0.52],[0,0],[2.098,0],[8.392,15.571],[-4.199,6.23],[4.198,7.267],[0,0],[2.098,0],[3.671,2.597],[0,0]],"v":[[508.045,304.672],[501.75,330.626],[463.984,411.599],[339.679,412.119],[339.679,287.025],[342.303,286.505],[406.292,193.589],[406.292,189.956],[411.537,189.435],[413.634,189.435],[420.977,196.702],[418.353,259.51],[416.781,273.524],[452.971,283.903],[498.081,283.903],[507.524,286.5],[508.049,304.668]],"c":true}},"o":{"k":100},"x":{"k":0},"nm":"蒙版 1"},{"inv":false,"mode":"s","pt":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[323.943,411.599],[287.753,411.599],[287.753,284.428],[323.943,284.428]],"c":true}},"o":{"k":100},"x":{"k":0},"nm":"蒙版 2"}],"sw":800,"sh":600,"sc":"#00b1ff","ip":0,"op":50,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":1,"nm":"品蓝色 纯色 2","ks":{"o":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":11,"s":[0],"e":[27]},{"t":16}]},"r":{"k":0},"p":{"k":[400,300,0]},"a":{"k":[400,300,0]},"s":{"k":[100,100,100]}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"f","pt":{"k":{"i":[[0,0],[3.675,0],[0,0],[2.623,1.039],[10.49,18.686],[8.393,0],[0,0],[5.767,-5.706],[-0.526,-6.747],[8.391,-4.158],[2.101,0],[0,0],[0,-4.152],[0,0],[-4.196,0],[0,0],[-1.574,1.04],[-1.051,-0.52],[-31.47,0],[-9.441,41.527],[-2.097,6.748],[5.768,7.267]],"o":[[-7.342,-8.823],[0,0],[-12.065,0],[14.688,-23.358],[-5.772,-9.866],[0,0],[-3.671,-0.52],[-3.672,3.633],[4.198,46.715],[-1.572,-1.556],[0,0],[-4.198,0],[0,0],[0,4.155],[0,0],[2.097,0],[0.525,1.036],[0,0],[31.47,0],[2.098,-9.345],[3.671,-14.014],[0,0]],"v":[[521.158,276.64],[498.604,267.817],[454.021,267.817],[433.565,265.741],[435.663,188.92],[414.159,173.864],[413.112,173.864],[395.279,178.534],[390.561,194.626],[337.06,270.932],[331.816,268.856],[280.411,268.856],[272.544,276.642],[272.544,419.386],[280.411,427.172],[332.339,427.172],[338.111,425.096],[340.208,427.172],[464.514,426.652],[517.49,333.736],[523.785,308.82],[521.16,276.637]],"c":true}},"o":{"k":100},"x":{"k":0},"nm":"蒙版 1"}],"sw":800,"sh":600,"sc":"#00b1ff","ip":0,"op":50,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":3,"ty":1,"nm":"灰色 纯色 1","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[400,300,0]},"a":{"k":[400,300,0]},"s":{"k":[100,100,100]}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"k":{"i":[[0,0],[3.675,0],[0,0],[2.623,1.039],[10.49,18.686],[8.393,0],[0,0],[5.767,-5.706],[-0.526,-6.747],[8.391,-4.158],[2.101,0],[0,0],[0,-4.152],[0,0],[-4.196,0],[0,0],[-1.574,1.04],[-1.051,-0.52],[-31.47,0],[-9.441,41.527],[-2.097,6.748],[5.768,7.267]],"o":[[-7.342,-8.823],[0,0],[-12.065,0],[14.688,-23.358],[-5.772,-9.866],[0,0],[-3.671,-0.52],[-3.672,3.633],[4.198,46.715],[-1.572,-1.556],[0,0],[-4.198,0],[0,0],[0,4.155],[0,0],[2.097,0],[0.525,1.036],[0,0],[31.47,0],[2.098,-9.345],[3.671,-14.014],[0,0]],"v":[[521.158,276.64],[498.604,267.817],[454.021,267.817],[433.565,265.741],[435.663,188.92],[414.159,173.864],[413.112,173.864],[395.279,178.534],[390.561,194.626],[337.06,270.932],[331.816,268.856],[280.411,268.856],[272.544,276.642],[272.544,419.386],[280.411,427.172],[332.339,427.172],[338.111,425.096],[340.208,427.172],[464.514,426.652],[517.49,333.736],[523.785,308.82],[521.16,276.637]],"c":true}},"o":{"k":100},"x":{"k":0},"nm":"蒙版 3"},{"inv":false,"mode":"s","pt":{"k":{"i":[[0,0],[2.097,-9.861],[18.887,0],[6.816,0],[0,0],[-1.052,0.52],[5.769,62.291],[0.525,0],[-3.147,0],[0,0],[-2.098,-4.669],[12.067,-18.166],[-1.052,-2.596],[-21.503,0],[0,0],[-2.101,-2.597],[2.618,-8.822]],"o":[[-2.098,7.267],[-7.343,32.183],[-30.419,0],[0,0],[1.047,0],[2.624,-1.036],[0,-2.597],[0.525,-0.52],[0,0],[2.098,0],[8.392,15.571],[-4.199,6.23],[4.198,7.267],[0,0],[2.098,0],[3.671,2.597],[0,0]],"v":[[508.045,304.672],[501.75,330.626],[463.984,411.599],[339.679,412.119],[339.679,287.025],[342.303,286.505],[406.292,193.589],[406.292,189.956],[411.537,189.435],[413.634,189.435],[420.977,196.702],[418.353,259.51],[416.781,273.524],[452.971,283.903],[498.081,283.903],[507.524,286.5],[508.049,304.668]],"c":true}},"o":{"k":100},"x":{"k":0},"nm":"蒙版 1"},{"inv":false,"mode":"s","pt":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[323.943,411.599],[287.753,411.599],[287.753,284.428],[323.943,284.428]],"c":true}},"o":{"k":100},"x":{"k":0},"nm":"蒙版 2"}],"sw":800,"sh":600,"sc":"#8c8c8c","ip":0,"op":37,"st":0,"bm":0,"sr":1}],"v":"4.5.4","ddd":0,"ip":0,"op":50,"fr":25,"w":800,"h":600} \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index d99bddd9..c8a615fb 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -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); void fillReset(SwFill* fill); void fillFree(SwFill* fill); + //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, 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); //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 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, 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); //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. SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& renderRegion, bool antiAlias); SwRleData* rleRender(const SwBBox* bbox); diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 77eca813..ca4116a3 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -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 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; for (uint32_t i = 0 ; i < len ; ++i, ++dst, ++cmp) { - auto tmp = op(_pixel(fill, sqrtf(det)), *cmp, a); - *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); + auto src = MULTIPLY(A(_pixel(fill, sqrtf(det))), a); + auto tmp = maskOp(src, *cmp, 0); + *dst = tmp + MULTIPLY(*dst, ~tmp); det += detFirstDerivative; 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) { 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(t * FIXPT_SIZE)))); + for (uint32_t i = 0; i < len; ++i, ++dst) { + *dst = maskOp(src, *dst, ~src); + } + return; + } + + auto vMax = static_cast(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(t * FIXPT_SIZE); + auto inc2 = static_cast(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(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(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(t * FIXPT_SIZE); + auto inc2 = static_cast(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) { //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(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(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(t * FIXPT_SIZE); - auto inc2 = static_cast(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) { //Rotation diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index dba666ae..e27da2e4 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -39,16 +39,21 @@ 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, 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); } - 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); } + 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) { fillLinear(fill, dst, y, x, len, cmp, alpha, csize, opacity); @@ -63,16 +68,21 @@ struct FillLinear 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); } - 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); } + 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) { 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) { //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) { 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 */ /************************************************************************/ -#if 0 + template -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(region.max.y - region.min.y); auto w = static_cast(region.max.x - region.min.x); @@ -1510,13 +1481,13 @@ static bool _rasterCompositeGradientMaskedRect(SwSurface* surface, const SwBBox& template -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(region.max.y - region.min.y); auto w = static_cast(region.max.x - region.min.x); auto cstride = surface->compositor->image.stride; - auto cbuffer = surface->compositor->image.buf32 + (region.min.y * cstride + region.min.x); - auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x); + auto cbuffer = surface->compositor->image.buf8 + (region.min.y * cstride + region.min.x); + auto dbuffer = surface->buf8 + (region.min.y * surface->stride + region.min.x); for (uint32_t y = 0; y < h; ++y) { 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; } -#endif + template static bool _rasterGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) { -#if 0 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); @@ -1539,7 +1509,7 @@ static bool _rasterGradientMaskedRect(SwSurface* surface, const SwBBox& region, if (_direct(method)) return _rasterDirectGradientMaskedRect(surface, region, fill, maskOp); else return _rasterCompositeGradientMaskedRect(surface, region, fill, maskOp); -#endif + return false; } @@ -1651,29 +1621,29 @@ static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region, /************************************************************************/ /* Rle Gradient */ /************************************************************************/ -#if 0 + template -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 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) { auto cmp = &cbuffer[span->y * cstride + span->x]; 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 -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 cstride = surface->compositor->image.stride; - auto cbuffer = surface->compositor->image.buf32; - auto dbuffer = surface->buf32; + auto cbuffer = surface->compositor->image.buf8; + auto dbuffer = surface->buf8; for (uint32_t i = 0; i < rle->size; ++i, ++span) { auto cmp = &cbuffer[span->y * cstride + span->x]; @@ -1682,7 +1652,7 @@ static bool _rasterDirectGradientMaskedRle(SwSurface* surface, const SwRleData* } return true; } -#endif + template 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); - auto amaskOp = _getAMaskOp(method); + auto maskOp = _getMaskOp(method); - //if (_direct(method)) return _rasterDirectGradientMaskedRle(surface, rle, fill, amaskOp); - //else return _rasterCompositeGradientMaskedRle(surface, rle, fill, amaskOp); + if (_direct(method)) return _rasterDirectGradientMaskedRle(surface, rle, fill, maskOp); + else return _rasterCompositeGradientMaskedRle(surface, rle, fill, maskOp); return false; } diff --git a/src/loaders/lottie/tvgLottieBuilder.cpp b/src/loaders/lottie/tvgLottieBuilder.cpp index ba50d8b0..ae61aca9 100644 --- a/src/loaders/lottie/tvgLottieBuilder.cpp +++ b/src/loaders/lottie/tvgLottieBuilder.cpp @@ -558,6 +558,8 @@ static void _updateMaskings(LottieLayer* layer, int32_t frameNo) //maskings+clipping Shape* mergingMask = nullptr; + auto pmethod = CompositeMethod::AlphaMask; + for (auto m = layer->masks.data; m < layer->masks.end(); ++m) { auto mask = static_cast(*m); auto shape = Shape::gen().release(); @@ -567,14 +569,17 @@ static void _updateMaskings(LottieLayer* layer, int32_t frameNo) P(shape)->update(RenderUpdateFlag::Path); } if (mergingMask) { - mergingMask->composite(cast(shape), mask->method); - } - else { auto method = mask->method; - if (method == CompositeMethod::AddMask) method = CompositeMethod::AlphaMask; - if (method == CompositeMethod::SubtractMask) method = CompositeMethod::InvAlphaMask; - layer->scene->composite(cast(shape), method); + if (method == CompositeMethod::SubtractMask && pmethod == method) { + method = CompositeMethod::AddMask; + } else if (pmethod == CompositeMethod::DifferenceMask && pmethod == method) { + method = CompositeMethod::IntersectMask; + } + mergingMask->composite(cast(shape), method); + } else { + layer->scene->composite(cast(shape), CompositeMethod::AlphaMask); } + pmethod = mask->method; mergingMask = shape; } }