lottie: don't redraw path item if its properties are not changed 56/185856/3
authorYoungbok Shin <youngb.shin@samsung.com>
Fri, 3 Aug 2018 04:38:04 +0000 (13:38 +0900)
committerYoungbok Shin <youngb.shin@samsung.com>
Fri, 3 Aug 2018 08:48:32 +0000 (08:48 +0000)
A path item has few animation frames, it has to be redrawn only in
animated frames. If the path item became static after animation frames,
it shouldn't redraw its path.
It will improve performance.

Change-Id: I583f2b8a889208a07530f6d06ed90469bcee726c

example/resource/dynamic_path_test.json [new file with mode: 0644]
src/lottie/lottieitem.cpp
src/lottie/lottieitem.h

diff --git a/example/resource/dynamic_path_test.json b/example/resource/dynamic_path_test.json
new file mode 100644 (file)
index 0000000..a01e506
--- /dev/null
@@ -0,0 +1 @@
+{"v":"5.1.17","fr":29.9700012207031,"ip":0,"op":150.000006109625,"w":300,"h":300,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":20,"s":[135,135],"e":[116,116]},{"t":137.000005580124}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20,"s":[24,25],"e":[57,52],"to":[5.5,4.5],"ti":[-5.5,-4.5]},{"t":129.000005254278}],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[0],"e":[54]},{"t":149.000006068894}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":0,"s":[100,100],"e":[50,50]},{"t":40.0000016292334}],"ix":2},"p":{"a":0,"k":[-26,-37],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145327582955,0.057777773589,0.866666674614,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 2","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"sr","sy":1,"d":1,"pt":{"a":0,"k":5,"ix":3},"p":{"a":0,"k":[26,-54],"ix":4},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":110,"s":[0],"e":[184]},{"t":149.000006068894}],"ix":5},"ir":{"a":0,"k":30,"ix":6},"is":{"a":0,"k":27,"ix":8},"or":{"a":0,"k":59,"ix":7},"os":{"a":0,"k":73,"ix":9},"ix":5,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"fl","c":{"a":0,"k":[0.07993286103,0.716212213039,0.766274511814,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 3","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":150.000006109625,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
index c3bdd77..e76100d 100644 (file)
@@ -669,7 +669,7 @@ void LOTPathDataItem::update(int frameNo, const VMatrix &parentMatrix,
     mCombinedAlpha = parentAlpha;
 
     // 1. update the local path if needed
-    if (!(mInit && mStaticPath)) {
+    if (!(mInit && mStaticPath) && hasChanged(frameNo)) {
         updatePath(mLocalPath, frameNo);
         mInit = true;
         mPathChanged = true;
@@ -731,12 +731,13 @@ void LOTRectItem::updatePath(VPath& path, int frameNo)
 {
     VPointF pos = mData->mPos.value(frameNo);
     VPointF size = mData->mSize.value(frameNo);
-    float   radius = mData->mRound.value(frameNo);
+    float   roundness = mData->mRound.value(frameNo);
     VRectF  r(pos.x() - size.x() / 2, pos.y() - size.y() / 2, size.x(),
              size.y());
 
     path.reset();
-    path.addRoundRect(r, radius, radius, mData->direction());
+    path.addRoundRect(r, roundness, roundness, mData->direction());
+    updateCache(frameNo, pos, size, roundness);
 }
 
 LOTEllipseItem::LOTEllipseItem(LOTEllipseData *data)
@@ -753,6 +754,7 @@ void LOTEllipseItem::updatePath(VPath& path, int frameNo)
 
     path.reset();
     path.addOval(r, mData->direction());
+    updateCache(frameNo, pos, size);
 }
 
 LOTShapeItem::LOTShapeItem(LOTShapeData *data)
@@ -794,6 +796,8 @@ void LOTPolystarItem::updatePath(VPath& path, int frameNo)
     m.translate(pos.x(), pos.y()).rotate(rotation);
     m.rotate(rotation);
     path.transform(m);
+    updateCache(frameNo, pos, points, innerRadius, outerRadius,
+                innerRoundness, outerRoundness, rotation);
 }
 
 /*
index 1d35d48..c7480df 100644 (file)
@@ -226,6 +226,7 @@ private:
    float                                   mCombinedAlpha;
 protected:
    virtual void updatePath(VPath& path, int frameNo) = 0;
+   virtual bool hasChanged(int frameNo) = 0;
 };
 
 class LOTRectItem: public LOTPathDataItem
@@ -235,6 +236,35 @@ public:
 protected:
    void updatePath(VPath& path, int frameNo) final;
    LOTRectData           *mData;
+
+   struct Cache {
+        int                  mFrameNo;
+        VPointF              mPos;
+        VPointF              mSize;
+        float                mRoundness;
+   };
+   Cache                     mCache;
+
+   void updateCache(int frameNo, VPointF pos, VPointF size, float roundness) {
+        mCache.mFrameNo = frameNo;
+        mCache.mPos = pos;
+        mCache.mSize = size;
+        mCache.mRoundness = roundness;
+   }
+   bool hasChanged(int frameNo) final {
+        if (mCache.mFrameNo == frameNo) return false;
+
+        VPointF pos = mData->mPos.value(frameNo);
+        VPointF size = mData->mSize.value(frameNo);
+        float   roundness = mData->mRound.value(frameNo);
+
+        if (vCompare(mCache.mPos.x(), pos.x()) && vCompare(mCache.mPos.y(), pos.y()) &&
+            vCompare(mCache.mSize.x(), size.x()) && vCompare(mCache.mSize.y(), size.y()) &&
+            vCompare(mCache.mRoundness, roundness))
+          return false;
+
+        return true;
+   }
 };
 
 class LOTEllipseItem: public LOTPathDataItem
@@ -244,6 +274,31 @@ public:
 private:
    void updatePath(VPath& path, int frameNo) final;
    LOTEllipseData           *mData;
+
+   struct Cache {
+        int                  mFrameNo;
+        VPointF              mPos;
+        VPointF              mSize;
+   };
+   Cache                     mCache;
+
+   void updateCache(int frameNo, VPointF pos, VPointF size) {
+        mCache.mFrameNo = frameNo;
+        mCache.mPos = pos;
+        mCache.mSize = size;
+   }
+   bool hasChanged(int frameNo) final {
+        if (mCache.mFrameNo == frameNo) return false;
+
+        VPointF pos = mData->mPos.value(frameNo);
+        VPointF size = mData->mSize.value(frameNo);
+
+        if (vCompare(mCache.mPos.x(), pos.x()) && vCompare(mCache.mPos.y(), pos.y()) &&
+            vCompare(mCache.mSize.x(), size.x()) && vCompare(mCache.mSize.y(), size.y()))
+          return false;
+
+        return true;
+   }
 };
 
 class LOTShapeItem: public LOTPathDataItem
@@ -253,6 +308,7 @@ public:
 private:
    void updatePath(VPath& path, int frameNo) final;
    LOTShapeData             *mData;
+   bool hasChanged(int frameNo) final { return true; }
 };
 
 class LOTPolystarItem: public LOTPathDataItem
@@ -262,6 +318,49 @@ public:
 private:
    void updatePath(VPath& path, int frameNo) final;
    LOTPolystarData             *mData;
+
+   struct Cache {
+        int                     mFrameNo;
+        VPointF                 mPos;
+        float                   mPoints;
+        float                   mInnerRadius;
+        float                   mOuterRadius;
+        float                   mInnerRoundness;
+        float                   mOuterRoundness;
+        float                   mRotation;
+   };
+   Cache                        mCache;
+
+   void updateCache(int frameNo, VPointF pos, float points, float innerRadius, float outerRadius,
+                    float innerRoundness, float outerRoundness, float rotation) {
+        mCache.mFrameNo = frameNo;
+        mCache.mPos = pos;
+        mCache.mPoints = points;
+        mCache.mInnerRadius = innerRadius;
+        mCache.mOuterRadius = outerRadius;
+        mCache.mInnerRoundness = innerRoundness;
+        mCache.mOuterRoundness = outerRoundness;
+        mCache.mRotation = rotation;
+   }
+   bool hasChanged(int frameNo) final {
+        if (mCache.mFrameNo == frameNo) return false;
+
+        VPointF pos = mData->mPos.value(frameNo);
+        float   points = mData->mPointCount.value(frameNo);
+        float   innerRadius = mData->mInnerRadius.value(frameNo);
+        float   outerRadius = mData->mOuterRadius.value(frameNo);
+        float   innerRoundness = mData->mInnerRoundness.value(frameNo);
+        float   outerRoundness = mData->mOuterRoundness.value(frameNo);
+        float   rotation = mData->mRotation.value(frameNo);
+
+        if (vCompare(mCache.mPos.x(), pos.x()) && vCompare(mCache.mPos.y(), pos.y()) &&
+            vCompare(mCache.mPoints, points) && vCompare(mCache.mRotation, rotation) &&
+            vCompare(mCache.mInnerRadius, innerRadius) && vCompare(mCache.mOuterRadius, outerRadius) &&
+            vCompare(mCache.mInnerRoundness, innerRoundness) && vCompare(mCache.mOuterRoundness, outerRoundness))
+          return false;
+
+        return true;
+   }
 };