diff --git a/src/loaders/lottie/tvgLottieBuilder.cpp b/src/loaders/lottie/tvgLottieBuilder.cpp index 75e4e8c8..a87476f9 100644 --- a/src/loaders/lottie/tvgLottieBuilder.cpp +++ b/src/loaders/lottie/tvgLottieBuilder.cpp @@ -1227,34 +1227,60 @@ void LottieBuilder::updateText(LottieLayer* layer, float frameNo) void LottieBuilder::updateMaskings(LottieLayer* layer, float frameNo) { - if (layer->masks.count == 0) return; + if (layer->masks.count == 0) return; - //Apply the base mask - auto pMask = static_cast(layer->masks[0]); - auto pMethod = pMask->method; - auto opacity = pMask->opacity(frameNo); - auto expand = pMask->expand(frameNo); + Shape* pShape = nullptr; + CompositeMethod pMethod; + uint8_t pOpacity; - auto pShape = layer->pooling(); - pShape->reset(); - pShape->fill(255, 255, 255, opacity); - pShape->transform(layer->cache.matrix); + for (auto m = layer->masks.begin(); m < layer->masks.end(); ++m) { + auto mask = *m; + if (mask->method == CompositeMethod::None) continue; - //Apply Masking Expansion (Offset) - if (expand == 0.0f) { - pMask->pathset(frameNo, P(pShape)->rs.path.cmds, P(pShape)->rs.path.pts, nullptr, nullptr, nullptr, exps); - } else { - //TODO: Once path direction support is implemented, ensure that the direction is ignored here - auto offset = LottieOffsetModifier(pMask->expand(frameNo)); - pMask->pathset(frameNo, P(pShape)->rs.path.cmds, P(pShape)->rs.path.pts, nullptr, nullptr, &offset, exps); - } + auto method = mask->method; + auto opacity = mask->opacity(frameNo); + auto expand = mask->expand(frameNo); + auto fastTrack = false; //single clipping - auto compMethod = (pMethod == CompositeMethod::SubtractMask || pMethod == CompositeMethod::InvAlphaMask) ? CompositeMethod::InvAlphaMask : CompositeMethod::AlphaMask; + //the first mask + if (!pShape) { + pShape = layer->pooling(); + pShape->reset(); + pShape->fill(255, 255, 255, opacity); + pShape->transform(layer->cache.matrix); + auto compMethod = (method == CompositeMethod::SubtractMask || method == CompositeMethod::InvAlphaMask) ? CompositeMethod::InvAlphaMask : CompositeMethod::AlphaMask; + //Cheaper. Replace the masking with a clipper + if (layer->masks.count == 1 && compMethod == CompositeMethod::AlphaMask) { + layer->scene->opacity(MULTIPLY(layer->scene->opacity(), opacity)); + layer->scene->clip(cast(pShape)); + fastTrack = true; + } else { + layer->scene->composite(cast(pShape), compMethod); + } + //Chain mask composition + } else if (pMethod != method || pOpacity != opacity || (method != CompositeMethod::SubtractMask && method != CompositeMethod::DifferenceMask)) { + auto shape = layer->pooling(); + shape->reset(); + shape->fill(255, 255, 255, opacity); + shape->transform(layer->cache.matrix); + pShape->composite(cast(shape), method); + pShape = shape; + } - //Cheaper. Replace the masking with a clipper - if (layer->masks.count == 1 && compMethod == CompositeMethod::AlphaMask && opacity == 255) { - layer->scene->clip(tvg::cast(pShape)); - return; + //Default Masking + if (expand == 0.0f) { + mask->pathset(frameNo, P(pShape)->rs.path.cmds, P(pShape)-> rs.path.pts, nullptr, nullptr, nullptr, exps); + //Masking with Expansion (Offset) + } else { + //TODO: Once path direction support is implemented, ensure that the direction is ignored here + auto offset = LottieOffsetModifier(expand); + mask->pathset(frameNo, P(pShape)->rs.path.cmds, P(pShape)->rs.path.pts, nullptr, nullptr, &offset, exps); + } + + if (fastTrack) return; + + pOpacity = opacity; + pMethod = method; } //Introduce an intermediate scene for embracing the matte + masking @@ -1263,30 +1289,6 @@ void LottieBuilder::updateMaskings(LottieLayer* layer, float frameNo) scene->push(cast(layer->scene)); layer->scene = scene; } - - layer->scene->composite(tvg::cast(pShape), compMethod); - - //Apply the subsquent masks - for (auto m = layer->masks.begin() + 1; m < layer->masks.end(); ++m) { - auto mask = static_cast(*m); - auto method = mask->method; - if (method == CompositeMethod::None) continue; - - //Append the mask shape - if (pMethod == method && (method == CompositeMethod::SubtractMask || method == CompositeMethod::DifferenceMask)) { - mask->pathset(frameNo, P(pShape)->rs.path.cmds, P(pShape)->rs.path.pts, nullptr, nullptr, nullptr, exps); - //Chain composition - } else { - auto shape = layer->pooling(); - shape->reset(); - shape->fill(255, 255, 255, mask->opacity(frameNo)); - shape->transform(layer->cache.matrix); - mask->pathset(frameNo, P(shape)->rs.path.cmds, P(shape)->rs.path.pts, nullptr, nullptr, nullptr, exps); - pShape->composite(tvg::cast(shape), method); - pShape = shape; - pMethod = method; - } - } } diff --git a/src/loaders/lottie/tvgLottieParser.cpp b/src/loaders/lottie/tvgLottieParser.cpp index c4b5037b..14a92fc2 100644 --- a/src/loaders/lottie/tvgLottieParser.cpp +++ b/src/loaders/lottie/tvgLottieParser.cpp @@ -1235,27 +1235,15 @@ void LottieParser::getLayerSize(float& val) LottieMask* LottieParser::parseMask() { auto mask = new LottieMask; - auto valid = true; //skip if the mask mode is none. - enterObject(); while (auto key = nextObjectKey()) { if (KEY_AS("inv")) mask->inverse = getBool(); - else if (KEY_AS("mode")) - { - mask->method = getMaskMethod(mask->inverse); - if (mask->method == CompositeMethod::None) valid = false; - } - else if (valid && KEY_AS("pt")) getPathSet(mask->pathset); - else if (valid && KEY_AS("o")) parseProperty(mask->opacity); - else if (valid && KEY_AS("x")) parseProperty(mask->expand); + else if (KEY_AS("mode")) mask->method = getMaskMethod(mask->inverse); + else if (KEY_AS("pt")) getPathSet(mask->pathset); + else if (KEY_AS("o")) parseProperty(mask->opacity); + else if (KEY_AS("x")) parseProperty(mask->expand); else skip(key); } - - if (!valid) { - delete(mask); - return nullptr; - } - return mask; } @@ -1319,7 +1307,6 @@ void LottieParser::parseTritone(LottieFxTritone* effect) } - void LottieParser::parseFill(LottieFxFill* effect) { int idx = 0; //fill mask -> all mask -> color -> invert -> h feather -> v feather -> opacity