c9e0c233c377875f6e1c62658dbea813194a6939
[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     float angle(float ) const { return 0;}
142 };
143
144 template <>
145 struct LOTKeyFrameValue<VPointF>
146 {
147     VPointF mStartValue;
148     VPointF mEndValue;
149     VPointF mInTangent;
150     VPointF mOutTangent;
151     bool    mPathKeyFrame = false;
152
153     VPointF value(float t) const {
154         if (mPathKeyFrame) {
155             /*
156              * position along the path calcualated
157              * using bezier at progress length (t * bezlen)
158              */
159             VBezier b = VBezier::fromPoints(mStartValue, mStartValue + mOutTangent,
160                                        mEndValue + mInTangent, mEndValue);
161             return b.pointAt(b.tAtLength(t * b.length()));
162
163         } else {
164             return lerp(mStartValue, mEndValue, t);
165         }
166     }
167
168     float angle(float t) const {
169         if (mPathKeyFrame) {
170             VBezier b = VBezier::fromPoints(mStartValue, mStartValue + mOutTangent,
171                                        mEndValue + mInTangent, mEndValue);
172             return b.angleAt(b.tAtLength(t * b.length()));
173         }
174         return 0;
175     }
176 };
177
178
179 template<typename T>
180 class LOTKeyFrame
181 {
182 public:
183     float progress(int frameNo) const {
184         return mInterpolator->value((frameNo - mStartFrame) / (mEndFrame - mStartFrame));
185     }
186     T value(int frameNo) const {
187         return mValue.value(progress(frameNo));
188     }
189     float angle(int frameNo) const {
190         return mValue.angle(progress(frameNo));
191     }
192
193 public:
194     float                 mStartFrame{0};
195     float                 mEndFrame{0};
196     std::shared_ptr<VInterpolator> mInterpolator;
197     LOTKeyFrameValue<T>  mValue;
198 };
199
200 template<typename T>
201 class LOTAnimInfo
202 {
203 public:
204     T value(int frameNo) const {
205         if (mKeyFrames.front().mStartFrame >= frameNo)
206             return mKeyFrames.front().mValue.mStartValue;
207         if(mKeyFrames.back().mEndFrame <= frameNo)
208             return mKeyFrames.back().mValue.mEndValue;
209
210         for(const auto &keyFrame : mKeyFrames) {
211             if (frameNo >= keyFrame.mStartFrame && frameNo < keyFrame.mEndFrame)
212                 return keyFrame.value(frameNo);
213         }
214         return T();
215     }
216
217     float angle(int frameNo) const {
218         if ((mKeyFrames.front().mStartFrame >= frameNo) ||
219             (mKeyFrames.back().mEndFrame <= frameNo) )
220             return 0;
221
222         for(const auto &keyFrame : mKeyFrames) {
223             if (frameNo >= keyFrame.mStartFrame && frameNo < keyFrame.mEndFrame)
224                 return keyFrame.angle(frameNo);
225         }
226         return 0;
227     }
228
229     bool changed(int prevFrame, int curFrame) {
230         int first = mKeyFrames.front().mStartFrame;
231         int last = mKeyFrames.back().mEndFrame;
232
233         if ((first > prevFrame  && first > curFrame) ||
234             (last < prevFrame  && last < curFrame)) {
235             return false;
236         }
237
238         return true;
239     }
240
241 public:
242     std::vector<LOTKeyFrame<T>>    mKeyFrames;
243 };
244
245 template<typename T>
246 class LOTAnimatable
247 {
248 public:
249     LOTAnimatable():mValue(),mAnimInfo(nullptr){}
250     LOTAnimatable(const T &value): mValue(value){}
251     bool isStatic() const {if (mAnimInfo) return false; else return true;}
252     T value(int frameNo) const {
253         return isStatic() ? mValue : mAnimInfo->value(frameNo);
254     }
255     float angle(int frameNo) const {
256         return isStatic() ? 0 : mAnimInfo->angle(frameNo);
257     }
258     bool changed(int prevFrame, int curFrame) {
259         return isStatic() ? false : mAnimInfo->changed(prevFrame, curFrame);
260     }
261 public:
262     T                                 mValue;
263     int                               mPropertyIndex{0}; /* "ix" */
264     std::unique_ptr<LOTAnimInfo<T>>   mAnimInfo;
265 };
266
267 enum class LottieBlendMode
268 {
269     Normal = 0,
270     Multiply = 1,
271     Screen = 2,
272     OverLay = 3
273 };
274
275 class LOTDataVisitor;
276 class LOTData
277 {
278 public:
279     enum class Type {
280         Composition = 1,
281         Layer,
282         ShapeGroup,
283         Transform,
284         Fill,
285         Stroke,
286         GFill,
287         GStroke,
288         Rect,
289         Ellipse,
290         Shape,
291         Polystar,
292         Trim,
293         Repeater
294     };
295     LOTData(LOTData::Type  type): mType(type){}
296     inline LOTData::Type type() const {return mType;}
297     bool isStatic() const{return mStatic;}
298     void setStatic(bool value) {mStatic = value;}
299     bool hidden() const {return mHidden;}
300 public:
301     bool                mStatic{true};
302     bool                mHidden{false};
303     LOTData::Type       mType;
304 };
305
306 class LOTGroupData: public LOTData
307 {
308 public:
309     LOTGroupData(LOTData::Type  type):LOTData(type){}
310 public:
311     std::vector<std::shared_ptr<LOTData>>  mChildren;
312     std::shared_ptr<LOTTransformData>      mTransform;
313 };
314
315 class LOTShapeGroupData : public LOTGroupData
316 {
317 public:
318     LOTShapeGroupData():LOTGroupData(LOTData::Type::ShapeGroup){}
319 };
320
321 class LOTLayerData;
322 struct LOTAsset
323 {
324     int                                          mAssetType; //lottie asset type  (precomp/char/image)
325     std::string                                  mRefId; // ref id
326     std::vector<std::shared_ptr<LOTData>>   mLayers;
327 };
328
329 class LOTLayerData : public LOTGroupData
330 {
331 public:
332     LOTLayerData():LOTGroupData(LOTData::Type::Layer){}
333     bool hasPathOperator() const noexcept {return mHasPathOperator;}
334     bool hasGradient() const noexcept {return mHasGradient;}
335     bool hasMask() const noexcept {return mHasMask;}
336     bool hasRepeater() const noexcept {return mHasRepeater;}
337     bool root() const noexcept {return mRoot;}
338     int id() const noexcept{ return mId;}
339     int parentId() const noexcept{ return mParentId;}
340     int inFrame() const noexcept{return mInFrame;}
341     int outFrame() const noexcept{return mOutFrame;}
342     int startFrame() const noexcept{return mStartFrame;}
343     int solidWidth() const noexcept{return mSolidLayer.mWidth;}
344     int solidHeight() const noexcept{return mSolidLayer.mHeight;}
345     LottieColor solidColor() const noexcept{return mSolidLayer.mColor;}
346     bool autoOrient() const noexcept{return mAutoOrient;}
347     int timeRemap(int frameNo) const;
348 public:
349     struct SolidLayer {
350         int            mWidth{0};
351         int            mHeight{0};
352         LottieColor    mColor;
353     };
354
355     MatteType            mMatteType{MatteType::None};
356     VRect                mBound;
357     LayerType            mLayerType{LayerType::Null}; //lottie layer type  (solid/shape/precomp)
358     int                  mParentId{-1}; // Lottie the id of the parent in the composition
359     int                  mId{-1};  // Lottie the group id  used for parenting.
360     long                 mInFrame{0};
361     long                 mOutFrame{0};
362     long                 mStartFrame{0};
363     LottieBlendMode      mBlendMode{LottieBlendMode::Normal};
364     float                mTimeStreatch{1.0f};
365     std::string          mPreCompRefId;
366     LOTAnimatable<float> mTimeRemap;  /* "tm" */
367     SolidLayer           mSolidLayer;
368     bool                 mHasPathOperator{false};
369     bool                 mHasMask{false};
370     bool                 mHasRepeater{false};
371     bool                 mHasGradient{false};
372     bool                 mRoot{false};
373     bool                 mAutoOrient{false};
374     std::vector<std::shared_ptr<LOTMaskData>>  mMasks;
375     LOTCompositionData   *mCompRef{nullptr};
376 };
377
378 class LOTCompositionData : public LOTData
379 {
380 public:
381     LOTCompositionData():LOTData(LOTData::Type::Composition){}
382     double duration() const {
383         return isStatic() ? startFrame() :
384                             frameDuration() / frameRate(); // in second
385     }
386     size_t frameAtPos(double pos) const {
387         if (pos < 0) pos = 0;
388         if (pos > 1) pos = 1;
389         return isStatic() ? 0 : pos * frameDuration();
390     }
391     long frameAtTime(double timeInSec) const {
392         return isStatic() ? startFrame() : frameAtPos(timeInSec / duration());
393     }
394     long frameDuration() const {return mEndFrame - mStartFrame -1;}
395     float frameRate() const {return mFrameRate;}
396     long startFrame() const {return mStartFrame;}
397     long endFrame() const {return mEndFrame;}
398     VSize size() const {return mSize;}
399     void processRepeaterObjects();
400 public:
401     std::string          mVersion;
402     VSize                mSize;
403     long                 mStartFrame{0};
404     long                 mEndFrame{0};
405     float                mFrameRate{60};
406     LottieBlendMode      mBlendMode;
407     std::shared_ptr<LOTLayerData> mRootLayer;
408     std::unordered_map<std::string,
409                        std::shared_ptr<VInterpolator>> mInterpolatorCache;
410     std::unordered_map<std::string,
411                        std::shared_ptr<LOTAsset>>    mAssets;
412
413 };
414
415 /**
416  * TimeRemap has the value in time domain(in sec)
417  * To get the proper mapping first we get the mapped time at the current frame Number
418  * then we need to convert mapped time to frame number using the composition time line
419  * Ex: at frame 10 the mappend time is 0.5(500 ms) which will be convert to frame number
420  * 30 if the frame rate is 60. or will result to frame number 15 if the frame rate is 30.
421  */
422 inline int LOTLayerData::timeRemap(int frameNo) const
423 {
424     frameNo = mTimeRemap.isStatic() ? frameNo :
425               mCompRef->frameAtTime(mTimeRemap.value(frameNo));
426     /* Apply time streatch if it has any.
427      * Time streatch is just a factor by which the animation will speedup or slow
428      * down with respect to the overal animation.
429      * Time streach factor is already applied to the layers inFrame and outFrame.
430      * @TODO need to find out if timestreatch also affects the in and out frame of the
431      * child layers or not. */
432     return frameNo / mTimeStreatch;
433 }
434
435 struct LOT3DData
436 {
437     LOTAnimatable<float>     mRx{0};
438     LOTAnimatable<float>     mRy{0};
439     LOTAnimatable<float>     mRz{0};
440 };
441
442 class LOTTransformData : public LOTData
443 {
444 public:
445     LOTTransformData():LOTData(LOTData::Type::Transform),mScale({100, 100}){}
446     VMatrix matrix(int frameNo, bool autoOrient = false) const;
447     VMatrix matrixForRepeater(int frameNo, float multiplier) const;
448     float opacity(int frameNo) const { return mOpacity.value(frameNo)/100;}
449     float startOpacity(int frameNo) const { return mStartOpacity.value(frameNo)/100;}
450     float endOpacity(int frameNo) const { return mEndOpacity.value(frameNo)/100;}
451     void cacheMatrix();
452     bool staticMatrix() const {return mStaticMatrix;}
453     bool ddd() const {return m3D ? true : false;}
454 private:
455     VMatrix computeMatrix(int frameNo, bool autoOrient = false) const;
456 public:
457     std::unique_ptr<LOT3DData>    m3D;
458     LOTAnimatable<float>          mRotation{0};  /* "r" */
459     LOTAnimatable<VPointF>        mScale;     /* "s" */
460     LOTAnimatable<VPointF>        mPosition;  /* "p" */
461     LOTAnimatable<float>          mX{0};
462     LOTAnimatable<float>          mY{0};
463     LOTAnimatable<VPointF>        mAnchor;    /* "a" */
464     LOTAnimatable<float>          mOpacity{100};   /* "o" */
465     LOTAnimatable<float>          mSkew{0};      /* "sk" */
466     LOTAnimatable<float>          mSkewAxis{0};  /* "sa" */
467     LOTAnimatable<float>          mStartOpacity{100}; /* "so" */
468     LOTAnimatable<float>          mEndOpacity{100};   /* "eo" */
469     bool                          mStaticMatrix{true};
470     bool                          mSeparate{false};
471     VMatrix                       mCachedMatrix;
472 };
473
474 class LOTFillData : public LOTData
475 {
476 public:
477     LOTFillData():LOTData(LOTData::Type::Fill){}
478     float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0;}
479     FillRule fillRule() const {return mFillRule;}
480 public:
481     FillRule                       mFillRule{FillRule::Winding}; /* "r" */
482     LOTAnimatable<LottieColor>     mColor;   /* "c" */
483     LOTAnimatable<int>             mOpacity{100};  /* "o" */
484     bool                           mEnabled{true}; /* "fillEnabled" */
485 };
486
487 struct LOTDashProperty
488 {
489     LOTAnimatable<float>     mDashArray[5]; /* "d" "g" "o"*/
490     int                      mDashCount{0};
491     bool                     mStatic{true};
492 };
493
494 class LOTStrokeData : public LOTData
495 {
496 public:
497     LOTStrokeData():LOTData(LOTData::Type::Stroke){}
498     float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0;}
499     float width(int frameNo) const {return mWidth.value(frameNo);}
500     CapStyle capStyle() const {return mCapStyle;}
501     JoinStyle joinStyle() const {return mJoinStyle;}
502     float meterLimit() const{return mMeterLimit;}
503     bool hasDashInfo() const { return !(mDash.mDashCount == 0);}
504     int getDashInfo(int frameNo, float *array) const;
505 public:
506     LOTAnimatable<LottieColor>        mColor;      /* "c" */
507     LOTAnimatable<int>                mOpacity{100};    /* "o" */
508     LOTAnimatable<float>              mWidth{0};      /* "w" */
509     CapStyle                          mCapStyle{CapStyle::Flat};   /* "lc" */
510     JoinStyle                         mJoinStyle{JoinStyle::Miter};  /* "lj" */
511     float                             mMeterLimit{0}; /* "ml" */
512     LOTDashProperty                   mDash;
513     bool                              mEnabled{true}; /* "fillEnabled" */
514 };
515
516 class LottieGradient
517 {
518 public:
519     friend inline LottieGradient operator+(const LottieGradient &g1, const LottieGradient &g2);
520     friend inline LottieGradient operator-(const LottieGradient &g1, const LottieGradient &g2);
521     friend inline LottieGradient operator*(float m, const LottieGradient &g);
522 public:
523     std::vector<float>    mGradient;
524 };
525
526 inline LottieGradient operator+(const LottieGradient &g1, const LottieGradient &g2)
527 {
528     if (g1.mGradient.size() != g2.mGradient.size())
529         return g1;
530
531     LottieGradient newG;
532     newG.mGradient = g1.mGradient;
533
534     auto g2It = g2.mGradient.begin();
535     for(auto &i : newG.mGradient) {
536         i = i + *g2It;
537         g2It++;
538     }
539
540     return newG;
541 }
542
543 inline LottieGradient operator-(const LottieGradient &g1, const LottieGradient &g2)
544 {
545     if (g1.mGradient.size() != g2.mGradient.size())
546         return g1;
547     LottieGradient newG;
548     newG.mGradient = g1.mGradient;
549
550     auto g2It = g2.mGradient.begin();
551     for(auto &i : newG.mGradient) {
552         i = i - *g2It;
553         g2It++;
554     }
555
556     return newG;
557 }
558
559 inline LottieGradient operator*(float m, const LottieGradient &g)
560 {
561     LottieGradient newG;
562     newG.mGradient = g.mGradient;
563
564     for(auto &i : newG.mGradient) {
565         i = i * m;
566     }
567     return newG;
568 }
569
570
571
572 class LOTGradient : public LOTData
573 {
574 public:
575     LOTGradient(LOTData::Type  type):LOTData(type){}
576     inline float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0;}
577     void update(std::unique_ptr<VGradient> &grad, int frameNo);
578
579 private:
580     void populate(VGradientStops &stops, int frameNo);
581 public:
582     int                                 mGradientType{1};        /* "t" Linear=1 , Radial = 2*/
583     LOTAnimatable<VPointF>              mStartPoint;          /* "s" */
584     LOTAnimatable<VPointF>              mEndPoint;            /* "e" */
585     LOTAnimatable<float>                mHighlightLength{0};     /* "h" */
586     LOTAnimatable<float>                mHighlightAngle{0};      /* "a" */
587     LOTAnimatable<int>                  mOpacity{0};             /* "o" */
588     LOTAnimatable<LottieGradient>       mGradient;            /* "g" */
589     int                                 mColorPoints{-1};
590     bool                                mEnabled{true};      /* "fillEnabled" */
591 };
592
593 class LOTGFillData : public LOTGradient
594 {
595 public:
596     LOTGFillData():LOTGradient(LOTData::Type::GFill){}
597     FillRule fillRule() const {return mFillRule;}
598 public:
599     FillRule                       mFillRule{FillRule::Winding}; /* "r" */
600 };
601
602 class LOTGStrokeData : public LOTGradient
603 {
604 public:
605     LOTGStrokeData():LOTGradient(LOTData::Type::GStroke){}
606     float width(int frameNo) const {return mWidth.value(frameNo);}
607     CapStyle capStyle() const {return mCapStyle;}
608     JoinStyle joinStyle() const {return mJoinStyle;}
609     float meterLimit() const{return mMeterLimit;}
610     bool hasDashInfo() const { return !(mDash.mDashCount == 0);}
611     int getDashInfo(int frameNo, float *array) const;
612 public:
613     LOTAnimatable<float>           mWidth;       /* "w" */
614     CapStyle                       mCapStyle{CapStyle::Flat};    /* "lc" */
615     JoinStyle                      mJoinStyle{JoinStyle::Miter};   /* "lj" */
616     float                          mMeterLimit{0};  /* "ml" */
617     LOTDashProperty                mDash;
618 };
619
620 class LOTPath : public LOTData
621 {
622 public:
623     LOTPath(LOTData::Type  type):LOTData(type){}
624     VPath::Direction direction() { if (mDirection == 3) return VPath::Direction::CCW;
625                                    else return VPath::Direction::CW;}
626 public:
627     int                                    mDirection{1};
628 };
629
630 class LOTShapeData : public LOTPath
631 {
632 public:
633     LOTShapeData():LOTPath(LOTData::Type::Shape){}
634     void process();
635 public:
636     LOTAnimatable<LottieShapeData>    mShape;
637 };
638
639 class LOTMaskData
640 {
641 public:
642     enum class Mode {
643       None,
644       Add,
645       Substarct,
646       Intersect,
647       Difference
648     };
649     float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0;}
650     bool isStatic() const {return mIsStatic;}
651 public:
652     LOTAnimatable<LottieShapeData>    mShape;
653     LOTAnimatable<float>              mOpacity;
654     bool                              mInv{false};
655     bool                              mIsStatic{true};
656     LOTMaskData::Mode                 mMode;
657 };
658
659 class LOTRectData : public LOTPath
660 {
661 public:
662     LOTRectData():LOTPath(LOTData::Type::Rect){}
663 public:
664     LOTAnimatable<VPointF>    mPos;
665     LOTAnimatable<VPointF>    mSize;
666     LOTAnimatable<float>      mRound{0};
667 };
668
669 class LOTEllipseData : public LOTPath
670 {
671 public:
672     LOTEllipseData():LOTPath(LOTData::Type::Ellipse){}
673 public:
674     LOTAnimatable<VPointF>   mPos;
675     LOTAnimatable<VPointF>   mSize;
676 };
677
678 class LOTPolystarData : public LOTPath
679 {
680 public:
681     enum class PolyType {
682         Star = 1,
683         Polygon = 2
684     };
685     LOTPolystarData():LOTPath(LOTData::Type::Polystar){}
686 public:
687     LOTPolystarData::PolyType     mType{PolyType::Polygon};
688     LOTAnimatable<VPointF>        mPos;
689     LOTAnimatable<float>          mPointCount{0};
690     LOTAnimatable<float>          mInnerRadius{0};
691     LOTAnimatable<float>          mOuterRadius{0};
692     LOTAnimatable<float>          mInnerRoundness{0};
693     LOTAnimatable<float>          mOuterRoundness{0};
694     LOTAnimatable<float>          mRotation{0};
695 };
696
697 class LOTTrimData : public LOTData
698 {
699 public:
700     struct Segment {
701         float start{0};
702         float end{0};
703     };
704     enum class TrimType {
705         Simultaneously,
706         Individually
707     };
708     LOTTrimData():LOTData(LOTData::Type::Trim){}
709     Segment segment(int frameNo) const {
710         float start = mStart.value(frameNo)/100.0f;
711         float end = mEnd.value(frameNo)/100.0f;
712         float offset = fmod(mOffset.value(frameNo), 360.0f)/ 360.0f;
713         start += offset;
714         end += offset;
715         // normalize start, end value to 0 - 1
716         if (fabs(start) > 1) start = fmod(start, 1);
717         if (fabs(end) > 1) end = fmod(end, 1);
718         Segment s;
719         if (start >= 0 && end >= 0) {
720             s.start = std::min(start, end);
721             s.end = std::max(start, end);
722         } else if (start < 0 && end < 0) {
723             start += 1;
724             end +=1;
725             s.start = std::min(start, end);
726             s.end = std::max(start, end);
727         } else {
728             // one of them is -ve so it a loop
729             if (start < 0) start +=1;
730             if (end < 0) end +=1;
731             s.start = std::max(start, end);
732             s.end = std::min(start, end);
733         }
734         return s;
735
736     }
737     LOTTrimData::TrimType type() const {return mTrimType;}
738 public:
739     LOTAnimatable<float>             mStart{0};
740     LOTAnimatable<float>             mEnd{0};
741     LOTAnimatable<float>             mOffset{0};
742     LOTTrimData::TrimType            mTrimType{TrimType::Simultaneously};
743 };
744
745 class LOTRepeaterData : public LOTGroupData
746 {
747 public:
748     LOTRepeaterData():LOTGroupData(LOTData::Type::Repeater){}
749     bool hasMtrixChange(int /*frameNo*/) const {
750         return !(mTransform->isStatic() && mOffset.isStatic());
751     }
752     float copies(int frameNo) const {return mCopies.value(frameNo);}
753     float offset(int frameNo) const {return mOffset.value(frameNo);}
754 public:
755     LOTAnimatable<float>             mCopies{0};
756     LOTAnimatable<float>             mOffset{0};
757 };
758
759 class LOTModel
760 {
761 public:
762    bool  isStatic() const {return mRoot->isStatic();}
763    double duration() const {return mRoot->duration();}
764    size_t frameDuration() const {return mRoot->frameDuration();}
765    size_t frameRate() const {return mRoot->frameRate();}
766    size_t startFrame() const {return mRoot->startFrame();}
767    size_t endFrame() const {return mRoot->endFrame();}
768    size_t frameAtPos(double pos) const {return mRoot->frameAtPos(pos);}
769 public:
770     std::shared_ptr<LOTCompositionData> mRoot;
771 };
772
773 #endif // LOTModel_H