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