lottie/parser: support parsing auto orient property of layer.
[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     bool autoOrient() const noexcept{return mAutoOrient;}
304     int timeRemap(int frameNo) const;
305 public:
306     struct SolidLayer {
307         int            mWidth{0};
308         int            mHeight{0};
309         LottieColor    mColor;
310     };
311
312     MatteType            mMatteType{MatteType::None};
313     VRect                mBound;
314     LayerType            mLayerType; //lottie layer type  (solid/shape/precomp)
315     int                  mParentId{-1}; // Lottie the id of the parent in the composition
316     int                  mId{-1};  // Lottie the group id  used for parenting.
317     long                 mInFrame{0};
318     long                 mOutFrame{0};
319     long                 mStartFrame{0};
320     LottieBlendMode      mBlendMode;
321     float                mTimeStreatch{1.0f};
322     std::string          mPreCompRefId;
323     LOTAnimatable<float> mTimeRemap;  /* "tm" */
324     SolidLayer           mSolidLayer;
325     bool                 mHasPathOperator{false};
326     bool                 mHasMask{false};
327     bool                 mHasRepeater{false};
328     bool                 mHasGradient{false};
329     bool                 mRoot{false};
330     bool                 mAutoOrient{false};
331     std::vector<std::shared_ptr<LOTMaskData>>  mMasks;
332     LOTCompositionData   *mCompRef;
333 };
334
335 class LOTCompositionData : public LOTData
336 {
337 public:
338     LOTCompositionData():LOTData(LOTData::Type::Composition){}
339     double duration() const {
340         return isStatic() ? startFrame() :
341                             frameDuration() / frameRate(); // in second
342     }
343     size_t frameAtPos(double pos) const {
344         if (pos < 0) pos = 0;
345         if (pos > 1) pos = 1;
346         return isStatic() ? 0 : pos * frameDuration();
347     }
348     long frameAtTime(double timeInSec) const {
349         return isStatic() ? startFrame() : frameAtPos(timeInSec / duration());
350     }
351     long frameDuration() const {return mEndFrame - mStartFrame -1;}
352     float frameRate() const {return mFrameRate;}
353     long startFrame() const {return mStartFrame;}
354     long endFrame() const {return mEndFrame;}
355     VSize size() const {return mSize;}
356     void processRepeaterObjects();
357 public:
358     std::string          mVersion;
359     VSize                mSize;
360     long                 mStartFrame{0};
361     long                 mEndFrame{0};
362     float                mFrameRate;
363     LottieBlendMode      mBlendMode;
364     std::shared_ptr<LOTLayerData> mRootLayer;
365     std::unordered_map<std::string,
366                        std::shared_ptr<VInterpolator>> mInterpolatorCache;
367     std::unordered_map<std::string,
368                        std::shared_ptr<LOTAsset>>    mAssets;
369
370 };
371
372 /**
373  * TimeRemap has the value in time domain(in sec)
374  * To get the proper mapping first we get the mapped time at the current frame Number
375  * then we need to convert mapped time to frame number using the composition time line
376  * Ex: at frame 10 the mappend time is 0.5(500 ms) which will be convert to frame number
377  * 30 if the frame rate is 60. or will result to frame number 15 if the frame rate is 30.
378  */
379 inline int LOTLayerData::timeRemap(int frameNo) const
380 {
381     frameNo = mTimeRemap.isStatic() ? frameNo :
382               mCompRef->frameAtTime(mTimeRemap.value(frameNo));
383     /* Apply time streatch if it has any.
384      * Time streatch is just a factor by which the animation will speedup or slow
385      * down with respect to the overal animation.
386      * Time streach factor is already applied to the layers inFrame and outFrame.
387      * @TODO need to find out if timestreatch also affects the in and out frame of the
388      * child layers or not. */
389     return frameNo / mTimeStreatch;
390 }
391
392 class LOTTransformData : public LOTData
393 {
394 public:
395     LOTTransformData():LOTData(LOTData::Type::Transform),mScale({100, 100}){}
396     VMatrix matrix(int frameNo) const;
397     float    opacity(int frameNo) const;
398     void cacheMatrix();
399     bool staticMatrix() const {return mStaticMatrix;}
400 private:
401     VMatrix computeMatrix(int frameNo) const;
402 public:
403     LOTAnimatable<float>     mRotation{0};  /* "r" */
404     LOTAnimatable<VPointF>   mScale;     /* "s" */
405     LOTAnimatable<VPointF>   mPosition;  /* "p" */
406     LOTAnimatable<float>     mX{0};
407     LOTAnimatable<float>     mY{0};
408     LOTAnimatable<VPointF>   mAnchor;    /* "a" */
409     LOTAnimatable<float>     mOpacity{100};   /* "o" */
410     LOTAnimatable<float>     mSkew{0};      /* "sk" */
411     LOTAnimatable<float>     mSkewAxis{0};  /* "sa" */
412     bool                     mStaticMatrix{true};
413     bool                     mSeparate{false};
414     VMatrix                  mCachedMatrix;
415 };
416
417 class LOTFillData : public LOTData
418 {
419 public:
420     LOTFillData():LOTData(LOTData::Type::Fill){}
421     float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0;}
422     FillRule fillRule() const {return mFillRule;}
423 public:
424     FillRule                       mFillRule{FillRule::Winding}; /* "r" */
425     LOTAnimatable<LottieColor>     mColor;   /* "c" */
426     LOTAnimatable<int>             mOpacity{100};  /* "o" */
427     bool                           mEnabled{true}; /* "fillEnabled" */
428 };
429
430 struct LOTDashProperty
431 {
432     LOTAnimatable<float>     mDashArray[5]; /* "d" "g" "o"*/
433     int                      mDashCount{0};
434     bool                     mStatic{true};
435 };
436
437 class LOTStrokeData : public LOTData
438 {
439 public:
440     LOTStrokeData():LOTData(LOTData::Type::Stroke){}
441     float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0;}
442     float width(int frameNo) const {return mWidth.value(frameNo);}
443     CapStyle capStyle() const {return mCapStyle;}
444     JoinStyle joinStyle() const {return mJoinStyle;}
445     float meterLimit() const{return mMeterLimit;}
446     bool hasDashInfo() const { return !(mDash.mDashCount == 0);}
447     int getDashInfo(int frameNo, float *array) const;
448 public:
449     LOTAnimatable<LottieColor>        mColor;      /* "c" */
450     LOTAnimatable<int>                mOpacity{100};    /* "o" */
451     LOTAnimatable<float>              mWidth{0};      /* "w" */
452     CapStyle                          mCapStyle;   /* "lc" */
453     JoinStyle                         mJoinStyle;  /* "lj" */
454     float                             mMeterLimit{0}; /* "ml" */
455     LOTDashProperty                   mDash;
456     bool                              mEnabled{true}; /* "fillEnabled" */
457 };
458
459 class LottieGradient
460 {
461 public:
462     friend inline LottieGradient operator+(const LottieGradient &g1, const LottieGradient &g2);
463     friend inline LottieGradient operator-(const LottieGradient &g1, const LottieGradient &g2);
464     friend inline LottieGradient operator*(float m, const LottieGradient &g);
465 public:
466     std::vector<float>    mGradient;
467 };
468
469 inline LottieGradient operator+(const LottieGradient &g1, const LottieGradient &g2)
470 {
471     if (g1.mGradient.size() != g2.mGradient.size())
472         return g1;
473
474     LottieGradient newG;
475     newG.mGradient = g1.mGradient;
476
477     auto g2It = g2.mGradient.begin();
478     for(auto &i : newG.mGradient) {
479         i = i + *g2It;
480         g2It++;
481     }
482
483     return newG;
484 }
485
486 inline LottieGradient operator-(const LottieGradient &g1, const LottieGradient &g2)
487 {
488     if (g1.mGradient.size() != g2.mGradient.size())
489         return g1;
490     LottieGradient newG;
491     newG.mGradient = g1.mGradient;
492
493     auto g2It = g2.mGradient.begin();
494     for(auto &i : newG.mGradient) {
495         i = i - *g2It;
496         g2It++;
497     }
498
499     return newG;
500 }
501
502 inline LottieGradient operator*(float m, const LottieGradient &g)
503 {
504     LottieGradient newG;
505     newG.mGradient = g.mGradient;
506
507     for(auto &i : newG.mGradient) {
508         i = i * m;
509     }
510     return newG;
511 }
512
513
514
515 class LOTGradient : public LOTData
516 {
517 public:
518     LOTGradient(LOTData::Type  type):LOTData(type){}
519     inline float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0;}
520     void update(std::unique_ptr<VGradient> &grad, int frameNo);
521
522 private:
523     void populate(VGradientStops &stops, int frameNo);
524 public:
525     int                                 mGradientType;        /* "t" Linear=1 , Radial = 2*/
526     LOTAnimatable<VPointF>              mStartPoint;          /* "s" */
527     LOTAnimatable<VPointF>              mEndPoint;            /* "e" */
528     LOTAnimatable<float>                mHighlightLength{0};     /* "h" */
529     LOTAnimatable<float>                mHighlightAngle{0};      /* "a" */
530     LOTAnimatable<int>                  mOpacity{0};             /* "o" */
531     LOTAnimatable<LottieGradient>       mGradient;            /* "g" */
532     int                                 mColorPoints{-1};
533     bool                                mEnabled{true};      /* "fillEnabled" */
534 };
535
536 class LOTGFillData : public LOTGradient
537 {
538 public:
539     LOTGFillData():LOTGradient(LOTData::Type::GFill){}
540     FillRule fillRule() const {return mFillRule;}
541 public:
542     FillRule                       mFillRule{FillRule::Winding}; /* "r" */
543 };
544
545 class LOTGStrokeData : public LOTGradient
546 {
547 public:
548     LOTGStrokeData():LOTGradient(LOTData::Type::GStroke){}
549     float width(int frameNo) const {return mWidth.value(frameNo);}
550     CapStyle capStyle() const {return mCapStyle;}
551     JoinStyle joinStyle() const {return mJoinStyle;}
552     float meterLimit() const{return mMeterLimit;}
553     bool hasDashInfo() const { return !(mDash.mDashCount == 0);}
554     int getDashInfo(int frameNo, float *array) const;
555 public:
556     LOTAnimatable<float>           mWidth;       /* "w" */
557     CapStyle                       mCapStyle;    /* "lc" */
558     JoinStyle                      mJoinStyle;   /* "lj" */
559     float                          mMeterLimit{0};  /* "ml" */
560     LOTDashProperty                mDash;
561 };
562
563 class LOTPath : public LOTData
564 {
565 public:
566     LOTPath(LOTData::Type  type):LOTData(type){}
567     VPath::Direction direction() { if (mDirection == 3) return VPath::Direction::CCW;
568                                    else return VPath::Direction::CW;}
569 public:
570     int                                    mDirection{1};
571 };
572
573 class LOTShapeData : public LOTPath
574 {
575 public:
576     LOTShapeData():LOTPath(LOTData::Type::Shape){}
577     void process();
578 public:
579     LOTAnimatable<LottieShapeData>    mShape;
580 };
581
582 class LOTMaskData
583 {
584 public:
585     enum class Mode {
586       None,
587       Add,
588       Substarct,
589       Intersect,
590       Difference
591     };
592     float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0;}
593     bool isStatic() const {return mIsStatic;}
594 public:
595     LOTAnimatable<LottieShapeData>    mShape;
596     LOTAnimatable<float>              mOpacity;
597     bool                              mInv{false};
598     bool                              mIsStatic{true};
599     LOTMaskData::Mode                 mMode;
600 };
601
602 class LOTRectData : public LOTPath
603 {
604 public:
605     LOTRectData():LOTPath(LOTData::Type::Rect){}
606 public:
607     LOTAnimatable<VPointF>    mPos;
608     LOTAnimatable<VPointF>    mSize;
609     LOTAnimatable<float>      mRound{0};
610 };
611
612 class LOTEllipseData : public LOTPath
613 {
614 public:
615     LOTEllipseData():LOTPath(LOTData::Type::Ellipse){}
616 public:
617     LOTAnimatable<VPointF>   mPos;
618     LOTAnimatable<VPointF>   mSize;
619 };
620
621 class LOTPolystarData : public LOTPath
622 {
623 public:
624     enum class PolyType {
625         Star = 1,
626         Polygon = 2
627     };
628     LOTPolystarData():LOTPath(LOTData::Type::Polystar){}
629 public:
630     LOTPolystarData::PolyType     mType{PolyType::Polygon};
631     LOTAnimatable<VPointF>        mPos;
632     LOTAnimatable<float>          mPointCount{0};
633     LOTAnimatable<float>          mInnerRadius{0};
634     LOTAnimatable<float>          mOuterRadius{0};
635     LOTAnimatable<float>          mInnerRoundness{0};
636     LOTAnimatable<float>          mOuterRoundness{0};
637     LOTAnimatable<float>          mRotation{0};
638 };
639
640 class LOTTrimData : public LOTData
641 {
642 public:
643     enum class TrimType {
644         Simultaneously,
645         Individually
646     };
647     LOTTrimData():LOTData(LOTData::Type::Trim){}
648     float start(int frameNo) const {return mStart.value(frameNo)/100.0f;}
649     float end(int frameNo) const {return mEnd.value(frameNo)/100.0f;}
650     float offset(int frameNo) const {return fmod(mOffset.value(frameNo), 360.0f)/ 360.0f;}
651     LOTTrimData::TrimType type() const {return mTrimType;}
652 public:
653     LOTAnimatable<float>             mStart{0};
654     LOTAnimatable<float>             mEnd{0};
655     LOTAnimatable<float>             mOffset{0};
656     LOTTrimData::TrimType            mTrimType{TrimType::Simultaneously};
657 };
658
659 class LOTRepeaterData : public LOTGroupData
660 {
661 public:
662     LOTRepeaterData():LOTGroupData(LOTData::Type::Repeater){}
663 public:
664     LOTAnimatable<float>             mCopies{0};
665     LOTAnimatable<float>             mOffset{0};
666 };
667
668 class LOTModel
669 {
670 public:
671    bool  isStatic() const {return mRoot->isStatic();}
672    double duration() const {return mRoot->duration();}
673    size_t frameDuration() const {return mRoot->frameDuration();}
674    size_t frameRate() const {return mRoot->frameRate();}
675    size_t startFrame() const {return mRoot->startFrame();}
676    size_t endFrame() const {return mRoot->endFrame();}
677    size_t frameAtPos(double pos) const {return mRoot->frameAtPos(pos);}
678 public:
679     std::shared_ptr<LOTCompositionData> mRoot;
680 };
681
682 #endif // LOTModel_H