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