diff --git a/src/loaders/lottie/tvgLottieBuilder.cpp b/src/loaders/lottie/tvgLottieBuilder.cpp index 52b9c4b4..7e8ba3e3 100644 --- a/src/loaders/lottie/tvgLottieBuilder.cpp +++ b/src/loaders/lottie/tvgLottieBuilder.cpp @@ -1191,6 +1191,24 @@ bool LottieBuilder::updateMatte(LottieComposition* comp, float frameNo, Scene* s } +void LottieBuilder::updateEffect(LottieLayer* layer, float frameNo) +{ + if (layer->effects.count == 0) return; + + for (auto ef = layer->effects.begin(); ef < layer->effects.end(); ++ef) { + if (!(*ef)->enable) continue; + switch ((*ef)->type) { + case LottieEffect::GaussianBlur: { + auto effect = static_cast(*ef); + layer->scene->push(SceneEffect::GaussianBlur, sqrt(effect->blurness(frameNo)), effect->direction(frameNo) - 1, effect->wrap(frameNo), 50); + break; + } + default: break; + } + } +} + + void LottieBuilder::updateLayer(LottieComposition* comp, Scene* scene, LottieLayer* layer, float frameNo) { layer->scene = nullptr; @@ -1246,6 +1264,8 @@ void LottieBuilder::updateLayer(LottieComposition* comp, Scene* scene, LottieLay layer->scene->blend(layer->blendMethod); + updateEffect(layer, frameNo); + //the given matte source was composited by the target earlier. if (!layer->matteSrc) scene->push(cast(layer->scene)); } diff --git a/src/loaders/lottie/tvgLottieBuilder.h b/src/loaders/lottie/tvgLottieBuilder.h index d38ae402..cb628e86 100644 --- a/src/loaders/lottie/tvgLottieBuilder.h +++ b/src/loaders/lottie/tvgLottieBuilder.h @@ -103,6 +103,7 @@ struct LottieBuilder void build(LottieComposition* comp); private: + void updateEffect(LottieLayer* layer, float frameNo); void updateLayer(LottieComposition* comp, Scene* scene, LottieLayer* layer, float frameNo); bool updateMatte(LottieComposition* comp, float frameNo, Scene* scene, LottieLayer* layer); void updatePrecomp(LottieComposition* comp, LottieLayer* precomp, float frameNo); diff --git a/src/loaders/lottie/tvgLottieModel.cpp b/src/loaders/lottie/tvgLottieModel.cpp index f3268ff2..2b2793ea 100644 --- a/src/loaders/lottie/tvgLottieModel.cpp +++ b/src/loaders/lottie/tvgLottieModel.cpp @@ -400,6 +400,10 @@ LottieLayer::~LottieLayer() delete(*m); } + for (auto e = effects.begin(); e < effects.end(); ++e) { + delete(*e); + } + delete(transform); free(name); } diff --git a/src/loaders/lottie/tvgLottieModel.h b/src/loaders/lottie/tvgLottieModel.h index b23dcd0f..ab353034 100644 --- a/src/loaders/lottie/tvgLottieModel.h +++ b/src/loaders/lottie/tvgLottieModel.h @@ -77,6 +77,33 @@ struct LottieStroke }; +struct LottieEffect +{ + enum Type : uint8_t + { + GaussianBlur = 0, + }; + + virtual ~LottieEffect() {} + + Type type; + bool enable = false; +}; + + +struct LottieGaussianBlur : LottieEffect +{ + LottieSlider blurness = 0.0f; + LottieCheckbox direction = 0; + LottieCheckbox wrap = 0; + + LottieGaussianBlur() + { + type = GaussianBlur; + } +}; + + struct LottieMask { LottiePathSet pathset; @@ -737,6 +764,7 @@ struct LottieLayer : LottieGroup LottieLayer* comp = nullptr; //Precompositor, current layer is belonges. LottieTransform* transform = nullptr; Array masks; + Array effects; LottieLayer* matteTarget = nullptr; LottieRenderPooler statical; //static pooler for solid fill and clipper diff --git a/src/loaders/lottie/tvgLottieParser.cpp b/src/loaders/lottie/tvgLottieParser.cpp index 9653c1a4..468934f8 100644 --- a/src/loaders/lottie/tvgLottieParser.cpp +++ b/src/loaders/lottie/tvgLottieParser.cpp @@ -57,6 +57,15 @@ static unsigned long _int2str(int num) } +LottieEffect* LottieParser::getEffect(int type) +{ + switch (type) { + case 29: return new LottieGaussianBlur; + default: return nullptr; + } +} + + CompositeMethod LottieParser::getMaskMethod(bool inversed) { auto mode = getString(); @@ -263,6 +272,19 @@ void LottieParser::getValue(Array& pts) } +void LottieParser::getValue(int8_t& val) +{ + if (peekType() == kArrayType) { + enterArray(); + if (nextArrayValue()) val = getInt(); + //discard rest + while (nextArrayValue()) getInt(); + } else { + val = getFloat(); + } +} + + void LottieParser::getValue(uint8_t& val) { if (peekType() == kArrayType) { @@ -1233,6 +1255,70 @@ void LottieParser::parseMasks(LottieLayer* layer) } +void LottieParser::parseGaussianBlur(LottieGaussianBlur* effect) +{ + int idx = 0; //blurness -> direction -> wrap + 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->blurness); + else if (idx == 1) parsePropertyInternal(effect->direction); + else if (idx == 2) parsePropertyInternal(effect->wrap); + ++idx; + } else skip(key); + } + } else skip(key); + } + } +} + + +void LottieParser::parseEffect(LottieEffect* effect) +{ + switch (effect->type) { + case LottieEffect::GaussianBlur: { + parseGaussianBlur(static_cast(effect)); + break; + } + default: break; + } +} + + +void LottieParser::parseEffects(LottieLayer* layer) +{ + auto invalid = true; + + enterArray(); + while (nextArrayValue()) { + LottieEffect* effect = nullptr; + enterObject(); + while (auto key = nextObjectKey()) { + //type must be priortized. + if (KEY_AS("ty")) + { + effect = getEffect(getInt()); + if (!effect) break; + else invalid = false; + } + else if (effect && KEY_AS("en")) effect->enable = getInt(); + else if (effect && KEY_AS("ef")) parseEffect(effect); + else skip(key); + } + //TODO: remove when all effects were guaranteed. + if (invalid) { + TVGLOG("LOTTIE", "Not supported Layer Effect = %d", (int)effect->type); + while (auto key = nextObjectKey()) skip(key); + } else layer->effects.push(effect); + } +} + + LottieLayer* LottieParser::parseLayer(LottieLayer* precomp) { auto layer = new LottieLayer; @@ -1278,11 +1364,7 @@ LottieLayer* LottieParser::parseLayer(LottieLayer* precomp) else if (KEY_AS("refId")) layer->rid = djb2Encode(getString()); else if (KEY_AS("td")) layer->matteSrc = getInt(); //used for matte layer else if (KEY_AS("t")) parseText(layer->children); - else if (KEY_AS("ef")) - { - TVGLOG("LOTTIE", "layer effect(ef) is not supported!"); - skip(key); - } + else if (KEY_AS("ef")) parseEffects(layer); else skip(key); } diff --git a/src/loaders/lottie/tvgLottieParser.h b/src/loaders/lottie/tvgLottieParser.h index 861a3920..0a3996ef 100644 --- a/src/loaders/lottie/tvgLottieParser.h +++ b/src/loaders/lottie/tvgLottieParser.h @@ -50,6 +50,7 @@ private: StrokeJoin getStrokeJoin(); CompositeMethod getMaskMethod(bool inversed); LottieInterpolator* getInterpolator(const char* key, Point& in, Point& out); + LottieEffect* getEffect(int type); void getInterpolatorPoint(Point& pt); void getPathSet(LottiePathSet& path); @@ -60,6 +61,7 @@ private: void getValue(ColorStop& color); void getValue(float& val); void getValue(uint8_t& val); + void getValue(int8_t& val); void getValue(RGB24& color); bool getValue(Point& pt); @@ -93,12 +95,15 @@ private: LottieFont* parseFont(); LottieMarker* parseMarker(); + void parseGaussianBlur(LottieGaussianBlur* effect); + bool parseDirection(LottieShape* shape, const char* key); bool parseCommon(LottieObject* obj, const char* key); void parseObject(Array& parent); void parseShapes(Array& parent); void parseText(Array& parent); void parseMasks(LottieLayer* layer); + void parseEffects(LottieLayer* layer); void parseTimeRemap(LottieLayer* layer); void parseStrokeDash(LottieStroke* stroke); void parseGradient(LottieGradient* gradient, const char* key); @@ -107,6 +112,7 @@ private: void parseFonts(); void parseChars(Array& glyphs); void parseMarkers(); + void parseEffect(LottieEffect* effect); void postProcess(Array& glyphs); //Current parsing context diff --git a/src/loaders/lottie/tvgLottieProperty.h b/src/loaders/lottie/tvgLottieProperty.h index 44244180..91a879ac 100644 --- a/src/loaders/lottie/tvgLottieProperty.h +++ b/src/loaders/lottie/tvgLottieProperty.h @@ -832,5 +832,7 @@ using LottiePoint = LottieGenericProperty; using LottieFloat = LottieGenericProperty; using LottieOpacity = LottieGenericProperty; using LottieColor = LottieGenericProperty; +using LottieSlider = LottieFloat; +using LottieCheckbox = LottieGenericProperty; #endif //_TVG_LOTTIE_PROPERTY_H_