lottie: revise the masking logic

- Allow the masking data even though they were mask None mode.
  Those will be used by the layer stroke effect.
- Fixed masking Offset to apply to all masking chains.
- Optimized fast track masking with resolving the opaicty condition.
- Clean up the overall code.
This commit is contained in:
Hermet Park 2024-12-18 15:29:58 +09:00 committed by Mira Grudzinska
parent 2eed9f9024
commit 00324f5e19
2 changed files with 53 additions and 64 deletions

View file

@ -1227,34 +1227,60 @@ void LottieBuilder::updateText(LottieLayer* layer, float frameNo)
void LottieBuilder::updateMaskings(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 Shape* pShape = nullptr;
auto pMask = static_cast<LottieMask*>(layer->masks[0]); CompositeMethod pMethod;
auto pMethod = pMask->method; uint8_t pOpacity;
auto opacity = pMask->opacity(frameNo);
auto expand = pMask->expand(frameNo);
auto pShape = layer->pooling(); for (auto m = layer->masks.begin(); m < layer->masks.end(); ++m) {
pShape->reset(); auto mask = *m;
pShape->fill(255, 255, 255, opacity); if (mask->method == CompositeMethod::None) continue;
pShape->transform(layer->cache.matrix);
//Apply Masking Expansion (Offset) auto method = mask->method;
if (expand == 0.0f) { auto opacity = mask->opacity(frameNo);
pMask->pathset(frameNo, P(pShape)->rs.path.cmds, P(pShape)->rs.path.pts, nullptr, nullptr, nullptr, exps); auto expand = mask->expand(frameNo);
} else { auto fastTrack = false; //single clipping
//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 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 //Default Masking
if (layer->masks.count == 1 && compMethod == CompositeMethod::AlphaMask && opacity == 255) { if (expand == 0.0f) {
layer->scene->clip(tvg::cast(pShape)); mask->pathset(frameNo, P(pShape)->rs.path.cmds, P(pShape)-> rs.path.pts, nullptr, nullptr, nullptr, exps);
return; //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 //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)); scene->push(cast(layer->scene));
layer->scene = 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<LottieMask*>(*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;
}
}
} }

View file

@ -1235,27 +1235,15 @@ void LottieParser::getLayerSize(float& val)
LottieMask* LottieParser::parseMask() LottieMask* LottieParser::parseMask()
{ {
auto mask = new LottieMask; auto mask = new LottieMask;
auto valid = true; //skip if the mask mode is none.
enterObject(); enterObject();
while (auto key = nextObjectKey()) { while (auto key = nextObjectKey()) {
if (KEY_AS("inv")) mask->inverse = getBool(); if (KEY_AS("inv")) mask->inverse = getBool();
else if (KEY_AS("mode")) else if (KEY_AS("mode")) mask->method = getMaskMethod(mask->inverse);
{ else if (KEY_AS("pt")) getPathSet(mask->pathset);
mask->method = getMaskMethod(mask->inverse); else if (KEY_AS("o")) parseProperty<LottieProperty::Type::Opacity>(mask->opacity);
if (mask->method == CompositeMethod::None) valid = false; else if (KEY_AS("x")) parseProperty<LottieProperty::Type::Float>(mask->expand);
}
else if (valid && KEY_AS("pt")) getPathSet(mask->pathset);
else if (valid && KEY_AS("o")) parseProperty<LottieProperty::Type::Opacity>(mask->opacity);
else if (valid && KEY_AS("x")) parseProperty<LottieProperty::Type::Float>(mask->expand);
else skip(key); else skip(key);
} }
if (!valid) {
delete(mask);
return nullptr;
}
return mask; return mask;
} }
@ -1319,7 +1307,6 @@ void LottieParser::parseTritone(LottieFxTritone* effect)
} }
void LottieParser::parseFill(LottieFxFill* effect) void LottieParser::parseFill(LottieFxFill* effect)
{ {
int idx = 0; //fill mask -> all mask -> color -> invert -> h feather -> v feather -> opacity int idx = 0; //fill mask -> all mask -> color -> invert -> h feather -> v feather -> opacity