lottie: support stroke layer effect

issue: https://github.com/thorvg/thorvg/issues/2718
This commit is contained in:
Hermet Park 2024-12-18 12:24:28 +09:00 committed by Hermet Park
parent 713840eb42
commit b041bdab4a
6 changed files with 138 additions and 27 deletions

View file

@ -1220,7 +1220,7 @@ void LottieBuilder::updateText(LottieLayer* layer, float frameNo)
} }
void LottieBuilder::updateMaskings(LottieLayer* layer, float frameNo) void LottieBuilder::updateMasks(LottieLayer* layer, float frameNo)
{ {
if (layer->masks.count == 0) return; if (layer->masks.count == 0) return;
@ -1306,6 +1306,60 @@ bool LottieBuilder::updateMatte(LottieComposition* comp, float frameNo, Scene* s
} }
void LottieBuilder::updateStrokeEffect(LottieLayer* layer, LottieFxStroke* effect, float frameNo)
{
if (layer->masks.count == 0) return;
auto shape = layer->pooling();
shape->reset();
//FIXME: all mask
if (effect->allMask(frameNo)) {
for (auto m = layer->masks.begin(); m < layer->masks.end(); ++m) {
auto mask = *m;
mask->pathset(frameNo, SHAPE(shape)->rs.path.cmds, SHAPE(shape)->rs.path.pts, nullptr, nullptr, nullptr, exps);
}
//A specific mask
} else {
auto idx = static_cast<uint32_t>(effect->mask(frameNo) - 1);
if (idx < 0 || idx >= layer->masks.count) return;
auto mask = layer->masks[idx];
mask->pathset(frameNo, SHAPE(shape)->rs.path.cmds, SHAPE(shape)->rs.path.pts, nullptr, nullptr, nullptr, exps);
}
shape->transform(layer->cache.matrix);
shape->strokeTrim(effect->begin(frameNo) * 0.01f, effect->end(frameNo) * 0.01f);
shape->strokeFill(255, 255, 255, (int)(effect->opacity(frameNo) * 255.0f));
shape->strokeJoin(StrokeJoin::Round);
shape->strokeCap(StrokeCap::Round);
auto size = effect->size(frameNo) * 2.0f;
shape->strokeWidth(size);
//fill the color to the layer shapes if any
auto color = effect->color(frameNo);
if (color.rgb[0] != 255 || color.rgb[1] != 255 || color.rgb[2] != 255) {
auto accessor = tvg::Accessor::gen();
auto stroke = (layer->type == LottieLayer::Type::Shape) ? true : false;
auto f = [color, size, stroke](const tvg::Paint* paint, void* data) -> bool {
if (paint->type() == tvg::Type::Shape) {
auto shape = (tvg::Shape*) paint;
//expand shape to fill the stroke region
if (stroke) {
shape->strokeWidth(size);
shape->strokeFill(color.rgb[0], color.rgb[1], color.rgb[2], 255);
}
shape->fill(color.rgb[0], color.rgb[1], color.rgb[2], 255);
}
return true;
};
accessor->set(layer->scene, f, nullptr);
}
layer->scene->mask(shape, MaskMethod::Alpha);
}
void LottieBuilder::updateEffect(LottieLayer* layer, float frameNo) void LottieBuilder::updateEffect(LottieLayer* layer, float frameNo)
{ {
constexpr int QUALITY = 25; constexpr int QUALITY = 25;
@ -1329,6 +1383,11 @@ void LottieBuilder::updateEffect(LottieLayer* layer, float frameNo)
layer->scene->push(SceneEffect::Fill, color.rgb[0], color.rgb[1], color.rgb[2], (int)(255.0f * effect->opacity(frameNo))); layer->scene->push(SceneEffect::Fill, color.rgb[0], color.rgb[1], color.rgb[2], (int)(255.0f * effect->opacity(frameNo)));
break; break;
} }
case LottieEffect::Stroke: {
auto effect = static_cast<LottieFxStroke*>(*ef);
updateStrokeEffect(layer, effect, frameNo);
break;
}
case LottieEffect::Tritone: { case LottieEffect::Tritone: {
auto effect = static_cast<LottieFxTritone*>(*ef); auto effect = static_cast<LottieFxTritone*>(*ef);
auto dark = effect->dark(frameNo); auto dark = effect->dark(frameNo);
@ -1406,7 +1465,7 @@ void LottieBuilder::updateLayer(LottieComposition* comp, Scene* scene, LottieLay
} }
} }
updateMaskings(layer, frameNo); updateMasks(layer, frameNo);
layer->scene->blend(layer->blendMethod); layer->scene->blend(layer->blendMethod);

View file

@ -102,6 +102,7 @@ struct LottieBuilder
void build(LottieComposition* comp); void build(LottieComposition* comp);
private: private:
void updateStrokeEffect(LottieLayer* layer, LottieFxStroke* effect, float frameNo);
void updateEffect(LottieLayer* layer, float frameNo); void updateEffect(LottieLayer* layer, float frameNo);
void updateLayer(LottieComposition* comp, Scene* scene, LottieLayer* layer, float frameNo); void updateLayer(LottieComposition* comp, Scene* scene, LottieLayer* layer, float frameNo);
bool updateMatte(LottieComposition* comp, float frameNo, Scene* scene, LottieLayer* layer); bool updateMatte(LottieComposition* comp, float frameNo, Scene* scene, LottieLayer* layer);
@ -109,7 +110,7 @@ private:
void updateSolid(LottieLayer* layer); void updateSolid(LottieLayer* layer);
void updateImage(LottieGroup* layer); void updateImage(LottieGroup* layer);
void updateText(LottieLayer* layer, float frameNo); void updateText(LottieLayer* layer, float frameNo);
void updateMaskings(LottieLayer* layer, float frameNo); void updateMasks(LottieLayer* layer, float frameNo);
void updateTransform(LottieLayer* layer, float frameNo); void updateTransform(LottieLayer* layer, float frameNo);
void updateChildren(LottieGroup* parent, float frameNo, Inlist<RenderContext>& contexts); void updateChildren(LottieGroup* parent, float frameNo, Inlist<RenderContext>& contexts);
void updateGroup(LottieGroup* parent, LottieObject** child, float frameNo, Inlist<RenderContext>& pcontexts, RenderContext* ctx); void updateGroup(LottieGroup* parent, LottieObject** child, float frameNo, Inlist<RenderContext>& pcontexts, RenderContext* ctx);

View file

@ -76,10 +76,9 @@ struct LottieStroke
StrokeJoin join = StrokeJoin::Round; StrokeJoin join = StrokeJoin::Round;
}; };
struct LottieEffect struct LottieEffect
{ {
enum Type : uint8_t {Tint = 20, Fill, Tritone = 23, DropShadow = 25, GaussianBlur = 29}; enum Type : uint8_t {Tint = 20, Fill, Stroke, Tritone, DropShadow = 25, GaussianBlur = 29};
virtual ~LottieEffect() {} virtual ~LottieEffect() {}
Type type; Type type;
@ -88,13 +87,13 @@ struct LottieEffect
struct LottieFxFill : LottieEffect struct LottieFxFill : LottieEffect
{ {
//int16_t mask layer //LottieInteger mask;
//LottieDropDown allMask? //LottieInteger allMask;
LottieColor color; LottieColor color;
//LottieDropDown inverted //LottieInteger invert;
//LottieSlider horizontalFeather //LottieSlider hFeather;
//LottieSlider verticalFeather //LottieSlider vFeather;
LottieSlider opacity; LottieFloat opacity;
LottieFxFill() LottieFxFill()
{ {
@ -102,11 +101,31 @@ struct LottieFxFill : LottieEffect
} }
}; };
struct LottieFxStroke : LottieEffect
{
LottieInteger mask;
LottieInteger allMask;
//LottieInteger sequential;
LottieColor color;
LottieFloat size;
//LottieFloat hardness; //should support with the blurness?
LottieFloat opacity;
LottieFloat begin;
LottieFloat end;
//LottieFloat space;
//LottieInteger style;
LottieFxStroke()
{
type = LottieEffect::Stroke;
}
};
struct LottieFxTint : LottieEffect struct LottieFxTint : LottieEffect
{ {
LottieColor black; LottieColor black;
LottieColor white; LottieColor white;
LottieSlider intensity; LottieFloat intensity;
LottieFxTint() LottieFxTint()
{ {
@ -129,10 +148,10 @@ struct LottieFxTritone : LottieEffect
struct LottieFxDropShadow : LottieEffect struct LottieFxDropShadow : LottieEffect
{ {
LottieColor color; LottieColor color;
LottieSlider opacity = 0; LottieFloat opacity = 0;
LottieAngle angle = 0.0f; LottieFloat angle = 0.0f;
LottieSlider distance = 0.0f; LottieFloat distance = 0.0f;
LottieSlider blurness = 0.0f; LottieFloat blurness = 0.0f;
LottieFxDropShadow() LottieFxDropShadow()
{ {
@ -142,9 +161,9 @@ struct LottieFxDropShadow : LottieEffect
struct LottieFxGaussianBlur : LottieEffect struct LottieFxGaussianBlur : LottieEffect
{ {
LottieSlider blurness = 0.0f; LottieFloat blurness = 0.0f;
LottieCheckbox direction = 0; LottieInteger direction = 0;
LottieCheckbox wrap = 0; LottieInteger wrap = 0;
LottieFxGaussianBlur() LottieFxGaussianBlur()
{ {

View file

@ -62,6 +62,7 @@ LottieEffect* LottieParser::getEffect(int type)
switch (type) { switch (type) {
case LottieEffect::Tint: return new LottieFxTint; case LottieEffect::Tint: return new LottieFxTint;
case LottieEffect::Fill: return new LottieFxFill; case LottieEffect::Fill: return new LottieFxFill;
case LottieEffect::Stroke: return new LottieFxStroke;
case LottieEffect::Tritone: return new LottieFxTritone; case LottieEffect::Tritone: return new LottieFxTritone;
case LottieEffect::DropShadow: return new LottieFxDropShadow; case LottieEffect::DropShadow: return new LottieFxDropShadow;
case LottieEffect::GaussianBlur: return new LottieFxGaussianBlur; case LottieEffect::GaussianBlur: return new LottieFxGaussianBlur;
@ -1261,7 +1262,7 @@ void LottieParser::parseMasks(LottieLayer* layer)
void LottieParser::parseTint(LottieFxTint* effect) void LottieParser::parseTint(LottieFxTint* effect)
{ {
int idx = 0; //black -> white -> intenstiy int idx = 0;
enterArray(); enterArray();
while (nextArrayValue()) { while (nextArrayValue()) {
enterObject(); enterObject();
@ -1285,7 +1286,7 @@ void LottieParser::parseTint(LottieFxTint* effect)
void LottieParser::parseTritone(LottieFxTritone* effect) void LottieParser::parseTritone(LottieFxTritone* effect)
{ {
int idx = 0; //bright, midtone, dark int idx = 0;
enterArray(); enterArray();
while (nextArrayValue()) { while (nextArrayValue()) {
enterObject(); enterObject();
@ -1310,7 +1311,7 @@ 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;
enterArray(); enterArray();
while (nextArrayValue()) { while (nextArrayValue()) {
enterObject(); enterObject();
@ -1333,7 +1334,7 @@ void LottieParser::parseFill(LottieFxFill* effect)
void LottieParser::parseGaussianBlur(LottieFxGaussianBlur* effect) void LottieParser::parseGaussianBlur(LottieFxGaussianBlur* effect)
{ {
int idx = 0; //blurness -> direction -> wrap int idx = 0;
enterArray(); enterArray();
while (nextArrayValue()) { while (nextArrayValue()) {
enterObject(); enterObject();
@ -1357,7 +1358,7 @@ void LottieParser::parseGaussianBlur(LottieFxGaussianBlur* effect)
void LottieParser::parseDropShadow(LottieFxDropShadow* effect) void LottieParser::parseDropShadow(LottieFxDropShadow* effect)
{ {
int idx = 0; //color -> opacity -> angle -> distance -> blur int idx = 0;
enterArray(); enterArray();
while (nextArrayValue()) { while (nextArrayValue()) {
enterObject(); enterObject();
@ -1381,6 +1382,34 @@ void LottieParser::parseDropShadow(LottieFxDropShadow* effect)
} }
void LottieParser::parseStroke(LottieFxStroke* effect)
{
int idx = 0;
enterArray();
while (nextArrayValue()) {
enterObject();
while (auto key = nextObjectKey()) {
if (KEY_AS("v")) {
enterObject();
while (auto key = nextObjectKey()) {
if (KEY_AS("k")) {
if (idx == 0) parsePropertyInternal(effect->mask);
else if (idx == 1) parsePropertyInternal(effect->allMask);
else if (idx == 3) parsePropertyInternal(effect->color);
else if (idx == 4) parsePropertyInternal(effect->size);
else if (idx == 6) parsePropertyInternal(effect->opacity);
else if (idx == 7) parsePropertyInternal(effect->begin);
else if (idx == 8) parsePropertyInternal(effect->end);
else skip();
++idx;
} else skip();
}
} else skip();
}
}
}
void LottieParser::parseEffect(LottieEffect* effect) void LottieParser::parseEffect(LottieEffect* effect)
{ {
switch (effect->type) { switch (effect->type) {
@ -1392,6 +1421,10 @@ void LottieParser::parseEffect(LottieEffect* effect)
parseFill(static_cast<LottieFxFill*>(effect)); parseFill(static_cast<LottieFxFill*>(effect));
break; break;
} }
case LottieEffect::Stroke: {
parseStroke(static_cast<LottieFxStroke*>(effect));
break;
}
case LottieEffect::Tritone: { case LottieEffect::Tritone: {
parseTritone(static_cast<LottieFxTritone*>(effect)); parseTritone(static_cast<LottieFxTritone*>(effect));
break; break;

View file

@ -98,6 +98,7 @@ private:
LottieFont* parseFont(); LottieFont* parseFont();
LottieMarker* parseMarker(); LottieMarker* parseMarker();
void parseStroke(LottieFxStroke* effect);
void parseTritone(LottieFxTritone* effect); void parseTritone(LottieFxTritone* effect);
void parseTint(LottieFxTint* effect); void parseTint(LottieFxTint* effect);
void parseFill(LottieFxFill* effect); void parseFill(LottieFxFill* effect);

View file

@ -920,8 +920,6 @@ using LottiePoint = LottieGenericProperty<Point>;
using LottieFloat = LottieGenericProperty<float>; using LottieFloat = LottieGenericProperty<float>;
using LottieOpacity = LottieGenericProperty<uint8_t>; using LottieOpacity = LottieGenericProperty<uint8_t>;
using LottieColor = LottieGenericProperty<RGB24>; using LottieColor = LottieGenericProperty<RGB24>;
using LottieSlider = LottieFloat; using LottieInteger = LottieGenericProperty<int8_t>;
using LottieAngle = LottieFloat;
using LottieCheckbox = LottieGenericProperty<int8_t>;
#endif //_TVG_LOTTIE_PROPERTY_H_ #endif //_TVG_LOTTIE_PROPERTY_H_