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