From a73e49a6f9fd3247ce63dd40f59974156e573efb Mon Sep 17 00:00:00 2001 From: subhransu mohanty Date: Fri, 24 Aug 2018 11:01:48 +0900 Subject: [PATCH] lottie: refactor processing of trim objects. 1. now each trim item keeps a list of path item it operates on. 2. trim update phase happens after the update phase. so that all path items are correctly updated. 3. Trim objects operate on a intermediate path so that multiple trim objects operating on same path can be possible. Change-Id: I9a6d66aef4449b9399ebc65e29d8633cf41cd25a --- src/lottie/lottieitem.cpp | 130 +++++++++++++++++++++++++++++----------------- src/lottie/lottieitem.h | 36 +++++++++---- src/lottie/lottiemodel.h | 4 ++ 3 files changed, 113 insertions(+), 57 deletions(-) diff --git a/src/lottie/lottieitem.cpp b/src/lottie/lottieitem.cpp index 1104cd5..8d57009 100644 --- a/src/lottie/lottieitem.cpp +++ b/src/lottie/lottieitem.cpp @@ -459,9 +459,12 @@ LOTShapeLayerItem::LOTShapeLayerItem(LOTLayerData *layerData) mRoot->addChildren(layerData); std::vector list; - mRoot->processPathItems(list); + mRoot->processPaintItems(list); - if (layerData->hasPathOperator()) mRoot->processTrimOperation(); + if (layerData->hasPathOperator()) { + list.clear(); + mRoot->processTrimItems(list); + } } std::unique_ptr @@ -522,6 +525,10 @@ LOTShapeLayerItem::createContentItem(LOTData *contentData) void LOTShapeLayerItem::updateContent() { mRoot->update(frameNo(), combinedMatrix(), combinedAlpha(), flag()); + + if (mLayerData->hasPathOperator()) { + mRoot->applyTrim(); + } } void LOTShapeLayerItem::renderList(std::vector &list) @@ -572,6 +579,17 @@ void LOTContentGroupItem::update(int frameNo, const VMatrix &parentMatrix, } } +void LOTContentGroupItem::applyTrim() +{ + for (auto &i : mContents) { + if (auto trim = dynamic_cast(i.get())) { + trim->update(); + } else if (auto group = dynamic_cast(i.get())) { + group->applyTrim(); + } + } +} + void LOTContentGroupItem::renderList(std::vector &list) { for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) { @@ -579,7 +597,7 @@ void LOTContentGroupItem::renderList(std::vector &list) } } -void LOTContentGroupItem::processPathItems( +void LOTContentGroupItem::processPaintItems( std::vector &list) { int curOpCount = list.size(); @@ -593,49 +611,33 @@ void LOTContentGroupItem::processPathItems( } else if (auto groupNode = dynamic_cast(i.get())) { // update the groups node with current list - groupNode->processPathItems(list); + groupNode->processPaintItems(list); } } } -void LOTContentGroupItem::processTrimOperation() -{ - std::vector list; - trimOperationHelper(list); -} - -void LOTContentGroupItem::trimOperationHelper(std::vector &list) +void LOTContentGroupItem::processTrimItems( + std::vector &list) { int curOpCount = list.size(); - for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) { - auto child = (*i).get(); - if (auto pathNode = dynamic_cast(child)) { - // the node is a path data node add the trim operation list to it. - pathNode->addTrimOperation(list); - } else if (auto trimNode = dynamic_cast(child)) { - // add it to the trim operation list - list.push_back(trimNode); + for (auto &i : mContents) { + if (auto pathNode = dynamic_cast(i.get())) { + // add it to the list + list.push_back(pathNode); + } else if (auto trimNode = dynamic_cast(i.get())) { + // the node is a paint data node update the path list of the paint item. + trimNode->addPathItems(list, curOpCount); } else if (auto groupNode = - dynamic_cast(child)) { + dynamic_cast(i.get())) { // update the groups node with current list - groupNode->trimOperationHelper(list); + groupNode->processTrimItems(list); } } - list.erase(list.begin() + curOpCount, list.end()); -} - -void LOTPathDataItem::addTrimOperation(std::vector &list) -{ - for (auto trimItem : list) { - mTrimNodeRefs.push_back(trimItem); - } } void LOTPathDataItem::update(int frameNo, const VMatrix &parentMatrix, float, const DirtyFlag &flag) { - VPath tempPath; - mPathChanged = false; // 1. update the local path if needed @@ -645,29 +647,25 @@ void LOTPathDataItem::update(int frameNo, const VMatrix &parentMatrix, mPathChanged = true; } - tempPath = mLocalPath; - - // 2. apply path operation if needed - if (mTrimNodeRefs.size() > 0) { - // TODO apply more than one trim path if necessary - VPathMesure pm; - float s = mTrimNodeRefs.front()->getStart(frameNo) / 100.0f; - float e = mTrimNodeRefs.front()->getEnd(frameNo) / 100.0f; - - pm.setOffset(s, e); - tempPath = pm.trim(tempPath); - mPathChanged = true; - } + mTemp = mLocalPath; // 3. compute the final path with parentMatrix if ((flag & DirtyFlagBit::Matrix) || mPathChanged) { - mFinalPath.clone(tempPath); - mFinalPath.transform(parentMatrix); + mMatrix = parentMatrix; mPathChanged = true; } } +const VPath & LOTPathDataItem::finalPath() +{ + if (mPathChanged) { + mFinalPath.clone(mTemp); + mFinalPath.transform(mMatrix); + mPathChanged = false; + } + return mFinalPath; +} LOTRectItem::LOTRectItem(LOTRectData *data) : LOTPathDataItem(data->isStatic()), mData(data) { @@ -779,7 +777,7 @@ void LOTPaintDataItem::updateRenderNode() mPath.reset(); for (auto &i : mPathItems) { - mPath.addPath(i->path()); + mPath.addPath(i->finalPath()); } mDrawable->setPath(mPath); } else { @@ -929,11 +927,47 @@ void LOTGStrokeItem::updateRenderNode() LOTTrimItem::LOTTrimItem(LOTTrimData *data) : mData(data) {} -void LOTTrimItem::update(int /*frameNo*/, const VMatrix &/*parentMatrix*/, +void LOTTrimItem::update(int frameNo, const VMatrix &/*parentMatrix*/, float /*parentAlpha*/, const DirtyFlag &/*flag*/) { + mDirty = false; + + if (mCache.mFrameNo == frameNo) return; + + float start = mData->start(frameNo); + float end = mData->end(frameNo); + float offset = mData->offset(frameNo); + + if (!(vCompare(mCache.mStart, start) && vCompare(mCache.mEnd, end) && + vCompare(mCache.mOffset, offset))) { + mDirty = true; + mCache.mStart = start; + mCache.mEnd = end; + mCache.mOffset = offset; + } + mCache.mFrameNo = frameNo; } +void LOTTrimItem::update() +{ + // when both path and trim are not dirty + if (!(mDirty || pathDirty())) return; + + //@TODO take the offset and trim type into account. + for (auto &i : mPathItems) { + VPathMesure pm; + pm.setOffset(mCache.mStart, mCache.mEnd); + i->updatePath(pm.trim(i->localPath())); + } +} + + +void LOTTrimItem::addPathItems(std::vector &list, int startOffset) +{ + std::copy(list.begin() + startOffset, list.end(), back_inserter(mPathItems)); +} + + LOTRepeaterItem::LOTRepeaterItem(LOTRepeaterData *data) : mData(data) {} void LOTRepeaterItem::update(int /*frameNo*/, const VMatrix &/*parentMatrix*/, diff --git a/src/lottie/lottieitem.h b/src/lottie/lottieitem.h index c20dbdc..1ef0ee3 100644 --- a/src/lottie/lottieitem.h +++ b/src/lottie/lottieitem.h @@ -181,11 +181,11 @@ public: LOTContentGroupItem(LOTShapeGroupData *data); void addChildren(LOTGroupData *data); void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag) final; - void processTrimOperation(); - void processPathItems(std::vector &list); + void applyTrim(); + void processTrimItems(std::vector &list); + void processPaintItems(std::vector &list); void renderList(std::vector &list) final; private: - void trimOperationHelper(std::vector &list); LOTShapeGroupData *mData; std::vector> mContents; }; @@ -195,15 +195,17 @@ class LOTPathDataItem : public LOTContentItem public: LOTPathDataItem(bool staticPath):mInit(false), mStaticPath(staticPath){} void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag) final; - void addTrimOperation(std::vector &list); bool dirty() const {return mPathChanged;} - const VPath &path()const {return mFinalPath;} + const VPath &localPath() const {return mTemp;} + const VPath &finalPath(); + void updatePath(const VPath &path) {mTemp.clone(path); mPathChanged = true;} private: - std::vector mTrimNodeRefs; bool mInit; bool mStaticPath; VPath mLocalPath; + VPath mTemp; VPath mFinalPath; + VMatrix mMatrix; bool mPathChanged{true}; protected: virtual void updatePath(VPath& path, int frameNo) = 0; @@ -440,10 +442,26 @@ class LOTTrimItem : public LOTContentItem public: LOTTrimItem(LOTTrimData *data); void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag) final; - float getStart(int frameNo) {return mData->mStart.value(frameNo);} - float getEnd(int frameNo) {return mData->mEnd.value(frameNo);} + void update(); + void addPathItems(std::vector &list, int startOffset); private: - LOTTrimData *mData; + bool pathDirty() const { + for (auto &i : mPathItems) { + if (i->dirty()) + return true; + } + return false; + } + struct Cache { + int mFrameNo{-1}; + float mStart{0}; + float mEnd{0}; + float mOffset{0}; + }; + Cache mCache; + std::vector mPathItems; + LOTTrimData *mData; + bool mDirty{true}; }; class LOTRepeaterItem : public LOTContentItem diff --git a/src/lottie/lottiemodel.h b/src/lottie/lottiemodel.h index bc1d373..165a502 100644 --- a/src/lottie/lottiemodel.h +++ b/src/lottie/lottiemodel.h @@ -654,6 +654,10 @@ public: LOTTrimData():LOTData(LOTData::Type::Trim){} void accept(LOTDataVisitor *visitor) final {visitor->visit(this);} + float start(int frameNo) const {return mStart.value(frameNo)/100.0f;} + float end(int frameNo) const {return mEnd.value(frameNo)/100.0f;} + float offset(int frameNo) const {return mOffset.value(frameNo)/100.0f;} + LOTTrimData::TrimType type() const {return mTrimType;} public: LOTAnimatable mStart{0}; LOTAnimatable mEnd{0}; -- 2.7.4