b3dba6063e0b801adefa80a0f54036fe0f82e250
[platform/core/uifw/lottie-player.git] / src / lottie / lottiemodel.h
1 #ifndef LOTModel_H
2 #define LOTModel_H
3
4 #include<vector>
5 #include<memory>
6 #include<unordered_map>
7 #include"vpoint.h"
8 #include"vrect.h"
9 #include"vinterpolator.h"
10 #include"vmatrix.h"
11 #include"vbezier.h"
12 #include"vbrush.h"
13 #include"vpath.h"
14
15 V_USE_NAMESPACE
16
17 class LOTCompositionData;
18 class LOTLayerData;
19 class LOTTransformData;
20 class LOTShapeGroupData;
21 class LOTShapeData;
22 class LOTRectData;
23 class LOTEllipseData;
24 class LOTTrimData;
25 class LOTRepeaterData;
26 class LOTFillData;
27 class LOTStrokeData;
28 class LOTGroupData;
29 class LOTGFillData;
30 class LOTGStrokeData;
31 class LottieShapeData;
32 class LOTPolystarData;
33 class LOTMaskData;
34
35 enum class MatteType
36 {
37     None = 0,
38     Alpha = 1,
39     AlphaInv,
40     Luma,
41     LumaInv
42 };
43
44 enum class LayerType {
45     Precomp = 0,
46     Solid = 1,
47     Image = 2,
48     Null = 3,
49     Shape = 4,
50     Text = 5
51 };
52
53 class LottieColor
54 {
55 public:
56     LottieColor() = default;
57     LottieColor(float red, float green , float blue):r(red), g(green),b(blue){}
58     VColor toColor(float a=1){ return VColor((255 * r), (255 * g), (255 * b), (255 * a));}
59     friend inline LottieColor operator+(const LottieColor &c1, const LottieColor &c2);
60     friend inline LottieColor operator-(const LottieColor &c1, const LottieColor &c2);
61 public:
62     float r{1};
63     float g{1};
64     float b{1};
65 };
66
67 inline LottieColor operator-(const LottieColor &c1, const LottieColor &c2)
68 {
69     return LottieColor(c1.r - c2.r, c1.g - c2.g, c1.b - c2.b);
70 }
71 inline LottieColor operator+(const LottieColor &c1, const LottieColor &c2)
72 {
73     return LottieColor(c1.r + c2.r, c1.g + c2.g, c1.b + c2.b);
74 }
75
76 inline const LottieColor operator*(const LottieColor &c, float m)
77 { return LottieColor(c.r*m, c.g*m, c.b*m); }
78
79 inline const LottieColor operator*(float m, const LottieColor &c)
80 { return LottieColor(c.r*m, c.g*m, c.b*m); }
81
82 class LottieShapeData
83 {
84 public:
85     void reserve(int size) {
86         mPoints.reserve(mPoints.size() + size);
87     }
88     void toPath(VPath& path) {
89         path.reset();
90
91         if (mPoints.empty()) return;
92
93         int size = mPoints.size();
94         const VPointF *points = mPoints.data();
95         /* reserve exact memory requirement at once
96          * ptSize = size + 1(size + close)
97          * elmSize = size/3 cubic + 1 move + 1 close
98          */
99         path.reserve(size + 1 , size/3 + 2);
100         path.moveTo(points[0]);
101         for (int i = 1 ; i < size; i+=3) {
102            path.cubicTo(points[i], points[i+1], points[i+2]);
103         }
104         if (mClosed)
105           path.close();
106     }
107 public:
108     std::vector<VPointF>    mPoints;
109     bool                     mClosed = false;   /* "c" */
110 };
111
112
113
114 template<typename T>
115 inline T lerp(const T& start, const T& end, float t)
116 {
117     return start + t * (end - start);
118 }
119
120 inline LottieShapeData lerp(const LottieShapeData& start, const LottieShapeData& end, float t)
121 {
122     if (start.mPoints.size() != start.mPoints.size())
123        return LottieShapeData();
124
125     LottieShapeData result;
126     result.reserve(start.mPoints.size());
127     for (unsigned int i = 0 ; i < start.mPoints.size(); i++) {
128        result.mPoints.push_back(start.mPoints[i] + t * (end.mPoints[i] - start.mPoints[i]));
129     }
130    return result;
131 }
132
133 template <typename T>
134 struct LOTKeyFrameValue
135 {
136     T mStartValue;
137     T mEndValue;
138     T value(float t) const {
139         return lerp(mStartValue, mEndValue, t);
140     }
141 };
142
143 template <>
144 struct LOTKeyFrameValue<VPointF>
145 {
146     VPointF mStartValue;
147     VPointF mEndValue;
148     VPointF mInTangent;
149     VPointF mOutTangent;
150     bool    mPathKeyFrame = false;
151
152     VPointF value(float t) const {
153         if (mPathKeyFrame) {
154             /*
155              * position along the path calcualated
156              * using bezier at progress length (t * bezlen)
157              */
158             VBezier b = VBezier::fromPoints(mStartValue, mStartValue + mOutTangent,
159                                        mEndValue + mInTangent, mEndValue);
160             return b.pointAt(b.tAtLength(t * b.length()));
161
162         } else {
163             return lerp(mStartValue, mEndValue, t);
164         }
165     }
166 };
167
168
169 template<typename T>
170 class LOTKeyFrame
171 {
172 public:
173     T value(int frameNo) const {
174         float progress = mInterpolator->value((frameNo - mStartFrame) / (mEndFrame - mStartFrame));
175         return mValue.value(progress);
176     }
177
178 public:
179     float                 mStartFrame{0};
180     float                 mEndFrame{0};
181     std::shared_ptr<VInterpolator> mInterpolator;
182     LOTKeyFrameValue<T>  mValue;
183 };
184
185 template<typename T>
186 class LOTAnimInfo
187 {
188 public:
189     T value(int frameNo) const {
190         if (mKeyFrames.front().mStartFrame >= frameNo)
191             return mKeyFrames.front().mValue.mStartValue;
192         if(mKeyFrames.back().mEndFrame <= frameNo)
193             return mKeyFrames.back().mValue.mEndValue;
194
195         for(auto keyFrame : mKeyFrames) {
196             if (frameNo >= keyFrame.mStartFrame && frameNo < keyFrame.mEndFrame)
197                 return keyFrame.value(frameNo);
198         }
199         return T();
200     }
201 public:
202     std::vector<LOTKeyFrame<T>>    mKeyFrames;
203 };
204
205 template<typename T>
206 class LOTAnimatable
207 {
208 public:
209     LOTAnimatable():mValue(),mAnimInfo(nullptr){}
210     LOTAnimatable(const T &value): mValue(value){}
211     bool isStatic() const {if (mAnimInfo) return false; else return true;}
212     T value(int frameNo) const{
213         if (isStatic())
214             return mValue;
215         else
216             return mAnimInfo->value(frameNo);
217     }
218 public:
219     T                                    mValue;
220     int                                  mPropertyIndex; /* "ix" */
221     std::unique_ptr<LOTAnimInfo<T>>   mAnimInfo;
222 };
223
224 enum class LottieBlendMode
225 {
226     Normal = 0,
227     Multiply = 1,
228     Screen = 2,
229     OverLay = 3
230 };
231
232 class LOTDataVisitor;
233 class LOTData
234 {
235 public:
236     enum class Type {
237         Composition = 1,
238         Layer,
239         ShapeGroup,
240         Transform,
241         Fill,
242         Stroke,
243         GFill,
244         GStroke,
245         Rect,
246         Ellipse,
247         Shape,
248         Polystar,
249         Trim,
250         Repeater
251     };
252     LOTData(LOTData::Type  type): mType(type){}
253     inline LOTData::Type type() const {return mType;}
254     bool isStatic() const{return mStatic;}
255     void setStatic(bool value) {mStatic = value;}
256     bool hidden() const {return mHidden;}
257 public:
258     bool                mStatic{true};
259     bool                mHidden{false};
260     LOTData::Type       mType;
261 };
262
263 class LOTGroupData: public LOTData
264 {
265 public:
266     LOTGroupData(LOTData::Type  type):LOTData(type){}
267 public:
268     std::vector<std::shared_ptr<LOTData>>  mChildren;
269     std::shared_ptr<LOTTransformData>      mTransform;
270 };
271
272 class LOTShapeGroupData : public LOTGroupData
273 {
274 public:
275     LOTShapeGroupData():LOTGroupData(LOTData::Type::ShapeGroup){}
276 };
277
278 class LOTLayerData;
279 struct LOTAsset
280 {
281     int                                          mAssetType; //lottie asset type  (precomp/char/image)
282     std::string                                  mRefId; // ref id
283     std::vector<std::shared_ptr<LOTData>>   mLayers;
284 };
285
286 class LOTLayerData : public LOTGroupData
287 {
288 public:
289     LOTLayerData():LOTGroupData(LOTData::Type::Layer){}
290     bool hasPathOperator() const noexcept {return mHasPathOperator;}
291     bool hasGradient() const noexcept {return mHasGradient;}
292     bool hasMask() const noexcept {return mHasMask;}
293     bool hasRepeater() const noexcept {return mHasRepeater;}
294     bool root() const noexcept {return mRoot;}
295     int id() const noexcept{ return mId;}
296     int parentId() const noexcept{ return mParentId;}
297     int inFrame() const noexcept{return mInFrame;}
298     int outFrame() const noexcept{return mOutFrame;}
299     int startFrame() const noexcept{return mStartFrame;}
300     int solidWidth() const noexcept{return mSolidLayer.mWidth;}
301     int solidHeight() const noexcept{return mSolidLayer.mHeight;}
302     LottieColor solidColor() const noexcept{return mSolidLayer.mColor;}
303     int timeRemap(int frameNo) const;
304 public:
305     struct SolidLayer {
306         int            mWidth{0};
307         int            mHeight{0};
308         LottieColor    mColor;
309     };
310
311     MatteType            mMatteType{MatteType::None};
312     VRect                mBound;
313     LayerType            mLayerType; //lottie layer type  (solid/shape/precomp)
314     int                  mParentId{-1}; // Lottie the id of the parent in the composition
315     int                  mId{-1};  // Lottie the group id  used for parenting.
316     long                 mInFrame{0};
317     long                 mOutFrame{0};
318     long                 mStartFrame{0};
319     LottieBlendMode      mBlendMode;
320     float                mTimeStreatch{1.0f};
321     std::string          mPreCompRefId;
322     LOTAnimatable<float> mTimeRemap;  /* "tm" */
323     SolidLayer           mSolidLayer;
324     bool                 mHasPathOperator{false};
325     bool                 mHasMask{false};
326     bool                 mHasRepeater{false};
327     bool                 mHasGradient{false};
328     bool                 mRoot{false};
329     std::vector<std::shared_ptr<LOTMaskData>>  mMasks;
330     LOTCompositionData   *mCompRef;
331 };
332
333 class LOTCompositionData : public LOTData
334 {
335 public:
336     LOTCompositionData():LOTData(LOTData::Type::Composition){}
337     double duration() const {
338         return isStatic() ? startFrame() :
339                             frameDuration() / frameRate(); // in second
340     }
341     size_t frameAtPos(double pos) const {
342         if (pos < 0) pos = 0;
343         if (pos > 1) pos = 1;
344         return isStatic() ? 0 : pos * frameDuration();
345     }
346     long frameAtTime(double timeInSec) const {
347         return isStatic() ? startFrame() : frameAtPos(timeInSec / duration());
348     }
349     long frameDuration() const {return mEndFrame - mStartFrame -1;}
350     float frameRate() const {return mFrameRate;}
351     long startFrame() const {return mStartFrame;}
352     long endFrame() const {return mEndFrame;}
353     VSize size() const {return mSize;}
354     void processRepeaterObjects();
355 public:
356     std::string          mVersion;
357     VSize                mSize;
358     long                 mStartFrame{0};
359     long                 mEndFrame{0};
360     float                mFrameRate;
361     LottieBlendMode      mBlendMode;
362     std::shared_ptr<LOTLayerData> mRootLayer;
363     std::unordered_map<std::string,
364                        std::shared_ptr<VInterpolator>> mInterpolatorCache;
365     std::unordered_map<std::string,
366                        std::shared_ptr<LOTAsset>>    mAssets;
367
368 };
369
370 /**
371  * TimeRemap has the value in time domain(in sec)
372  * To get the proper mapping first we get the mapped time at the current frame Number
373  * then we need to convert mapped time to frame number using the composition time line
374  * Ex: at frame 10 the mappend time is 0.5(500 ms) which will be convert to frame number
375  * 30 if the frame rate is 60. or will result to frame number 15 if the frame rate is 30.
376  */
377 inline int LOTLayerData::timeRemap(int frameNo) const
378 {
379     frameNo = mTimeRemap.isStatic() ? frameNo :
380               mCompRef->frameAtTime(mTimeRemap.value(frameNo));
381     /* Apply time streatch if it has any.
382      * Time streatch is just a factor by which the animation will speedup or slow
383      * down with respect to the overal animation.
384      * Time streach factor is already applied to the layers inFrame and outFrame.
385      * @TODO need to find out if timestreatch also affects the in and out frame of the
386      * child layers or not. */
387     return frameNo / mTimeStreatch;
388 }
389
390 class LOTTransformData : public LOTData
391 {
392 public:
393     LOTTransformData():LOTData(LOTData::Type::Transform),mScale({100, 100}){}
394     VMatrix matrix(int frameNo) const;
395     float    opacity(int frameNo) const;
396     void cacheMatrix();
397     bool staticMatrix() const {return mStaticMatrix;}
398 private:
399     VMatrix computeMatrix(int frameNo) const;
400 public:
401     LOTAnimatable<float>     mRotation{0};  /* "r" */
402     LOTAnimatable<VPointF>   mScale;     /* "s" */
403     LOTAnimatable<VPointF>   mPosition;  /* "p" */
404     LOTAnimatable<float>     mX{0};
405     LOTAnimatable<float>     mY{0};
406     LOTAnimatable<VPointF>   mAnchor;    /* "a" */
407     LOTAnimatable<float>     mOpacity{100};   /* "o" */
408     LOTAnimatable<float>     mSkew{0};      /* "sk" */
409     LOTAnimatable<float>     mSkewAxis{0};  /* "sa" */
410     bool                     mStaticMatrix{true};
411     bool                     mSeparate{false};
412     VMatrix                  mCachedMatrix;
413 };
414
415 class LOTFillData : public LOTData
416 {
417 public:
418     LOTFillData():LOTData(LOTData::Type::Fill){}
419     float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0;}
420     FillRule fillRule() const {return mFillRule;}
421 public:
422     FillRule                       mFillRule{FillRule::Winding}; /* "r" */
423     LOTAnimatable<LottieColor>     mColor;   /* "c" */
424     LOTAnimatable<int>             mOpacity{100};  /* "o" */
425     bool                           mEnabled{true}; /* "fillEnabled" */
426 };
427
428 struct LOTDashProperty
429 {
430     LOTAnimatable<float>     mDashArray[5]; /* "d" "g" "o"*/
431     int                      mDashCount{0};
432     bool                     mStatic{true};
433 };
434
435 class LOTStrokeData : public LOTData
436 {
437 public:
438     LOTStrokeData():LOTData(LOTData::Type::Stroke){}
439     float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0;}
440     float width(int frameNo) const {return mWidth.value(frameNo);}
441     CapStyle capStyle() const {return mCapStyle;}
442     JoinStyle joinStyle() const {return mJoinStyle;}
443     float meterLimit() const{return mMeterLimit;}
444     bool hasDashInfo() const { return !(mDash.mDashCount == 0);}
445     int getDashInfo(int frameNo, float *array) const;
446 public:
447     LOTAnimatable<LottieColor>        mColor;      /* "c" */
448     LOTAnimatable<int>                mOpacity{100};    /* "o" */
449     LOTAnimatable<float>              mWidth{0};      /* "w" */
450     CapStyle                          mCapStyle;   /* "lc" */
451     JoinStyle                         mJoinStyle;  /* "lj" */
452     float                             mMeterLimit{0}; /* "ml" */
453     LOTDashProperty                   mDash;
454     bool                              mEnabled{true}; /* "fillEnabled" */
455 };
456
457 class LottieGradient
458 {
459 public:
460     friend inline LottieGradient operator+(const LottieGradient &g1, const LottieGradient &g2);
461     friend inline LottieGradient operator-(const LottieGradient &g1, const LottieGradient &g2);
462     friend inline LottieGradient operator*(float m, const LottieGradient &g);
463 public:
464     std::vector<float>    mGradient;
465 };
466
467 inline LottieGradient operator+(const LottieGradient &g1, const LottieGradient &g2)
468 {
469     if (g1.mGradient.size() != g2.mGradient.size())
470         return g1;
471
472     LottieGradient newG;
473     newG.mGradient = g1.mGradient;
474
475     auto g2It = g2.mGradient.begin();
476     for(auto &i : newG.mGradient) {
477         i = i + *g2It;
478         g2It++;
479     }
480
481     return newG;
482 }
483
484 inline LottieGradient operator-(const LottieGradient &g1, const LottieGradient &g2)
485 {
486     if (g1.mGradient.size() != g2.mGradient.size())
487         return g1;
488     LottieGradient newG;
489     newG.mGradient = g1.mGradient;
490
491     auto g2It = g2.mGradient.begin();
492     for(auto &i : newG.mGradient) {
493         i = i - *g2It;
494         g2It++;
495     }
496
497     return newG;
498 }
499
500 inline LottieGradient operator*(float m, const LottieGradient &g)
501 {
502     LottieGradient newG;
503     newG.mGradient = g.mGradient;
504
505     for(auto &i : newG.mGradient) {
506         i = i * m;
507     }
508     return newG;
509 }
510
511
512
513 class LOTGradient : public LOTData
514 {
515 public:
516     LOTGradient(LOTData::Type  type):LOTData(type){}
517     inline float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0;}
518     void update(std::unique_ptr<VGradient> &grad, int frameNo);
519
520 private:
521     void populate(VGradientStops &stops, int frameNo);
522 public:
523     int                                 mGradientType;        /* "t" Linear=1 , Radial = 2*/
524     LOTAnimatable<VPointF>              mStartPoint;          /* "s" */
525     LOTAnimatable<VPointF>              mEndPoint;            /* "e" */
526     LOTAnimatable<float>                mHighlightLength{0};     /* "h" */
527     LOTAnimatable<float>                mHighlightAngle{0};      /* "a" */
528     LOTAnimatable<int>                  mOpacity{0};             /* "o" */
529     LOTAnimatable<LottieGradient>       mGradient;            /* "g" */
530     int                                 mColorPoints{-1};
531     bool                                mEnabled{true};      /* "fillEnabled" */
532 };
533
534 class LOTGFillData : public LOTGradient
535 {
536 public:
537     LOTGFillData():LOTGradient(LOTData::Type::GFill){}
538     FillRule fillRule() const {return mFillRule;}
539 public:
540     FillRule                       mFillRule{FillRule::Winding}; /* "r" */
541 };
542
543 class LOTGStrokeData : public LOTGradient
544 {
545 public:
546     LOTGStrokeData():LOTGradient(LOTData::Type::GStroke){}
547     float width(int frameNo) const {return mWidth.value(frameNo);}
548     CapStyle capStyle() const {return mCapStyle;}
549     JoinStyle joinStyle() const {return mJoinStyle;}
550     float meterLimit() const{return mMeterLimit;}
551     bool hasDashInfo() const { return !(mDash.mDashCount == 0);}
552     int getDashInfo(int frameNo, float *array) const;
553 public:
554     LOTAnimatable<float>           mWidth;       /* "w" */
555     CapStyle                       mCapStyle;    /* "lc" */
556     JoinStyle                      mJoinStyle;   /* "lj" */
557     float                          mMeterLimit{0};  /* "ml" */
558     LOTDashProperty                mDash;
559 };
560
561 class LOTPath : public LOTData
562 {
563 public:
564     LOTPath(LOTData::Type  type):LOTData(type){}
565     VPath::Direction direction() { if (mDirection == 3) return VPath::Direction::CCW;
566                                    else return VPath::Direction::CW;}
567 public:
568     int                                    mDirection{1};
569 };
570
571 class LOTShapeData : public LOTPath
572 {
573 public:
574     LOTShapeData():LOTPath(LOTData::Type::Shape){}
575     void process();
576 public:
577     LOTAnimatable<LottieShapeData>    mShape;
578 };
579
580 class LOTMaskData
581 {
582 public:
583     enum class Mode {
584       None,
585       Add,
586       Substarct,
587       Intersect,
588       Difference
589     };
590     float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0;}
591     bool isStatic() const {return mIsStatic;}
592 public:
593     LOTAnimatable<LottieShapeData>    mShape;
594     LOTAnimatable<float>              mOpacity;
595     bool                              mInv{false};
596     bool                              mIsStatic{true};
597     LOTMaskData::Mode                 mMode;
598 };
599
600 class LOTRectData : public LOTPath
601 {
602 public:
603     LOTRectData():LOTPath(LOTData::Type::Rect){}
604 public:
605     LOTAnimatable<VPointF>    mPos;
606     LOTAnimatable<VPointF>    mSize;
607     LOTAnimatable<float>      mRound{0};
608 };
609
610 class LOTEllipseData : public LOTPath
611 {
612 public:
613     LOTEllipseData():LOTPath(LOTData::Type::Ellipse){}
614 public:
615     LOTAnimatable<VPointF>   mPos;
616     LOTAnimatable<VPointF>   mSize;
617 };
618
619 class LOTPolystarData : public LOTPath
620 {
621 public:
622     enum class PolyType {
623         Star = 1,
624         Polygon = 2
625     };
626     LOTPolystarData():LOTPath(LOTData::Type::Polystar){}
627 public:
628     LOTPolystarData::PolyType     mType{PolyType::Polygon};
629     LOTAnimatable<VPointF>        mPos;
630     LOTAnimatable<float>          mPointCount{0};
631     LOTAnimatable<float>          mInnerRadius{0};
632     LOTAnimatable<float>          mOuterRadius{0};
633     LOTAnimatable<float>          mInnerRoundness{0};
634     LOTAnimatable<float>          mOuterRoundness{0};
635     LOTAnimatable<float>          mRotation{0};
636 };
637
638 class LOTTrimData : public LOTData
639 {
640 public:
641     enum class TrimType {
642         Simultaneously,
643         Individually
644     };
645     LOTTrimData():LOTData(LOTData::Type::Trim){}
646     float start(int frameNo) const {return mStart.value(frameNo)/100.0f;}
647     float end(int frameNo) const {return mEnd.value(frameNo)/100.0f;}
648     float offset(int frameNo) const {return fmod(mOffset.value(frameNo), 360.0f)/ 360.0f;}
649     LOTTrimData::TrimType type() const {return mTrimType;}
650 public:
651     LOTAnimatable<float>             mStart{0};
652     LOTAnimatable<float>             mEnd{0};
653     LOTAnimatable<float>             mOffset{0};
654     LOTTrimData::TrimType            mTrimType{TrimType::Simultaneously};
655 };
656
657 class LOTRepeaterData : public LOTGroupData
658 {
659 public:
660     LOTRepeaterData():LOTGroupData(LOTData::Type::Repeater){}
661 public:
662     LOTAnimatable<float>             mCopies{0};
663     LOTAnimatable<float>             mOffset{0};
664 };
665
666 class LOTModel
667 {
668 public:
669    bool  isStatic() const {return mRoot->isStatic();}
670    double duration() const {return mRoot->duration();}
671    size_t frameDuration() const {return mRoot->frameDuration();}
672    size_t frameRate() const {return mRoot->frameRate();}
673    size_t startFrame() const {return mRoot->startFrame();}
674    size_t endFrame() const {return mRoot->endFrame();}
675    size_t frameAtPos(double pos) const {return mRoot->frameAtPos(pos);}
676 public:
677     std::shared_ptr<LOTCompositionData> mRoot;
678 };
679
680 #endif // LOTModel_H