lottie/feature: Added support for handing lottie repeater objects. 92/188992/3
authorsubhransu mohanty <sub.mohanty@samsung.com>
Wed, 12 Sep 2018 08:16:05 +0000 (17:16 +0900)
committersubhransu mohanty <sub.mohanty@samsung.com>
Fri, 7 Dec 2018 02:55:42 +0000 (11:55 +0900)
Change-Id: If65b81aab08baeecd3c16ff70a38587429bd8c61

src/lottie/lottieitem.cpp
src/lottie/lottieitem.h
src/lottie/lottiemodel.cpp
src/lottie/lottiemodel.h
src/lottie/lottieparser.cpp

index 766a1745e15ea64eb5e60d1d454eb9b8e0fd25b6..8170c1654c7c3440f2cec89bd7555cbc6b3fc015 100644 (file)
@@ -563,7 +563,7 @@ LOTShapeLayerItem::createContentItem(LOTData *contentData)
     switch (contentData->type()) {
     case LOTData::Type::ShapeGroup: {
         return std::make_unique<LOTContentGroupItem>(
-            static_cast<LOTShapeGroupData *>(contentData));
+            static_cast<LOTGroupData *>(contentData));
         break;
     }
     case LOTData::Type::Rect: {
@@ -644,7 +644,7 @@ void LOTShapeLayerItem::renderList(std::vector<VDrawable *> &list)
     mRoot->renderList(list);
 }
 
-LOTContentGroupItem::LOTContentGroupItem(LOTShapeGroupData *data) : mData(data)
+LOTContentGroupItem::LOTContentGroupItem(LOTGroupData *data) : mData(data)
 {
     addChildren(mData);
 }
@@ -672,7 +672,7 @@ void LOTContentGroupItem::update(int frameNo, const VMatrix &parentMatrix,
     float     alpha = parentAlpha;
     DirtyFlag newFlag = flag;
 
-    if (mData) {
+    if (mData && mData->mTransform) {
         // update the matrix and the flag
         if ((flag & DirtyFlagBit::Matrix) ||
             !mData->mTransform->staticMatrix()) {
@@ -1139,14 +1139,44 @@ void LOTTrimItem::addPathItems(std::vector<LOTPathDataItem *> &list, int startOf
 }
 
 
-LOTRepeaterItem::LOTRepeaterItem(LOTRepeaterData *data) : mData(data) {}
-
-void LOTRepeaterItem::update(int /*frameNo*/, const VMatrix &/*parentMatrix*/,
-                             float /*parentAlpha*/, const DirtyFlag &/*flag*/)
+LOTRepeaterItem::LOTRepeaterItem(LOTRepeaterData *data) : mData(data)
 {
+    assert(mData->mChildren.size() == 1);
+    LOTGroupData *root = reinterpret_cast<LOTGroupData *>(mData->mChildren[0].get());
+    assert(root);
+
+    for (int i= 0; i < mData->copies(0); i++) {
+        auto content = std::make_unique<LOTContentGroupItem>(static_cast<LOTGroupData *>(root));
+        content->setParent(this);
+        mContents.push_back(std::move(content));
+    }
 }
 
-void LOTRepeaterItem::renderList(std::vector<VDrawable *> &/*list*/) {}
+void LOTRepeaterItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
+{
+
+    DirtyFlag newFlag = flag;
+
+    if (mData->hasMtrixChange(frameNo)) {
+        newFlag |= DirtyFlagBit::Matrix;
+    }
+
+    float multiplier = mData->offset(frameNo);
+    float startOpacity = mData->mTransform->startOpacity(frameNo);
+    float endOpacity = mData->mTransform->endOpacity(frameNo);
+    float index = 0;
+    float copies = mData->copies(frameNo);
+    if (!vCompare(copies, 1)) copies -=1;
+
+    newFlag |= DirtyFlagBit::Alpha;
+    for (const auto &content : mContents) {
+        float newAlpha = parentAlpha * lerp(startOpacity, endOpacity, index / copies);
+        VMatrix result = mData->mTransform->matrixForRepeater(frameNo, multiplier) * parentMatrix;
+        content->update(frameNo, result, newAlpha, newFlag);
+        multiplier += 1;
+        index +=1;
+    }
+}
 
 static void updateGStops(LOTNode *n, const VGradient *grad)
 {
index d87f37a3a460c25300ad82de9e3bd8b31077b784..025146029b2e28426795d9c80546b76fa4efd3dc 100644 (file)
@@ -197,16 +197,17 @@ private:
 class LOTContentGroupItem: public LOTContentItem
 {
 public:
-   LOTContentGroupItem(LOTShapeGroupData *data);
+    LOTContentGroupItem(){}
+   LOTContentGroupItem(LOTGroupData *data);
    void addChildren(LOTGroupData *data);
-   void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag) final;
+   void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag);
    void applyTrim();
    void processTrimItems(std::vector<LOTPathDataItem *> &list);
    void processPaintItems(std::vector<LOTPathDataItem *> &list);
    void renderList(std::vector<VDrawable *> &list) final;
    const VMatrix & matrix() const { return mMatrix;}
-private:
-   LOTShapeGroupData                             *mData;
+protected:
+   LOTGroupData                                  *mData{nullptr};
    std::vector<std::unique_ptr<LOTContentItem>>   mContents;
    VMatrix                                        mMatrix;
 };
@@ -416,12 +417,11 @@ private:
    bool                             mDirty{true};
 };
 
-class LOTRepeaterItem : public LOTContentItem
+class LOTRepeaterItem : public LOTContentGroupItem
 {
 public:
    LOTRepeaterItem(LOTRepeaterData *data);
    void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag) final;
-   void renderList(std::vector<VDrawable *> &list) final;
 private:
    LOTRepeaterData             *mData;
 };
index c9b6b62b9c41bef8cb22ac7e11e306b035ba4ecd..63b924edd32af5b138637aec14f2b0994033a29e 100644 (file)
@@ -3,26 +3,46 @@
 #include <cassert>
 #include <stack>
 
+/*
+ * We process the iterator objects in the children list
+ * by iterating from back to front. when we find a repeater object
+ * we remove the objects from satrt till repeater object and then place
+ * under a new shape group object which we add it as children to the repeater
+ * object.
+ * Then we visit the childrens of the newly created shape group object to
+ * process the remaining repeater object(when children list contains more than one
+ * repeater).
+ *
+ */
 class LottieRepeaterProcesser {
 public:
-    void visitChildren(LOTGroupData *obj)
-    {
-        for (const auto& child : obj->mChildren) {
-            if (child->mType == LOTData::Type::Repeater) {
-                LOTRepeaterData *repeater =
-                    static_cast<LOTRepeaterData *>(child.get());
-                std::shared_ptr<LOTShapeGroupData> sharedShapeGroup =
-                    std::make_shared<LOTShapeGroupData>();
+    void visitChildren(LOTGroupData *obj) {
+        for (auto i = obj->mChildren.rbegin(); i != obj->mChildren.rend(); ++i ) {
+            auto child = (*i).get();
+            if (child->type() == LOTData::Type::Repeater) {
+                LOTRepeaterData *repeater = static_cast<LOTRepeaterData *>(child);
+                auto sharedShapeGroup = std::make_shared<LOTShapeGroupData>();
                 LOTShapeGroupData *shapeGroup = sharedShapeGroup.get();
+                // 1. increment the reverse iterator to point to the
+                //   object before the repeater
+                ++i;
+                // 2. move all the children till repater to the group
+                std::move(obj->mChildren.begin(),
+                          i.base(), back_inserter(shapeGroup->mChildren));
+                // 3. erase the objects from the original children list
+                obj->mChildren.erase(obj->mChildren.begin(),
+                                     i.base());
+                // 4. Add the newly created group to the repeater object.
                 repeater->mChildren.push_back(sharedShapeGroup);
-                // copy all the child of the object till repeater and
-                // move that in to a group and then add that group to
-                // the repeater object.
-                for (const auto& cpChild : obj->mChildren) {
-                    if (cpChild == child) break;
-                    shapeGroup->mChildren.push_back(cpChild);
-                }
+
+                // 5. visit newly created group to process remaining repeater object.
+                visitChildren(shapeGroup);
+                // 6. exit the loop as the current iterators are invalid
+                break;
+            } else {
+                visit(child);
             }
+
         }
     }
 
@@ -47,6 +67,20 @@ void LOTCompositionData::processRepeaterObjects()
     visitor.visit(mRootLayer.get());
 }
 
+VMatrix LOTTransformData::matrixForRepeater(int frameNo, float multiplier) const
+{
+    VPointF scale = mScale.value(frameNo) / 100.f;
+    scale.setX(std::pow(scale.x(), multiplier));
+    scale.setY(std::pow(scale.y(), multiplier));
+    VMatrix m;
+    m.translate(mPosition.value(frameNo) * multiplier)
+     .rotate(mRotation.value(frameNo) * multiplier)
+     .scale(scale)
+     .translate(mAnchor.value(frameNo));
+    return m;
+}
+
+
 VMatrix LOTTransformData::matrix(int frameNo, bool autoOrient) const
 {
     if (mStaticMatrix)
index 8ceb1c5dd5ddc5ba7bd3cb7b978f6c78ad783eee..a939979f68477386fab940807dc169db2f962b63 100644 (file)
@@ -444,6 +444,7 @@ class LOTTransformData : public LOTData
 public:
     LOTTransformData():LOTData(LOTData::Type::Transform),mScale({100, 100}){}
     VMatrix matrix(int frameNo, bool autoOrient = false) const;
+    VMatrix matrixForRepeater(int frameNo, float multiplier) const;
     float opacity(int frameNo) const { return mOpacity.value(frameNo)/100;}
     float startOpacity(int frameNo) const { return mStartOpacity.value(frameNo)/100;}
     float endOpacity(int frameNo) const { return mEndOpacity.value(frameNo)/100;}
@@ -745,6 +746,11 @@ class LOTRepeaterData : public LOTGroupData
 {
 public:
     LOTRepeaterData():LOTGroupData(LOTData::Type::Repeater){}
+    bool hasMtrixChange(int /*frameNo*/) const {
+        return !(mTransform->isStatic() && mOffset.isStatic());
+    }
+    float copies(int frameNo) const {return mCopies.value(frameNo);}
+    float offset(int frameNo) const {return mOffset.value(frameNo);}
 public:
     LOTAnimatable<float>             mCopies{0};
     LOTAnimatable<float>             mOffset{0};
index b63d1e9e07125cde6ccb6a61c1d501eaaf7af776..91e9f3996d7ff71f0f101f8da872e5ff7fe6e5d6 100644 (file)
@@ -1966,7 +1966,10 @@ public:
     void visit(LOTData *obj, std::string level) {
         switch (obj->mType) {
         case LOTData::Type::Repeater: {
-            vDebug << level << "{ Repeater:";
+            auto r = static_cast<LOTRepeaterData *>(obj);
+            vDebug << level << "{ Repeater: a:" << !obj->isStatic()
+                   << ", copies:" << r->copies(0)
+                   << ", offset:" << r->offset(0);
             visitChildren(static_cast<LOTGroupData *>(obj), level);
             vDebug << level << "} Repeater";
             break;