6 #include<unordered_map>
9 #include"vinterpolator.h"
17 class LOTCompositionData;
19 class LOTTransformData;
20 class LOTShapeGroupData;
25 class LOTRepeaterData;
31 class LottieShapeData;
32 class LOTPolystarData;
44 enum class LayerType {
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);
67 inline LottieColor operator-(const LottieColor &c1, const LottieColor &c2)
69 return LottieColor(c1.r - c2.r, c1.g - c2.g, c1.b - c2.b);
71 inline LottieColor operator+(const LottieColor &c1, const LottieColor &c2)
73 return LottieColor(c1.r + c2.r, c1.g + c2.g, c1.b + c2.b);
76 inline const LottieColor operator*(const LottieColor &c, float m)
77 { return LottieColor(c.r*m, c.g*m, c.b*m); }
79 inline const LottieColor operator*(float m, const LottieColor &c)
80 { return LottieColor(c.r*m, c.g*m, c.b*m); }
85 void reserve(int size) {
86 mPoints.reserve(mPoints.size() + size);
88 void toPath(VPath& path) {
91 if (mPoints.empty()) return;
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
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]);
108 std::vector<VPointF> mPoints;
109 bool mClosed = false; /* "c" */
115 inline T lerp(const T& start, const T& end, float t)
117 return start + t * (end - start);
120 inline LottieShapeData lerp(const LottieShapeData& start, const LottieShapeData& end, float t)
122 if (start.mPoints.size() != start.mPoints.size())
123 return LottieShapeData();
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]));
133 template <typename T>
134 struct LOTKeyFrameValue
138 T value(float t) const {
139 return lerp(mStartValue, mEndValue, t);
144 struct LOTKeyFrameValue<VPointF>
150 bool mPathKeyFrame = false;
152 VPointF value(float t) const {
155 * position along the path calcualated
156 * using bezier at progress length (t * bezlen)
158 VBezier b = VBezier::fromPoints(mStartValue, mStartValue + mOutTangent,
159 mEndValue + mInTangent, mEndValue);
160 return b.pointAt(b.tAtLength(t * b.length()));
163 return lerp(mStartValue, mEndValue, t);
173 T value(int frameNo) const {
174 float progress = mInterpolator->value((frameNo - mStartFrame) / (mEndFrame - mStartFrame));
175 return mValue.value(progress);
179 float mStartFrame{0};
181 std::shared_ptr<VInterpolator> mInterpolator;
182 LOTKeyFrameValue<T> mValue;
189 T value(int frameNo) const {
190 if (mKeyFrames.front().mStartFrame >= frameNo)
191 return mKeyFrames.front().mValue.mStartValue;
192 if(mKeyFrames.back().mEndFrame <= frameNo)
193 return mKeyFrames.back().mValue.mEndValue;
195 for(auto keyFrame : mKeyFrames) {
196 if (frameNo >= keyFrame.mStartFrame && frameNo < keyFrame.mEndFrame)
197 return keyFrame.value(frameNo);
202 std::vector<LOTKeyFrame<T>> mKeyFrames;
209 LOTAnimatable():mValue(),mAnimInfo(nullptr){}
210 LOTAnimatable(const T &value): mValue(value){}
211 bool isStatic() const {if (mAnimInfo) return false; else return true;}
212 T value(int frameNo) const{
216 return mAnimInfo->value(frameNo);
220 int mPropertyIndex; /* "ix" */
221 std::unique_ptr<LOTAnimInfo<T>> mAnimInfo;
224 enum class LottieBlendMode
232 class LOTDataVisitor;
252 LOTData(LOTData::Type type): mType(type){}
253 inline LOTData::Type type() const {return mType;}
254 bool isStatic() const{return mStatic;}
255 void setStatic(bool value) {mStatic = value;}
256 bool hidden() const {return mHidden;}
263 class LOTGroupData: public LOTData
266 LOTGroupData(LOTData::Type type):LOTData(type){}
268 std::vector<std::shared_ptr<LOTData>> mChildren;
269 std::shared_ptr<LOTTransformData> mTransform;
272 class LOTShapeGroupData : public LOTGroupData
275 LOTShapeGroupData():LOTGroupData(LOTData::Type::ShapeGroup){}
281 int mAssetType; //lottie asset type (precomp/char/image)
282 std::string mRefId; // ref id
283 std::vector<std::shared_ptr<LOTData>> mLayers;
286 class LOTLayerData : public LOTGroupData
289 LOTLayerData():LOTGroupData(LOTData::Type::Layer){}
290 bool hasPathOperator() const noexcept {return mHasPathOperator;}
291 bool hasGradient() const noexcept {return mHasGradient;}
292 bool hasMask() const noexcept {return mHasMask;}
293 bool hasRepeater() const noexcept {return mHasRepeater;}
294 bool root() const noexcept {return mRoot;}
295 int id() const noexcept{ return mId;}
296 int parentId() const noexcept{ return mParentId;}
297 int inFrame() const noexcept{return mInFrame;}
298 int outFrame() const noexcept{return mOutFrame;}
299 int startFrame() const noexcept{return mStartFrame;}
300 int solidWidth() const noexcept{return mSolidLayer.mWidth;}
301 int solidHeight() const noexcept{return mSolidLayer.mHeight;}
302 LottieColor solidColor() const noexcept{return mSolidLayer.mColor;}
303 bool autoOrient() const noexcept{return mAutoOrient;}
304 int timeRemap(int frameNo) const;
312 MatteType mMatteType{MatteType::None};
314 LayerType mLayerType; //lottie layer type (solid/shape/precomp)
315 int mParentId{-1}; // Lottie the id of the parent in the composition
316 int mId{-1}; // Lottie the group id used for parenting.
320 LottieBlendMode mBlendMode;
321 float mTimeStreatch{1.0f};
322 std::string mPreCompRefId;
323 LOTAnimatable<float> mTimeRemap; /* "tm" */
324 SolidLayer mSolidLayer;
325 bool mHasPathOperator{false};
326 bool mHasMask{false};
327 bool mHasRepeater{false};
328 bool mHasGradient{false};
330 bool mAutoOrient{false};
331 std::vector<std::shared_ptr<LOTMaskData>> mMasks;
332 LOTCompositionData *mCompRef;
335 class LOTCompositionData : public LOTData
338 LOTCompositionData():LOTData(LOTData::Type::Composition){}
339 double duration() const {
340 return isStatic() ? startFrame() :
341 frameDuration() / frameRate(); // in second
343 size_t frameAtPos(double pos) const {
344 if (pos < 0) pos = 0;
345 if (pos > 1) pos = 1;
346 return isStatic() ? 0 : pos * frameDuration();
348 long frameAtTime(double timeInSec) const {
349 return isStatic() ? startFrame() : frameAtPos(timeInSec / duration());
351 long frameDuration() const {return mEndFrame - mStartFrame -1;}
352 float frameRate() const {return mFrameRate;}
353 long startFrame() const {return mStartFrame;}
354 long endFrame() const {return mEndFrame;}
355 VSize size() const {return mSize;}
356 void processRepeaterObjects();
358 std::string mVersion;
363 LottieBlendMode mBlendMode;
364 std::shared_ptr<LOTLayerData> mRootLayer;
365 std::unordered_map<std::string,
366 std::shared_ptr<VInterpolator>> mInterpolatorCache;
367 std::unordered_map<std::string,
368 std::shared_ptr<LOTAsset>> mAssets;
373 * TimeRemap has the value in time domain(in sec)
374 * To get the proper mapping first we get the mapped time at the current frame Number
375 * then we need to convert mapped time to frame number using the composition time line
376 * Ex: at frame 10 the mappend time is 0.5(500 ms) which will be convert to frame number
377 * 30 if the frame rate is 60. or will result to frame number 15 if the frame rate is 30.
379 inline int LOTLayerData::timeRemap(int frameNo) const
381 frameNo = mTimeRemap.isStatic() ? frameNo :
382 mCompRef->frameAtTime(mTimeRemap.value(frameNo));
383 /* Apply time streatch if it has any.
384 * Time streatch is just a factor by which the animation will speedup or slow
385 * down with respect to the overal animation.
386 * Time streach factor is already applied to the layers inFrame and outFrame.
387 * @TODO need to find out if timestreatch also affects the in and out frame of the
388 * child layers or not. */
389 return frameNo / mTimeStreatch;
392 class LOTTransformData : public LOTData
395 LOTTransformData():LOTData(LOTData::Type::Transform),mScale({100, 100}){}
396 VMatrix matrix(int frameNo) const;
397 float opacity(int frameNo) const;
399 bool staticMatrix() const {return mStaticMatrix;}
401 VMatrix computeMatrix(int frameNo) const;
403 LOTAnimatable<float> mRotation{0}; /* "r" */
404 LOTAnimatable<VPointF> mScale; /* "s" */
405 LOTAnimatable<VPointF> mPosition; /* "p" */
406 LOTAnimatable<float> mX{0};
407 LOTAnimatable<float> mY{0};
408 LOTAnimatable<VPointF> mAnchor; /* "a" */
409 LOTAnimatable<float> mOpacity{100}; /* "o" */
410 LOTAnimatable<float> mSkew{0}; /* "sk" */
411 LOTAnimatable<float> mSkewAxis{0}; /* "sa" */
412 bool mStaticMatrix{true};
413 bool mSeparate{false};
414 VMatrix mCachedMatrix;
417 class LOTFillData : public LOTData
420 LOTFillData():LOTData(LOTData::Type::Fill){}
421 float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0;}
422 FillRule fillRule() const {return mFillRule;}
424 FillRule mFillRule{FillRule::Winding}; /* "r" */
425 LOTAnimatable<LottieColor> mColor; /* "c" */
426 LOTAnimatable<int> mOpacity{100}; /* "o" */
427 bool mEnabled{true}; /* "fillEnabled" */
430 struct LOTDashProperty
432 LOTAnimatable<float> mDashArray[5]; /* "d" "g" "o"*/
437 class LOTStrokeData : public LOTData
440 LOTStrokeData():LOTData(LOTData::Type::Stroke){}
441 float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0;}
442 float width(int frameNo) const {return mWidth.value(frameNo);}
443 CapStyle capStyle() const {return mCapStyle;}
444 JoinStyle joinStyle() const {return mJoinStyle;}
445 float meterLimit() const{return mMeterLimit;}
446 bool hasDashInfo() const { return !(mDash.mDashCount == 0);}
447 int getDashInfo(int frameNo, float *array) const;
449 LOTAnimatable<LottieColor> mColor; /* "c" */
450 LOTAnimatable<int> mOpacity{100}; /* "o" */
451 LOTAnimatable<float> mWidth{0}; /* "w" */
452 CapStyle mCapStyle; /* "lc" */
453 JoinStyle mJoinStyle; /* "lj" */
454 float mMeterLimit{0}; /* "ml" */
455 LOTDashProperty mDash;
456 bool mEnabled{true}; /* "fillEnabled" */
462 friend inline LottieGradient operator+(const LottieGradient &g1, const LottieGradient &g2);
463 friend inline LottieGradient operator-(const LottieGradient &g1, const LottieGradient &g2);
464 friend inline LottieGradient operator*(float m, const LottieGradient &g);
466 std::vector<float> mGradient;
469 inline LottieGradient operator+(const LottieGradient &g1, const LottieGradient &g2)
471 if (g1.mGradient.size() != g2.mGradient.size())
475 newG.mGradient = g1.mGradient;
477 auto g2It = g2.mGradient.begin();
478 for(auto &i : newG.mGradient) {
486 inline LottieGradient operator-(const LottieGradient &g1, const LottieGradient &g2)
488 if (g1.mGradient.size() != g2.mGradient.size())
491 newG.mGradient = g1.mGradient;
493 auto g2It = g2.mGradient.begin();
494 for(auto &i : newG.mGradient) {
502 inline LottieGradient operator*(float m, const LottieGradient &g)
505 newG.mGradient = g.mGradient;
507 for(auto &i : newG.mGradient) {
515 class LOTGradient : public LOTData
518 LOTGradient(LOTData::Type type):LOTData(type){}
519 inline float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0;}
520 void update(std::unique_ptr<VGradient> &grad, int frameNo);
523 void populate(VGradientStops &stops, int frameNo);
525 int mGradientType; /* "t" Linear=1 , Radial = 2*/
526 LOTAnimatable<VPointF> mStartPoint; /* "s" */
527 LOTAnimatable<VPointF> mEndPoint; /* "e" */
528 LOTAnimatable<float> mHighlightLength{0}; /* "h" */
529 LOTAnimatable<float> mHighlightAngle{0}; /* "a" */
530 LOTAnimatable<int> mOpacity{0}; /* "o" */
531 LOTAnimatable<LottieGradient> mGradient; /* "g" */
532 int mColorPoints{-1};
533 bool mEnabled{true}; /* "fillEnabled" */
536 class LOTGFillData : public LOTGradient
539 LOTGFillData():LOTGradient(LOTData::Type::GFill){}
540 FillRule fillRule() const {return mFillRule;}
542 FillRule mFillRule{FillRule::Winding}; /* "r" */
545 class LOTGStrokeData : public LOTGradient
548 LOTGStrokeData():LOTGradient(LOTData::Type::GStroke){}
549 float width(int frameNo) const {return mWidth.value(frameNo);}
550 CapStyle capStyle() const {return mCapStyle;}
551 JoinStyle joinStyle() const {return mJoinStyle;}
552 float meterLimit() const{return mMeterLimit;}
553 bool hasDashInfo() const { return !(mDash.mDashCount == 0);}
554 int getDashInfo(int frameNo, float *array) const;
556 LOTAnimatable<float> mWidth; /* "w" */
557 CapStyle mCapStyle; /* "lc" */
558 JoinStyle mJoinStyle; /* "lj" */
559 float mMeterLimit{0}; /* "ml" */
560 LOTDashProperty mDash;
563 class LOTPath : public LOTData
566 LOTPath(LOTData::Type type):LOTData(type){}
567 VPath::Direction direction() { if (mDirection == 3) return VPath::Direction::CCW;
568 else return VPath::Direction::CW;}
573 class LOTShapeData : public LOTPath
576 LOTShapeData():LOTPath(LOTData::Type::Shape){}
579 LOTAnimatable<LottieShapeData> mShape;
592 float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0;}
593 bool isStatic() const {return mIsStatic;}
595 LOTAnimatable<LottieShapeData> mShape;
596 LOTAnimatable<float> mOpacity;
598 bool mIsStatic{true};
599 LOTMaskData::Mode mMode;
602 class LOTRectData : public LOTPath
605 LOTRectData():LOTPath(LOTData::Type::Rect){}
607 LOTAnimatable<VPointF> mPos;
608 LOTAnimatable<VPointF> mSize;
609 LOTAnimatable<float> mRound{0};
612 class LOTEllipseData : public LOTPath
615 LOTEllipseData():LOTPath(LOTData::Type::Ellipse){}
617 LOTAnimatable<VPointF> mPos;
618 LOTAnimatable<VPointF> mSize;
621 class LOTPolystarData : public LOTPath
624 enum class PolyType {
628 LOTPolystarData():LOTPath(LOTData::Type::Polystar){}
630 LOTPolystarData::PolyType mType{PolyType::Polygon};
631 LOTAnimatable<VPointF> mPos;
632 LOTAnimatable<float> mPointCount{0};
633 LOTAnimatable<float> mInnerRadius{0};
634 LOTAnimatable<float> mOuterRadius{0};
635 LOTAnimatable<float> mInnerRoundness{0};
636 LOTAnimatable<float> mOuterRoundness{0};
637 LOTAnimatable<float> mRotation{0};
640 class LOTTrimData : public LOTData
643 enum class TrimType {
647 LOTTrimData():LOTData(LOTData::Type::Trim){}
648 float start(int frameNo) const {return mStart.value(frameNo)/100.0f;}
649 float end(int frameNo) const {return mEnd.value(frameNo)/100.0f;}
650 float offset(int frameNo) const {return fmod(mOffset.value(frameNo), 360.0f)/ 360.0f;}
651 LOTTrimData::TrimType type() const {return mTrimType;}
653 LOTAnimatable<float> mStart{0};
654 LOTAnimatable<float> mEnd{0};
655 LOTAnimatable<float> mOffset{0};
656 LOTTrimData::TrimType mTrimType{TrimType::Simultaneously};
659 class LOTRepeaterData : public LOTGroupData
662 LOTRepeaterData():LOTGroupData(LOTData::Type::Repeater){}
664 LOTAnimatable<float> mCopies{0};
665 LOTAnimatable<float> mOffset{0};
671 bool isStatic() const {return mRoot->isStatic();}
672 double duration() const {return mRoot->duration();}
673 size_t frameDuration() const {return mRoot->frameDuration();}
674 size_t frameRate() const {return mRoot->frameRate();}
675 size_t startFrame() const {return mRoot->startFrame();}
676 size_t endFrame() const {return mRoot->endFrame();}
677 size_t frameAtPos(double pos) const {return mRoot->frameAtPos(pos);}
679 std::shared_ptr<LOTCompositionData> mRoot;