1 #include "lottieitem.h"
8 VDrawable::VDrawable():mFlag(DirtyState::All),
10 mFillRule(FillRule::Winding)
12 mStroke.dashArraySize = 0;
13 mStroke.cap = CapStyle::Round;
14 mStroke.join= JoinStyle::Round;
15 mStroke.meterLimit = 10;
16 mStroke.enable = false;
19 void VDrawable::preprocess()
21 if (mFlag & (DirtyState::Path)) {
23 VPath newPath = mPath;
24 if (mStroke.dashArraySize) {
25 VDasher dasher(mStroke.dashArray, mStroke.dashArraySize);
26 newPath = dasher.dashed(mPath);
28 mRleTask = VRaster::instance().generateStrokeInfo(mPath, mStroke.cap, mStroke.join,
29 mStroke.width, mStroke.meterLimit);
31 mRleTask = VRaster::instance().generateFillInfo(mPath, mFillRule);
33 mFlag &= ~DirtyFlag(DirtyState::Path);
39 if (mRleTask.valid()) {
40 mRle = std::move(mRleTask.get());
45 void VDrawable::setStrokeInfo(CapStyle cap, JoinStyle join, float meterLimit, float strokeWidth)
47 mStroke.enable = true;
50 mStroke.meterLimit = meterLimit;
51 mStroke.width = strokeWidth;
52 mFlag |= DirtyState::Path;
54 void VDrawable::setDashInfo(float *array, int size)
56 mStroke.dashArray = array;
57 mStroke.dashArraySize = size;
58 mFlag |= DirtyState::Path;
61 void VDrawable::sync()
63 mCNode.mFlag = ChangeFlagNone;
64 if (mFlag & DirtyState::None) return;
66 if (mFlag & DirtyState::Path) {
67 const std::vector<VPath::Element> &elm = mPath.elements();
68 const std::vector<VPointF> &pts = mPath.points();
69 const float *ptPtr = reinterpret_cast<const float *>(pts.data());
70 const char *elmPtr = reinterpret_cast<const char *>(elm.data());
71 mCNode.mPath.elmPtr = elmPtr;
72 mCNode.mPath.elmCount = elm.size();
73 mCNode.mPath.ptPtr = ptPtr;
74 mCNode.mPath.ptCount = 2 * pts.size();
75 mCNode.mFlag |= ChangeFlagPath;
79 mCNode.mStroke.width = mStroke.width;
80 mCNode.mStroke.meterLimit = mStroke.meterLimit;
81 mCNode.mStroke.enable = 1;
84 case FillRule::EvenOdd:
85 mCNode.mFillRule = LOTNode::EvenOdd;
88 mCNode.mFillRule = LOTNode::Winding;
92 switch (mStroke.cap) {
94 mCNode.mStroke.cap = LOTNode::FlatCap;
96 case CapStyle::Square:
97 mCNode.mStroke.cap = LOTNode::SquareCap;
100 mCNode.mStroke.cap = LOTNode::RoundCap;
103 mCNode.mStroke.cap = LOTNode::FlatCap;
107 switch (mStroke.join) {
108 case JoinStyle::Miter:
109 mCNode.mStroke.join = LOTNode::MiterJoin;
111 case JoinStyle::Bevel:
112 mCNode.mStroke.join = LOTNode::BevelJoin;
114 case JoinStyle::Round:
115 mCNode.mStroke.join = LOTNode::RoundJoin;
118 mCNode.mStroke.join = LOTNode::MiterJoin;
122 mCNode.mStroke.dashArray = mStroke.dashArray;
123 mCNode.mStroke.dashArraySize = mStroke.dashArraySize;
126 mCNode.mStroke.enable = 0;
129 switch (mBrush.type()) {
130 case VBrush::Type::Solid:
131 mCNode.mType = LOTNode::BrushSolid;
132 mCNode.mColor.r = mBrush.mColor.r;
133 mCNode.mColor.g = mBrush.mColor.g;
134 mCNode.mColor.b = mBrush.mColor.b;
135 mCNode.mColor.a = mBrush.mColor.a;
137 case VBrush::Type::LinearGradient:
138 mCNode.mType = LOTNode::BrushGradient;
139 mCNode.mGradient.type = LOTNode::Gradient::Linear;
140 mCNode.mGradient.start.x = mBrush.mGradient->linear.x1;
141 mCNode.mGradient.start.y = mBrush.mGradient->linear.y1;
142 mCNode.mGradient.end.x = mBrush.mGradient->linear.x2;
143 mCNode.mGradient.end.y = mBrush.mGradient->linear.y2;
145 case VBrush::Type::RadialGradient:
146 mCNode.mType = LOTNode::BrushGradient;
147 mCNode.mGradient.type = LOTNode::Gradient::Radial;
148 mCNode.mGradient.center.x = mBrush.mGradient->radial.cx;
149 mCNode.mGradient.center.y = mBrush.mGradient->radial.cy;
150 mCNode.mGradient.focal.x = mBrush.mGradient->radial.fx;
151 mCNode.mGradient.focal.y = mBrush.mGradient->radial.fy;
152 mCNode.mGradient.cradius = mBrush.mGradient->radial.cradius;
153 mCNode.mGradient.fradius = mBrush.mGradient->radial.fradius;
160 /* Lottie Layer Rules
161 * 1. time stretch is pre calculated and applied to all the properties of the lottilayer model and all its children
162 * 2. The frame property could be reversed using,time-reverse layer property in AE. which means (start frame > endFrame)
166 LOTCompItem::LOTCompItem(LOTModel *model):mRootModel(model), mUpdateViewBox(false),mCurFrameNo(-1)
168 // 1. build layer item list
169 mCompData = model->mRoot.get();
170 for(auto i : mCompData->mChildren) {
171 LOTLayerData *layerData = dynamic_cast<LOTLayerData *>(i.get());
173 LOTLayerItem *layerItem = LOTCompItem::createLayerItem(layerData);
175 mLayers.push_back(layerItem);
176 mLayerMap[layerItem->id()] = layerItem;
181 //2. update parent layer
182 for(auto i : mLayers) {
183 int id = i->parentId();
185 auto search = mLayerMap.find(id);
186 if (search != mLayerMap.end()) {
187 LOTLayerItem *parentLayer = search->second;
188 i->setParentLayer(parentLayer);
192 //3. update static property of each layer
193 for(auto i : mLayers) {
194 i->updateStaticProperty();
197 mViewSize = mCompData->size();
200 LOTCompItem::~LOTCompItem()
202 for(auto i : mLayers) {
208 LOTCompItem::createLayerItem(LOTLayerData *layerData)
210 switch(layerData->mLayerType) {
211 case LayerType::Precomp: {
212 return new LOTCompLayerItem(layerData);
215 case LayerType::Solid: {
216 return new LOTSolidLayerItem(layerData);
219 case LayerType::Shape: {
220 return new LOTShapeLayerItem(layerData);
223 case LayerType::Null: {
224 return new LOTNullLayerItem(layerData);
233 void LOTCompItem::resize(const VSize &size)
235 if (mViewSize == size) return;
237 mUpdateViewBox = true;
240 VSize LOTCompItem::size() const
245 bool LOTCompItem::update(int frameNo)
250 // check if cached frame is same as requested frame.
251 if (!mUpdateViewBox && (mCurFrameNo == frameNo)) return false;
253 sx = mViewSize.width() / float(mCompData->size().width());
254 sy = mViewSize.height() / float(mCompData->size().height());
255 float scale = fmin(sx, sy);
256 m.scale(scale, scale);
258 // update the layer from back to front
259 for (auto i = mLayers.rbegin(); i != mLayers.rend(); ++i) {
260 LOTLayerItem *layer = *i;
261 layer->update(frameNo, m, 1.0);
264 mCurFrameNo = frameNo;
265 mUpdateViewBox = false;
269 void LOTCompItem::buildRenderList()
271 mDrawableList.clear();
272 for (auto i = mLayers.rbegin(); i != mLayers.rend(); ++i) {
273 LOTLayerItem *layer = *i;
274 layer->renderList(mDrawableList);
278 for(auto i : mDrawableList) {
280 mRenderList.push_back(&i->mCNode);
284 const std::vector<LOTNode *>& LOTCompItem::renderList() const
289 bool LOTCompItem::render(const LOTBuffer &buffer)
291 VBitmap bitmap((uchar *)buffer.buffer, buffer.width, buffer.height,
292 buffer.bytesPerLine, VBitmap::Format::ARGB32_Premultiplied, nullptr, nullptr);
294 /* schedule all preprocess task for this frame at once.
296 for (auto &e : mDrawableList) {
300 VPainter painter(&bitmap);
302 for (auto i = mLayers.rbegin(); i != mLayers.rend(); ++i) {
303 LOTLayerItem *layer = *i;
304 layer->render(&painter, mask);
310 void LOTMaskItem::update(int frameNo, const VMatrix &parentMatrix,
311 float parentAlpha, const DirtyFlag &flag)
313 if (mData->mShape.isStatic()) {
314 if (mLocalPath.isEmpty()) {
315 mLocalPath = mData->mShape.value(frameNo).toPath();
318 mLocalPath = mData->mShape.value(frameNo).toPath();
320 float opacity = mData->opacity(frameNo);
321 opacity = opacity * parentAlpha;
322 mCombinedAlpha = opacity;
324 VPath path = mLocalPath;
325 path.transform(parentMatrix);
327 mRleTask = VRaster::instance().generateFillInfo(path);
330 VRle LOTMaskItem::rle()
332 if (mRleTask.valid()) {
333 mRle = std::move(mRleTask.get());
334 if (!vCompare(mCombinedAlpha, 1.0f))
335 mRle = mRle * (mCombinedAlpha * 255);
342 void LOTLayerItem::render(VPainter *painter, const VRle &inheritMask)
344 std::vector<VDrawable *> list;
346 VRle mask = inheritMask;
349 mask = maskRle(painter->clipBoundingRect());
351 mask = mask & inheritMask;
355 painter->setBrush(i->mBrush);
356 if (!mask.isEmpty()) {
357 VRle rle = i->rle() & mask;
358 painter->drawRle(VPoint(), rle);
360 painter->drawRle(VPoint(), i->rle());
365 VRle LOTLayerItem::maskRle(const VRect &clipRect)
369 for (auto &i : mMasks) {
370 switch (i->maskMode()) {
371 case LOTMaskData::Mode::Add: {
372 rle = rle + i->rle();
375 case LOTMaskData::Mode::Substarct: {
376 if (rle.isEmpty() && !clipRect.isEmpty())
377 rle = VRle::toRle(clipRect);
378 rle = rle - i->rle();
381 case LOTMaskData::Mode::Intersect: {
382 rle = rle & i->rle();
392 LOTLayerItem::LOTLayerItem(LOTLayerData *layerData):mLayerData(layerData),
393 mParentLayer(nullptr),
394 mPrecompLayer(nullptr),
395 mCombinedAlpha(0.0f),
397 mDirtyFlag(DirtyFlagBit::All)
399 if (mLayerData->mHasMask) {
400 for (auto i : mLayerData->mMasks) {
401 mMasks.push_back(std::make_unique<LOTMaskItem>(i.get()));
406 void LOTLayerItem::updateStaticProperty()
409 mParentLayer->updateStaticProperty();
411 mStatic = mLayerData->isStatic();
412 mStatic = mParentLayer ? (mStatic & mParentLayer->isStatic()) : mStatic;
413 mStatic = mPrecompLayer ? (mStatic & mPrecompLayer->isStatic()) : mStatic;
416 void LOTLayerItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha)
419 // 1. check if the layer is part of the current frame
420 if (!visible()) return;
422 // 2. calculate the parent matrix and alpha
423 VMatrix m = matrix(frameNo);
425 float alpha = parentAlpha * opacity(frameNo);
429 for (auto &i : mMasks)
430 i->update(frameNo, m, alpha, mDirtyFlag);
433 // 3. update the dirty flag based on the change
434 if (!mCombinedMatrix.fuzzyCompare(m)) {
435 mDirtyFlag |= DirtyFlagBit::Matrix;
437 if (!vCompare(mCombinedAlpha, alpha)) {
438 mDirtyFlag |= DirtyFlagBit::Alpha;
441 mCombinedAlpha = alpha;
443 // 4. if no parent property change and layer is static then nothing to do.
444 if ((flag() & DirtyFlagBit::None) && isStatic())
447 //5. update the content of the layer
450 //6. reset the dirty flag
451 mDirtyFlag = DirtyFlagBit::None;
455 LOTLayerItem::opacity(int frameNo) const
457 return mLayerData->mTransform->opacity(frameNo);
461 LOTLayerItem::matrix(int frameNo) const
464 return mLayerData->mTransform->matrix(frameNo) * mParentLayer->matrix(frameNo);
466 return mLayerData->mTransform->matrix(frameNo);
469 bool LOTLayerItem::visible() const
471 if (frameNo() >= mLayerData->inFrame() && frameNo() < mLayerData->outFrame())
479 LOTCompLayerItem::LOTCompLayerItem(LOTLayerData *layerModel):LOTLayerItem(layerModel)
481 for(auto i : mLayerData->mChildren) {
482 LOTLayerData *layerModel = dynamic_cast<LOTLayerData *>(i.get());
484 LOTLayerItem *layerItem = LOTCompItem::createLayerItem(layerModel);
486 mLayers.push_back(layerItem);
487 mLayerMap[layerItem->id()] = layerItem;
492 //2. update parent layer
493 for(auto i : mLayers) {
494 int id = i->parentId();
496 auto search = mLayerMap.find(id);
497 if (search != mLayerMap.end()) {
498 LOTLayerItem *parentLayer = search->second;
499 i->setParentLayer(parentLayer);
502 i->setPrecompLayer(this);
506 void LOTCompLayerItem::updateStaticProperty()
508 LOTLayerItem::updateStaticProperty();
510 for(auto i : mLayers) {
511 i->updateStaticProperty();
515 void LOTCompLayerItem::render(VPainter *painter, const VRle &inheritMask)
517 VRle mask = inheritMask;
521 mask = maskRle(painter->clipBoundingRect());
523 mask = mask & inheritMask;
526 for(auto i : mLayers) {
527 i->render(painter, mask);
531 LOTCompLayerItem::~LOTCompLayerItem()
533 for(auto i : mLayers) {
538 void LOTCompLayerItem::updateContent()
540 // update the layer from back to front
541 for (auto i = mLayers.rbegin(); i != mLayers.rend(); ++i) {
542 LOTLayerItem *layer = *i;
543 layer->update(frameNo(), combinedMatrix(), combinedAlpha());
547 void LOTCompLayerItem::renderList(std::vector<VDrawable *> &list)
549 if (!visible()) return;
551 // update the layer from back to front
552 for (auto i = mLayers.rbegin(); i != mLayers.rend(); ++i) {
553 LOTLayerItem *layer = *i;
554 layer->renderList(list);
558 LOTSolidLayerItem::LOTSolidLayerItem(LOTLayerData *layerData):LOTLayerItem(layerData)
563 void LOTSolidLayerItem::updateContent()
566 mRenderNode = std::make_unique<VDrawable>();
567 mRenderNode->mType = VDrawable::Type::Fill;
568 mRenderNode->mFlag |= VDrawable::DirtyState::All;
571 if (flag() & DirtyFlagBit::Matrix) {
573 path.addRect(VRectF(0, 0, mLayerData->solidWidth(), mLayerData->solidHeight()));
574 path.transform(combinedMatrix());
575 mRenderNode->mFlag |= VDrawable::DirtyState::Path;
576 mRenderNode->mPath = path;
578 if (flag() & DirtyFlagBit::Alpha) {
579 LottieColor color = mLayerData->solidColor();
580 VBrush brush(color.toColor(combinedAlpha()));
581 mRenderNode->setBrush(brush);
582 mRenderNode->mFlag |= VDrawable::DirtyState::Brush;
586 void LOTSolidLayerItem::renderList(std::vector<VDrawable *> &list)
588 if (!visible()) return;
590 list.push_back(mRenderNode.get());
593 LOTNullLayerItem::LOTNullLayerItem(LOTLayerData *layerData):LOTLayerItem(layerData)
597 void LOTNullLayerItem::updateContent()
603 LOTShapeLayerItem::LOTShapeLayerItem(LOTLayerData *layerData):LOTLayerItem(layerData)
605 mRoot = new LOTContentGroupItem(nullptr);
606 mRoot->addChildren(layerData);
607 mRoot->processPaintOperation();
608 if (layerData->hasPathOperator())
609 mRoot->processTrimOperation();
612 LOTShapeLayerItem::~LOTShapeLayerItem()
617 LOTContentItem * LOTShapeLayerItem::createContentItem(LOTData *contentData)
619 switch(contentData->type()) {
620 case LOTData::Type::ShapeGroup: {
621 return new LOTContentGroupItem(static_cast<LOTShapeGroupData *>(contentData));
624 case LOTData::Type::Rect: {
625 return new LOTRectItem(static_cast<LOTRectData *>(contentData));
628 case LOTData::Type::Ellipse: {
629 return new LOTEllipseItem(static_cast<LOTEllipseData *>(contentData));
632 case LOTData::Type::Shape: {
633 return new LOTShapeItem(static_cast<LOTShapeData *>(contentData));
636 case LOTData::Type::Polystar: {
637 return new LOTPolystarItem(static_cast<LOTPolystarData *>(contentData));
640 case LOTData::Type::Fill: {
641 return new LOTFillItem(static_cast<LOTFillData *>(contentData));
644 case LOTData::Type::GFill: {
645 return new LOTGFillItem(static_cast<LOTGFillData *>(contentData));
648 case LOTData::Type::Stroke: {
649 return new LOTStrokeItem(static_cast<LOTStrokeData *>(contentData));
652 case LOTData::Type::GStroke: {
653 return new LOTGStrokeItem(static_cast<LOTGStrokeData *>(contentData));
656 case LOTData::Type::Repeater: {
657 return new LOTRepeaterItem(static_cast<LOTRepeaterData *>(contentData));
660 case LOTData::Type::Trim: {
661 return new LOTTrimItem(static_cast<LOTTrimData *>(contentData));
670 void LOTShapeLayerItem::updateContent()
672 mRoot->update(frameNo(), combinedMatrix(), combinedAlpha(), flag());
675 void LOTShapeLayerItem::renderList(std::vector<VDrawable *> &list)
677 if (!visible()) return;
678 mRoot->renderList(list);
681 LOTContentGroupItem::LOTContentGroupItem(LOTShapeGroupData *data):mData(data)
686 void LOTContentGroupItem::addChildren(LOTGroupData *data)
690 for(auto i : data->mChildren) {
691 LOTData *data = i.get();
692 LOTContentItem *content = LOTShapeLayerItem::createContentItem(data);
694 mContents.push_back(content);
698 LOTContentGroupItem::~LOTContentGroupItem()
700 for(auto i : mContents) {
706 void LOTContentGroupItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
708 VMatrix m = parentMatrix;
709 float alpha = parentAlpha;
710 DirtyFlag newFlag = flag;
713 // update the matrix and the flag
714 if ((flag & DirtyFlagBit::Matrix) || !mData->mTransform->staticMatrix() ) {
715 newFlag |= DirtyFlagBit::Matrix;
717 m = mData->mTransform->matrix(frameNo);
719 alpha *= mData->mTransform->opacity(frameNo);
721 if (!vCompare(alpha, parentAlpha)) {
722 newFlag |= DirtyFlagBit::Alpha;
726 for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) {
727 (*i)->update(frameNo, m, alpha, newFlag);
731 void LOTContentGroupItem::renderList(std::vector<VDrawable *> &list)
733 for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) {
734 (*i)->renderList(list);
738 void LOTContentGroupItem::processPaintOperation()
740 std::vector<LOTPaintDataItem *> list;
741 paintOperationHelper(list);
744 void LOTContentGroupItem::paintOperationHelper(std::vector<LOTPaintDataItem *> &list)
746 int curOpCount = list.size();
747 for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) {
749 if (auto pathNode = dynamic_cast<LOTPathDataItem *>(child)) {
750 // the node is a path data node add the paint operation list to it.
751 pathNode->addPaintOperation(list, curOpCount);
752 } else if (auto paintNode = dynamic_cast<LOTPaintDataItem *>(child)) {
753 // add it to the paint operation list
754 list.push_back(paintNode);
755 } else if (auto groupNode = dynamic_cast<LOTContentGroupItem *>(child)) {
756 // update the groups node with current list
757 groupNode->paintOperationHelper(list);
760 list.erase(list.begin() + curOpCount, list.end());
763 void LOTPathDataItem::addPaintOperation(std::vector<LOTPaintDataItem *> &list, int externalCount)
765 for(auto paintItem : list) {
766 bool sameGroup = (externalCount-- > 0) ? false : true;
767 mNodeList.push_back(std::make_unique<VDrawable>());
768 mRenderList.push_back(LOTRenderNode(this, paintItem, mNodeList.back().get(), sameGroup));
772 void LOTContentGroupItem::processTrimOperation()
774 std::vector<LOTTrimItem *> list;
775 trimOperationHelper(list);
778 void LOTContentGroupItem::trimOperationHelper(std::vector<LOTTrimItem *> &list)
780 int curOpCount = list.size();
781 for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) {
783 if (auto pathNode = dynamic_cast<LOTPathDataItem *>(child)) {
784 // the node is a path data node add the trim operation list to it.
785 pathNode->addTrimOperation(list);
786 } else if (auto trimNode = dynamic_cast<LOTTrimItem *>(child)) {
787 // add it to the trim operation list
788 list.push_back(trimNode);
789 } else if (auto groupNode = dynamic_cast<LOTContentGroupItem *>(child)) {
790 // update the groups node with current list
791 groupNode->trimOperationHelper(list);
794 list.erase(list.begin() + curOpCount, list.end());
797 void LOTPathDataItem::addTrimOperation(std::vector<LOTTrimItem *> &list)
799 for(auto trimItem : list) {
800 mTrimNodeRefs.push_back(trimItem);
804 void LOTPathDataItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
808 mPathChanged = false;
809 mCombinedAlpha = parentAlpha;
811 // 1. update the local path if needed
812 if (!(mInit && mStaticPath)) {
813 mLocalPath = getPath(frameNo);
818 tempPath = mLocalPath;
820 // 2. apply path operation if needed
821 if (mTrimNodeRefs.size() > 0)
823 //TODO apply more than one trim path if necessary
825 float s = mTrimNodeRefs.front()->getStart(frameNo);
826 float e = mTrimNodeRefs.front()->getEnd(frameNo);
828 pm.setPath(mLocalPath);
831 tempPath = pm.getPath();
836 // 3. compute the final path with parentMatrix
838 if ((flag & DirtyFlagBit::Matrix) || mPathChanged) {
839 mFinalPath = tempPath;
840 mFinalPath.transform(parentMatrix);
844 // 2. update the rendernode list
845 for (const auto &i : mRenderList) {
846 i.drawable->mFlag = VDrawable::DirtyState::None;
847 i.paintNodeRef->updateRenderNode(i.pathNodeRef, i.drawable, i.sameGroup);
849 i.drawable->mPath = mFinalPath;
850 i.drawable->mFlag |= VDrawable::DirtyState::Path;
855 void LOTPathDataItem::renderList(std::vector<VDrawable *> &list)
857 for (const auto &i : mRenderList) {
858 list.push_back(i.drawable);
862 VPath LOTPathDataItem::path() const
868 LOTRectItem::LOTRectItem(LOTRectData *data):LOTPathDataItem(data->isStatic()),mData(data)
872 VPath LOTRectItem::getPath(int frameNo)
874 VPointF pos = mData->mPos.value(frameNo);
875 VPointF size = mData->mSize.value(frameNo);
876 float radius = mData->mRound.value(frameNo);
877 VRectF r(pos.x() - size.x()/2, pos.y() - size.y()/2, size.x(), size.y());
880 path.addRoundRect(r, radius, radius, mData->direction());
885 LOTEllipseItem::LOTEllipseItem(LOTEllipseData *data):LOTPathDataItem(data->isStatic()),mData(data)
890 VPath LOTEllipseItem::getPath(int frameNo)
892 VPointF pos = mData->mPos.value(frameNo);
893 VPointF size = mData->mSize.value(frameNo);
894 VRectF r(pos.x() - size.x()/2, pos.y() - size.y()/2, size.x(), size.y());
897 path.addOval(r, mData->direction());
902 LOTShapeItem::LOTShapeItem(LOTShapeData *data):LOTPathDataItem(data->isStatic()),mData(data)
907 VPath LOTShapeItem::getPath(int frameNo)
909 return mData->mShape.value(frameNo).toPath();
913 LOTPolystarItem::LOTPolystarItem(LOTPolystarData *data):LOTPathDataItem(data->isStatic()),mData(data)
918 VPath LOTPolystarItem::getPath(int frameNo)
920 VPointF pos = mData->mPos.value(frameNo);
921 float points = mData->mPointCount.value(frameNo);
922 float innerRadius = mData->mInnerRadius.value(frameNo);
923 float outerRadius = mData->mOuterRadius.value(frameNo);
924 float innerRoundness = mData->mInnerRoundness.value(frameNo);
925 float outerRoundness = mData->mOuterRoundness.value(frameNo);
926 float rotation = mData->mRotation.value(frameNo);
931 if (mData->mType == LOTPolystarData::PolyType::Star) {
932 path.addPolystar(points, innerRadius, outerRadius,
933 innerRoundness, outerRoundness,
934 0.0, 0.0, 0.0, mData->direction());
936 path.addPolygon(points, outerRadius, outerRoundness,
937 0.0, 0.0, 0.0, mData->direction());
940 m.translate(pos.x(), pos.y()).rotate(rotation);
950 * PaintData Node handling
954 void LOTPaintDataItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
956 mContentChanged = false;
957 mParentAlpha = parentAlpha;
958 mParentMatrix = parentMatrix;
961 // 1. update the local content if needed
962 // if (!(mInit && mStaticContent)) {
964 updateContent(frameNo);
965 mContentChanged = true;
970 LOTFillItem::LOTFillItem(LOTFillData *data):LOTPaintDataItem(data->isStatic()),mData(data)
974 void LOTFillItem::updateContent(int frameNo)
976 LottieColor c = mData->mColor.value(frameNo);
977 float opacity = mData->opacity(frameNo);
978 mColor = c.toColor(opacity);
979 mFillRule = mData->fillRule();
982 void LOTFillItem::updateRenderNode(LOTPathDataItem *pathNode, VDrawable *drawable, bool sameParent)
984 VColor color = mColor;
986 color.setAlpha(color.a * pathNode->combinedAlpha());
988 color.setAlpha(color.a * parentAlpha() * pathNode->combinedAlpha());
990 drawable->setBrush(brush);
991 drawable->setFillRule(mFillRule);
995 LOTGFillItem::LOTGFillItem(LOTGFillData *data):LOTPaintDataItem(data->isStatic()),mData(data)
999 void LOTGFillItem::updateContent(int frameNo)
1001 mData->update(mGradient, frameNo);
1002 mGradient->mMatrix = mParentMatrix;
1003 mFillRule = mData->fillRule();
1006 void LOTGFillItem::updateRenderNode(LOTPathDataItem *pathNode, VDrawable *drawable, bool sameParent)
1008 drawable->setBrush(VBrush(mGradient.get()));
1009 drawable->setFillRule(mFillRule);
1012 LOTStrokeItem::LOTStrokeItem(LOTStrokeData *data):LOTPaintDataItem(data->isStatic()),mData(data)
1017 void LOTStrokeItem::updateContent(int frameNo)
1019 LottieColor c = mData->mColor.value(frameNo);
1020 float opacity = mData->opacity(frameNo);
1021 mColor = c.toColor(opacity);
1022 mCap = mData->capStyle();
1023 mJoin = mData->joinStyle();
1024 mMiterLimit = mData->meterLimit();
1025 mWidth = mData->width(frameNo);
1026 if (mData->hasDashInfo()) {
1027 mDashArraySize = mData->getDashInfo(frameNo, mDashArray);
1031 static float getScale(const VMatrix &matrix)
1033 constexpr float SQRT_2 = 1.41421;
1035 VPointF p2(SQRT_2,SQRT_2);
1036 p1 = matrix.map(p1);
1037 p2 = matrix.map(p2);
1038 VPointF final = p2 - p1;
1040 return std::sqrt( final.x() * final.x() + final.y() * final.y());
1043 void LOTStrokeItem::updateRenderNode(LOTPathDataItem *pathNode, VDrawable *drawable, bool sameParent)
1045 VColor color = mColor;
1047 color.setAlpha(color.a * pathNode->combinedAlpha());
1049 color.setAlpha(color.a * parentAlpha() * pathNode->combinedAlpha());
1051 VBrush brush(color);
1052 drawable->setBrush(brush);
1054 drawable->setStrokeInfo(mCap, mJoin, mMiterLimit, mWidth * getScale(mParentMatrix));
1055 if (mDashArraySize) {
1056 drawable->setDashInfo(mDashArray, mDashArraySize);
1060 LOTGStrokeItem::LOTGStrokeItem(LOTGStrokeData *data):LOTPaintDataItem(data->isStatic()),mData(data)
1065 void LOTGStrokeItem::updateContent(int frameNo)
1067 mData->update(mGradient, frameNo);
1068 mGradient->mMatrix = mParentMatrix;
1069 mCap = mData->capStyle();
1070 mJoin = mData->joinStyle();
1071 mMiterLimit = mData->meterLimit();
1072 mWidth = mData->width(frameNo);
1073 if (mData->hasDashInfo()) {
1074 mDashArraySize = mData->getDashInfo(frameNo, mDashArray);
1078 void LOTGStrokeItem::updateRenderNode(LOTPathDataItem *pathNode, VDrawable *drawable, bool sameParent)
1080 drawable->setBrush(VBrush(mGradient.get()));
1081 drawable->setStrokeInfo(mCap, mJoin, mMiterLimit, mWidth * getScale(mParentMatrix));
1082 if (mDashArraySize) {
1083 drawable->setDashInfo(mDashArray, mDashArraySize);
1087 LOTTrimItem::LOTTrimItem(LOTTrimData *data):mData(data)
1091 void LOTTrimItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
1095 LOTRepeaterItem::LOTRepeaterItem(LOTRepeaterData *data):mData(data)
1100 void LOTRepeaterItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
1105 void LOTRepeaterItem::renderList(std::vector<VDrawable *> &list)