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;
38 virtual ~LOTDataVisitor() {}
39 virtual void visit(LOTCompositionData *) = 0;
40 virtual void visit(LOTLayerData *) = 0;
41 virtual void visit(LOTTransformData *) = 0;
42 virtual void visit(LOTShapeGroupData *) = 0;
43 virtual void visit(LOTShapeData *) = 0;
44 virtual void visit(LOTRectData *) = 0;
45 virtual void visit(LOTEllipseData *) = 0;
46 virtual void visit(LOTPolystarData *) {};
47 virtual void visit(LOTTrimData *) = 0;
48 virtual void visit(LOTRepeaterData *) = 0;
49 virtual void visit(LOTFillData *) = 0;
50 virtual void visit(LOTStrokeData *) = 0;
51 virtual void visit(LOTGFillData *){};
52 virtual void visit(LOTGStrokeData *){};
53 virtual void visitChildren(LOTGroupData *) = 0;
65 enum class LayerType {
77 LottieColor():r(1),g(1), b(1){}
78 LottieColor(float red, float green , float blue):r(red), g(green),b(blue){}
79 VColor toColor(float a=1){ return VColor((255 * r), (255 * g), (255 * b), (255 * a));}
80 friend inline LottieColor operator+(const LottieColor &c1, const LottieColor &c2);
81 friend inline LottieColor operator-(const LottieColor &c1, const LottieColor &c2);
88 inline LottieColor operator-(const LottieColor &c1, const LottieColor &c2)
90 return LottieColor(c1.r - c2.r, c1.g - c2.g, c1.b - c2.b);
92 inline LottieColor operator+(const LottieColor &c1, const LottieColor &c2)
94 return LottieColor(c1.r + c2.r, c1.g + c2.g, c1.b + c2.b);
97 inline const LottieColor operator*(const LottieColor &c, float m)
98 { return LottieColor(c.r*m, c.g*m, c.b*m); }
100 inline const LottieColor operator*(float m, const LottieColor &c)
101 { return LottieColor(c.r*m, c.g*m, c.b*m); }
103 class LottieShapeData
106 void reserve(int size) {
107 mPoints.reserve(mPoints.size() + size);
109 void toPath(VPath& path) {
112 if (mPoints.empty()) return;
114 int size = mPoints.size();
115 const VPointF *points = mPoints.data();
116 /* reserve exact memory requirement at once
117 * ptSize = size + 1(size + close)
118 * elmSize = size/3 cubic + 1 move + 1 close
120 path.reserve(size + 1 , size/3 + 2);
121 path.moveTo(points[0]);
122 for (int i = 1 ; i < size; i+=3) {
123 path.cubicTo(points[i], points[i+1], points[i+2]);
129 std::vector<VPointF> mPoints;
130 bool mClosed = false; /* "c" */
136 inline T lerp(const T& start, const T& end, float t)
138 return start + t * (end - start);
141 inline LottieShapeData lerp(const LottieShapeData& start, const LottieShapeData& end, float t)
143 if (start.mPoints.size() != start.mPoints.size())
144 return LottieShapeData();
146 LottieShapeData result;
147 result.reserve(start.mPoints.size());
148 for (unsigned int i = 0 ; i < start.mPoints.size(); i++) {
149 result.mPoints.push_back(start.mPoints[i] + t * (end.mPoints[i] - start.mPoints[i]));
154 template <typename T>
155 struct LOTKeyFrameValue
159 T value(float t) const {
160 return lerp(mStartValue, mEndValue, t);
165 struct LOTKeyFrameValue<VPointF>
171 bool mPathKeyFrame = false;
173 VPointF value(float t) const {
175 return VBezier::fromPoints(mStartValue, mStartValue + mOutTangent,
176 mEndValue + mInTangent, mEndValue).pointAt(t);
178 return lerp(mStartValue, mEndValue, t);
188 LOTKeyFrame(): mStartFrame(0),
190 mInterpolator(nullptr){}
192 T value(int frameNo) const {
193 float progress = mInterpolator->value(float(frameNo - mStartFrame) / float(mEndFrame - mStartFrame));
194 return mValue.value(progress);
200 std::shared_ptr<VInterpolator> mInterpolator;
201 LOTKeyFrameValue<T> mValue;
208 T value(int frameNo) const {
209 if (mKeyFrames.front().mStartFrame >= frameNo)
210 return mKeyFrames.front().mValue.mStartValue;
211 if(mKeyFrames.back().mEndFrame <= frameNo)
212 return mKeyFrames.back().mValue.mEndValue;
214 for(auto keyFrame : mKeyFrames) {
215 if (frameNo >= keyFrame.mStartFrame && frameNo < keyFrame.mEndFrame)
216 return keyFrame.value(frameNo);
221 std::vector<LOTKeyFrame<T>> mKeyFrames;
228 LOTAnimatable():mValue(),mAnimInfo(nullptr){}
229 LOTAnimatable(const T &value): mValue(value){}
230 bool isStatic() const {if (mAnimInfo) return false; else return true;}
231 T value(int frameNo) const{
235 return mAnimInfo->value(frameNo);
239 int mPropertyIndex; /* "ix" */
240 std::unique_ptr<LOTAnimInfo<T>> mAnimInfo;
243 enum class LottieBlendMode
251 class LOTDataVisitor;
271 LOTData(LOTData::Type type): mType(type){}
273 inline LOTData::Type type() const {return mType;}
274 virtual void accept(LOTDataVisitor *){}
275 bool isStatic() const{return mStatic;}
276 void setStatic(bool value) {mStatic = value;}
282 class LOTGroupData: public LOTData
285 LOTGroupData(LOTData::Type type):LOTData(type){}
287 std::vector<std::shared_ptr<LOTData>> mChildren;
288 std::shared_ptr<LOTTransformData> mTransform;
291 class LOTShapeGroupData : public LOTGroupData
294 LOTShapeGroupData():LOTGroupData(LOTData::Type::ShapeGroup){}
295 void accept(LOTDataVisitor *visitor) override
296 {visitor->visit(this); visitor->visitChildren(this);}
302 int mAssetType; //lottie asset type (precomp/char/image)
303 std::string mRefId; // ref id
304 std::vector<std::shared_ptr<LOTData>> mLayers;
307 class LOTLayerData : public LOTGroupData
310 LOTLayerData():LOTGroupData(LOTData::Type::Layer){}
311 bool hasPathOperator() const noexcept {return mHasPathOperator;}
312 bool hasGradient() const noexcept {return mHasGradient;}
313 bool hasMask() const noexcept {return mHasMask;}
314 bool hasRepeater() const noexcept {return mHasRepeater;}
315 bool root() const noexcept {return mRoot;}
316 int id() const noexcept{ return mId;}
317 int parentId() const noexcept{ return mParentId;}
318 int inFrame() const noexcept{return mInFrame;}
319 int outFrame() const noexcept{return mOutFrame;}
320 int startFrame() const noexcept{return mStartFrame;}
321 int solidWidth() const noexcept{return mSolidLayer.mWidth;}
322 int solidHeight() const noexcept{return mSolidLayer.mHeight;}
323 LottieColor solidColor() const noexcept{return mSolidLayer.mColor;}
324 void accept(LOTDataVisitor *visitor) override
325 {visitor->visit(this); visitor->visitChildren(this);}
333 MatteType mMatteType{MatteType::None};
335 LayerType mLayerType; //lottie layer type (solid/shape/precomp)
336 int mParentId{-1}; // Lottie the id of the parent in the composition
337 int mId{-1}; // Lottie the group id used for parenting.
341 LottieBlendMode mBlendMode;
342 float mTimeStreatch{1.0f};
343 std::string mPreCompRefId;
344 LOTAnimatable<float> mTimeRemap; /* "tm" */
345 SolidLayer mSolidLayer;
346 bool mHasPathOperator{false};
347 bool mHasMask{false};
348 bool mHasRepeater{false};
349 bool mHasGradient{false};
351 std::vector<std::shared_ptr<LOTMaskData>> mMasks;
354 class LOTCompositionData : public LOTData
357 LOTCompositionData():LOTData(LOTData::Type::Composition){}
358 long frameDuration() const {return mEndFrame - mStartFrame -1;}
359 float frameRate() const {return mFrameRate;}
360 long startFrame() const {return mStartFrame;}
361 long endFrame() const {return mEndFrame;}
362 VSize size() const {return mSize;}
363 void processRepeaterObjects();
364 void accept(LOTDataVisitor *visitor) override
365 {visitor->visit(this); mRootLayer->accept(visitor);}
367 std::string mVersion;
372 LottieBlendMode mBlendMode;
373 std::shared_ptr<LOTLayerData> mRootLayer;
374 std::unordered_map<std::string,
375 std::shared_ptr<VInterpolator>> mInterpolatorCache;
376 std::unordered_map<std::string,
377 std::shared_ptr<LOTAsset>> mAssets;
381 class LOTTransformData : public LOTData
384 LOTTransformData():LOTData(LOTData::Type::Transform),mScale({100, 100}){}
385 VMatrix matrix(int frameNo) const;
386 float opacity(int frameNo) const;
388 bool staticMatrix() const {return mStaticMatrix;}
389 void accept(LOTDataVisitor *visitor) final
390 {visitor->visit(this);}
392 VMatrix computeMatrix(int frameNo) const;
394 LOTAnimatable<float> mRotation{0}; /* "r" */
395 LOTAnimatable<VPointF> mScale; /* "s" */
396 LOTAnimatable<VPointF> mPosition; /* "p" */
397 LOTAnimatable<float> mX{0};
398 LOTAnimatable<float> mY{0};
399 LOTAnimatable<VPointF> mAnchor; /* "a" */
400 LOTAnimatable<float> mOpacity{100}; /* "o" */
401 LOTAnimatable<float> mSkew{0}; /* "sk" */
402 LOTAnimatable<float> mSkewAxis{0}; /* "sa" */
403 bool mStaticMatrix{true};
404 bool mSeparate{false};
405 VMatrix mCachedMatrix;
408 class LOTFillData : public LOTData
411 LOTFillData():LOTData(LOTData::Type::Fill){}
412 float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0;}
413 FillRule fillRule() const {return mFillRule;}
414 void accept(LOTDataVisitor *visitor) final
415 {visitor->visit(this);}
417 FillRule mFillRule{FillRule::Winding}; /* "r" */
418 LOTAnimatable<LottieColor> mColor; /* "c" */
419 LOTAnimatable<int> mOpacity{100}; /* "o" */
420 bool mEnabled{true}; /* "fillEnabled" */
423 struct LOTDashProperty
425 LOTAnimatable<float> mDashArray[5]; /* "d" "g" "o"*/
430 class LOTStrokeData : public LOTData
433 LOTStrokeData():LOTData(LOTData::Type::Stroke){}
434 float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0;}
435 float width(int frameNo) const {return mWidth.value(frameNo);}
436 CapStyle capStyle() const {return mCapStyle;}
437 JoinStyle joinStyle() const {return mJoinStyle;}
438 float meterLimit() const{return mMeterLimit;}
439 bool hasDashInfo() const { return !(mDash.mDashCount == 0);}
440 int getDashInfo(int frameNo, float *array) const;
441 void accept(LOTDataVisitor *visitor) final
442 {visitor->visit(this);}
444 LOTAnimatable<LottieColor> mColor; /* "c" */
445 LOTAnimatable<int> mOpacity{100}; /* "o" */
446 LOTAnimatable<float> mWidth{0}; /* "w" */
447 CapStyle mCapStyle; /* "lc" */
448 JoinStyle mJoinStyle; /* "lj" */
449 float mMeterLimit{0}; /* "ml" */
450 LOTDashProperty mDash;
451 bool mEnabled{true}; /* "fillEnabled" */
457 friend inline LottieGradient operator+(const LottieGradient &g1, const LottieGradient &g2);
458 friend inline LottieGradient operator-(const LottieGradient &g1, const LottieGradient &g2);
459 friend inline LottieGradient operator*(float m, const LottieGradient &g);
461 std::vector<float> mGradient;
464 inline LottieGradient operator+(const LottieGradient &g1, const LottieGradient &g2)
466 if (g1.mGradient.size() != g2.mGradient.size())
470 newG.mGradient = g1.mGradient;
472 auto g2It = g2.mGradient.begin();
473 for(auto &i : newG.mGradient) {
481 inline LottieGradient operator-(const LottieGradient &g1, const LottieGradient &g2)
483 if (g1.mGradient.size() != g2.mGradient.size())
486 newG.mGradient = g1.mGradient;
488 auto g2It = g2.mGradient.begin();
489 for(auto &i : newG.mGradient) {
497 inline LottieGradient operator*(float m, const LottieGradient &g)
500 newG.mGradient = g.mGradient;
502 for(auto &i : newG.mGradient) {
510 class LOTGradient : public LOTData
513 LOTGradient(LOTData::Type type):LOTData(type){}
514 inline float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0;}
515 void update(std::unique_ptr<VGradient> &grad, int frameNo);
518 void populate(VGradientStops &stops, int frameNo);
520 int mGradientType; /* "t" Linear=1 , Radial = 2*/
521 LOTAnimatable<VPointF> mStartPoint; /* "s" */
522 LOTAnimatable<VPointF> mEndPoint; /* "e" */
523 LOTAnimatable<float> mHighlightLength{0}; /* "h" */
524 LOTAnimatable<float> mHighlightAngle{0}; /* "a" */
525 LOTAnimatable<int> mOpacity{0}; /* "o" */
526 LOTAnimatable<LottieGradient> mGradient; /* "g" */
527 int mColorPoints{-1};
528 bool mEnabled{true}; /* "fillEnabled" */
531 class LOTGFillData : public LOTGradient
534 LOTGFillData():LOTGradient(LOTData::Type::GFill){}
535 FillRule fillRule() const {return mFillRule;}
536 void accept(LOTDataVisitor *visitor) final
537 {visitor->visit(this);}
539 FillRule mFillRule{FillRule::Winding}; /* "r" */
542 class LOTGStrokeData : public LOTGradient
545 LOTGStrokeData():LOTGradient(LOTData::Type::GStroke){}
546 float width(int frameNo) const {return mWidth.value(frameNo);}
547 CapStyle capStyle() const {return mCapStyle;}
548 JoinStyle joinStyle() const {return mJoinStyle;}
549 float meterLimit() const{return mMeterLimit;}
550 bool hasDashInfo() const { return !(mDash.mDashCount == 0);}
551 int getDashInfo(int frameNo, float *array) const;
552 void accept(LOTDataVisitor *visitor) final
553 {visitor->visit(this);}
555 LOTAnimatable<float> mWidth; /* "w" */
556 CapStyle mCapStyle; /* "lc" */
557 JoinStyle mJoinStyle; /* "lj" */
558 float mMeterLimit{0}; /* "ml" */
559 LOTDashProperty mDash;
562 class LOTPath : public LOTData
565 LOTPath(LOTData::Type type):LOTData(type){}
566 VPath::Direction direction() { if (mDirection == 3) return VPath::Direction::CCW;
567 else return VPath::Direction::CW;}
572 class LOTShapeData : public LOTPath
575 LOTShapeData():LOTPath(LOTData::Type::Shape){}
577 void accept(LOTDataVisitor *visitor) final
578 {visitor->visit(this);}
580 LOTAnimatable<LottieShapeData> mShape;
593 float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0;}
594 bool isStatic() const {return mIsStatic;}
596 LOTAnimatable<LottieShapeData> mShape;
597 LOTAnimatable<float> mOpacity;
599 bool mIsStatic{true};
600 LOTMaskData::Mode mMode;
603 class LOTRectData : public LOTPath
606 LOTRectData():LOTPath(LOTData::Type::Rect){}
607 void accept(LOTDataVisitor *visitor) final
608 {visitor->visit(this);}
610 LOTAnimatable<VPointF> mPos;
611 LOTAnimatable<VPointF> mSize;
612 LOTAnimatable<float> mRound{0};
615 class LOTEllipseData : public LOTPath
618 void accept(LOTDataVisitor *visitor) final
619 {visitor->visit(this);}
620 LOTEllipseData():LOTPath(LOTData::Type::Ellipse){}
622 LOTAnimatable<VPointF> mPos;
623 LOTAnimatable<VPointF> mSize;
626 class LOTPolystarData : public LOTPath
629 enum class PolyType {
633 LOTPolystarData():LOTPath(LOTData::Type::Polystar){}
634 void accept(LOTDataVisitor *visitor) final
635 {visitor->visit(this);}
637 LOTPolystarData::PolyType mType{PolyType::Polygon};
638 LOTAnimatable<VPointF> mPos;
639 LOTAnimatable<float> mPointCount{0};
640 LOTAnimatable<float> mInnerRadius{0};
641 LOTAnimatable<float> mOuterRadius{0};
642 LOTAnimatable<float> mInnerRoundness{0};
643 LOTAnimatable<float> mOuterRoundness{0};
644 LOTAnimatable<float> mRotation{0};
647 class LOTTrimData : public LOTData
650 enum class TrimType {
654 LOTTrimData():LOTData(LOTData::Type::Trim){}
655 void accept(LOTDataVisitor *visitor) final
656 {visitor->visit(this);}
657 float start(int frameNo) const {return mStart.value(frameNo)/100.0f;}
658 float end(int frameNo) const {return mEnd.value(frameNo)/100.0f;}
659 float offset(int frameNo) const {return mOffset.value(frameNo)/100.0f;}
660 LOTTrimData::TrimType type() const {return mTrimType;}
662 LOTAnimatable<float> mStart{0};
663 LOTAnimatable<float> mEnd{0};
664 LOTAnimatable<float> mOffset{0};
665 LOTTrimData::TrimType mTrimType{TrimType::Simultaneously};
668 class LOTRepeaterData : public LOTGroupData
671 LOTRepeaterData():LOTGroupData(LOTData::Type::Repeater){}
672 void accept(LOTDataVisitor *visitor) final
673 {visitor->visit(this); visitor->visitChildren(this);}
675 LOTAnimatable<float> mCopies{0};
676 LOTAnimatable<float> mOffset{0};
682 bool isStatic() const{return mRoot->isStatic();}
683 int frameDuration() {return mRoot->frameDuration();}
684 int frameRate() {return mRoot->frameRate();}
685 int startFrame() {return mRoot->startFrame();}
687 std::shared_ptr<LOTCompositionData> mRoot;