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) * parentMatrix;
424 float alpha = parentAlpha * opacity(frameNo);
428 for (auto &i : mMasks)
429 i->update(frameNo, m, alpha, mDirtyFlag);
432 // 3. update the dirty flag based on the change
433 if (!mCombinedMatrix.fuzzyCompare(m)) {
434 mDirtyFlag |= DirtyFlagBit::Matrix;
436 if (!vCompare(mCombinedAlpha, alpha)) {
437 mDirtyFlag |= DirtyFlagBit::Alpha;
440 mCombinedAlpha = alpha;
442 // 4. if no parent property change and layer is static then nothing to do.
443 if ((flag() & DirtyFlagBit::None) && isStatic())
446 //5. update the content of the layer
449 //6. reset the dirty flag
450 mDirtyFlag = DirtyFlagBit::None;
454 LOTLayerItem::opacity(int frameNo) const
456 return mLayerData->mTransform->opacity(frameNo);
460 LOTLayerItem::matrix(int frameNo) const
463 return mLayerData->mTransform->matrix(frameNo) * mParentLayer->matrix(frameNo);
465 return mLayerData->mTransform->matrix(frameNo);
468 bool LOTLayerItem::visible() const
470 if (frameNo() >= mLayerData->inFrame() && frameNo() < mLayerData->outFrame())
478 LOTCompLayerItem::LOTCompLayerItem(LOTLayerData *layerModel):LOTLayerItem(layerModel)
480 for(auto i : mLayerData->mChildren) {
481 LOTLayerData *layerModel = dynamic_cast<LOTLayerData *>(i.get());
483 LOTLayerItem *layerItem = LOTCompItem::createLayerItem(layerModel);
485 mLayers.push_back(layerItem);
486 mLayerMap[layerItem->id()] = layerItem;
491 //2. update parent layer
492 for(auto i : mLayers) {
493 int id = i->parentId();
495 auto search = mLayerMap.find(id);
496 if (search != mLayerMap.end()) {
497 LOTLayerItem *parentLayer = search->second;
498 i->setParentLayer(parentLayer);
501 i->setPrecompLayer(this);
505 void LOTCompLayerItem::updateStaticProperty()
507 LOTLayerItem::updateStaticProperty();
509 for(auto i : mLayers) {
510 i->updateStaticProperty();
514 void LOTCompLayerItem::render(VPainter *painter, const VRle &inheritMask)
516 VRle mask = inheritMask;
520 mask = maskRle(painter->clipBoundingRect());
522 mask = mask & inheritMask;
525 for(auto i : mLayers) {
526 i->render(painter, mask);
530 LOTCompLayerItem::~LOTCompLayerItem()
532 for(auto i : mLayers) {
537 void LOTCompLayerItem::updateContent()
539 // update the layer from back to front
540 for (auto i = mLayers.rbegin(); i != mLayers.rend(); ++i) {
541 LOTLayerItem *layer = *i;
542 layer->update(frameNo(), combinedMatrix(), combinedAlpha());
546 void LOTCompLayerItem::renderList(std::vector<VDrawable *> &list)
548 if (!visible()) return;
550 // update the layer from back to front
551 for (auto i = mLayers.rbegin(); i != mLayers.rend(); ++i) {
552 LOTLayerItem *layer = *i;
553 layer->renderList(list);
557 LOTSolidLayerItem::LOTSolidLayerItem(LOTLayerData *layerData):LOTLayerItem(layerData)
562 void LOTSolidLayerItem::updateContent()
565 mRenderNode = std::make_unique<VDrawable>();
566 mRenderNode->mType = VDrawable::Type::Fill;
567 mRenderNode->mFlag |= VDrawable::DirtyState::All;
570 if (flag() & DirtyFlagBit::Matrix) {
572 path.addRect(VRectF(0, 0, mLayerData->solidWidth(), mLayerData->solidHeight()));
573 path.transform(combinedMatrix());
574 mRenderNode->mFlag |= VDrawable::DirtyState::Path;
575 mRenderNode->mPath = path;
577 if (flag() & DirtyFlagBit::Alpha) {
578 LottieColor color = mLayerData->solidColor();
579 VBrush brush(color.toColor(combinedAlpha()));
580 mRenderNode->setBrush(brush);
581 mRenderNode->mFlag |= VDrawable::DirtyState::Brush;
585 void LOTSolidLayerItem::renderList(std::vector<VDrawable *> &list)
587 if (!visible()) return;
589 list.push_back(mRenderNode.get());
592 LOTNullLayerItem::LOTNullLayerItem(LOTLayerData *layerData):LOTLayerItem(layerData)
596 void LOTNullLayerItem::updateContent()
602 LOTShapeLayerItem::LOTShapeLayerItem(LOTLayerData *layerData):LOTLayerItem(layerData)
604 mRoot = new LOTContentGroupItem(nullptr);
605 mRoot->addChildren(layerData);
606 mRoot->processPaintOperation();
607 if (layerData->hasPathOperator())
608 mRoot->processTrimOperation();
611 LOTShapeLayerItem::~LOTShapeLayerItem()
616 LOTContentItem * LOTShapeLayerItem::createContentItem(LOTData *contentData)
618 switch(contentData->type()) {
619 case LOTData::Type::ShapeGroup: {
620 return new LOTContentGroupItem(static_cast<LOTShapeGroupData *>(contentData));
623 case LOTData::Type::Rect: {
624 return new LOTRectItem(static_cast<LOTRectData *>(contentData));
627 case LOTData::Type::Ellipse: {
628 return new LOTEllipseItem(static_cast<LOTEllipseData *>(contentData));
631 case LOTData::Type::Shape: {
632 return new LOTShapeItem(static_cast<LOTShapeData *>(contentData));
635 case LOTData::Type::Polystar: {
636 return new LOTPolystarItem(static_cast<LOTPolystarData *>(contentData));
639 case LOTData::Type::Fill: {
640 return new LOTFillItem(static_cast<LOTFillData *>(contentData));
643 case LOTData::Type::GFill: {
644 return new LOTGFillItem(static_cast<LOTGFillData *>(contentData));
647 case LOTData::Type::Stroke: {
648 return new LOTStrokeItem(static_cast<LOTStrokeData *>(contentData));
651 case LOTData::Type::GStroke: {
652 return new LOTGStrokeItem(static_cast<LOTGStrokeData *>(contentData));
655 case LOTData::Type::Repeater: {
656 return new LOTRepeaterItem(static_cast<LOTRepeaterData *>(contentData));
659 case LOTData::Type::Trim: {
660 return new LOTTrimItem(static_cast<LOTTrimData *>(contentData));
669 void LOTShapeLayerItem::updateContent()
671 mRoot->update(frameNo(), combinedMatrix(), combinedAlpha(), flag());
674 void LOTShapeLayerItem::renderList(std::vector<VDrawable *> &list)
676 if (!visible()) return;
677 mRoot->renderList(list);
680 LOTContentGroupItem::LOTContentGroupItem(LOTShapeGroupData *data):mData(data)
685 void LOTContentGroupItem::addChildren(LOTGroupData *data)
689 for(auto i : data->mChildren) {
690 LOTData *data = i.get();
691 LOTContentItem *content = LOTShapeLayerItem::createContentItem(data);
693 mContents.push_back(content);
697 LOTContentGroupItem::~LOTContentGroupItem()
699 for(auto i : mContents) {
705 void LOTContentGroupItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
707 VMatrix m = parentMatrix;
708 float alpha = parentAlpha;
709 DirtyFlag newFlag = flag;
712 // update the matrix and the flag
713 if ((flag & DirtyFlagBit::Matrix) || !mData->mTransform->staticMatrix() ) {
714 newFlag |= DirtyFlagBit::Matrix;
716 m = mData->mTransform->matrix(frameNo) * parentMatrix;
717 alpha *= mData->mTransform->opacity(frameNo);
719 if (!vCompare(alpha, parentAlpha)) {
720 newFlag |= DirtyFlagBit::Alpha;
724 for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) {
725 (*i)->update(frameNo, m, alpha, newFlag);
729 void LOTContentGroupItem::renderList(std::vector<VDrawable *> &list)
731 for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) {
732 (*i)->renderList(list);
736 void LOTContentGroupItem::processPaintOperation()
738 std::vector<LOTPaintDataItem *> list;
739 paintOperationHelper(list);
742 void LOTContentGroupItem::paintOperationHelper(std::vector<LOTPaintDataItem *> &list)
744 int curOpCount = list.size();
745 for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) {
747 if (auto pathNode = dynamic_cast<LOTPathDataItem *>(child)) {
748 // the node is a path data node add the paint operation list to it.
749 pathNode->addPaintOperation(list, curOpCount);
750 } else if (auto paintNode = dynamic_cast<LOTPaintDataItem *>(child)) {
751 // add it to the paint operation list
752 list.push_back(paintNode);
753 } else if (auto groupNode = dynamic_cast<LOTContentGroupItem *>(child)) {
754 // update the groups node with current list
755 groupNode->paintOperationHelper(list);
758 list.erase(list.begin() + curOpCount, list.end());
761 void LOTPathDataItem::addPaintOperation(std::vector<LOTPaintDataItem *> &list, int externalCount)
763 for(auto paintItem : list) {
764 bool sameGroup = (externalCount-- > 0) ? false : true;
765 mNodeList.push_back(std::make_unique<VDrawable>());
766 mRenderList.push_back(LOTRenderNode(this, paintItem, mNodeList.back().get(), sameGroup));
770 void LOTContentGroupItem::processTrimOperation()
772 std::vector<LOTTrimItem *> list;
773 trimOperationHelper(list);
776 void LOTContentGroupItem::trimOperationHelper(std::vector<LOTTrimItem *> &list)
778 int curOpCount = list.size();
779 for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) {
781 if (auto pathNode = dynamic_cast<LOTPathDataItem *>(child)) {
782 // the node is a path data node add the trim operation list to it.
783 pathNode->addTrimOperation(list);
784 } else if (auto trimNode = dynamic_cast<LOTTrimItem *>(child)) {
785 // add it to the trim operation list
786 list.push_back(trimNode);
787 } else if (auto groupNode = dynamic_cast<LOTContentGroupItem *>(child)) {
788 // update the groups node with current list
789 groupNode->trimOperationHelper(list);
792 list.erase(list.begin() + curOpCount, list.end());
795 void LOTPathDataItem::addTrimOperation(std::vector<LOTTrimItem *> &list)
797 for(auto trimItem : list) {
798 mTrimNodeRefs.push_back(trimItem);
802 void LOTPathDataItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
806 mPathChanged = false;
807 mCombinedAlpha = parentAlpha;
809 // 1. update the local path if needed
810 if (!(mInit && mStaticPath)) {
811 mLocalPath = getPath(frameNo);
816 tempPath = mLocalPath;
818 // 2. apply path operation if needed
819 if (mTrimNodeRefs.size() > 0)
821 //TODO apply more than one trim path if necessary
823 float s = mTrimNodeRefs.front()->getStart(frameNo);
824 float e = mTrimNodeRefs.front()->getEnd(frameNo);
826 pm.setPath(mLocalPath);
829 tempPath = pm.getPath();
834 // 3. compute the final path with parentMatrix
836 if ((flag & DirtyFlagBit::Matrix) || mPathChanged) {
837 mFinalPath = tempPath;
838 mFinalPath.transform(parentMatrix);
842 // 2. update the rendernode list
843 for (const auto &i : mRenderList) {
844 i.drawable->mFlag = VDrawable::DirtyState::None;
845 i.paintNodeRef->updateRenderNode(i.pathNodeRef, i.drawable, i.sameGroup);
847 i.drawable->mPath = mFinalPath;
848 i.drawable->mFlag |= VDrawable::DirtyState::Path;
853 void LOTPathDataItem::renderList(std::vector<VDrawable *> &list)
855 for (const auto &i : mRenderList) {
856 list.push_back(i.drawable);
860 VPath LOTPathDataItem::path() const
866 LOTRectItem::LOTRectItem(LOTRectData *data):LOTPathDataItem(data->isStatic()),mData(data)
870 VPath LOTRectItem::getPath(int frameNo)
872 VPointF pos = mData->mPos.value(frameNo);
873 VPointF size = mData->mSize.value(frameNo);
874 float radius = mData->mRound.value(frameNo);
875 VRectF r(pos.x() - size.x()/2, pos.y() - size.y()/2, size.x(), size.y());
878 path.addRoundRect(r, radius, radius, mData->direction());
883 LOTEllipseItem::LOTEllipseItem(LOTEllipseData *data):LOTPathDataItem(data->isStatic()),mData(data)
888 VPath LOTEllipseItem::getPath(int frameNo)
890 VPointF pos = mData->mPos.value(frameNo);
891 VPointF size = mData->mSize.value(frameNo);
892 VRectF r(pos.x() - size.x()/2, pos.y() - size.y()/2, size.x(), size.y());
895 path.addOval(r, mData->direction());
900 LOTShapeItem::LOTShapeItem(LOTShapeData *data):LOTPathDataItem(data->isStatic()),mData(data)
905 VPath LOTShapeItem::getPath(int frameNo)
907 LottieShapeData shapeData = mData->mShape.value(frameNo);
909 if (shapeData.mPoints.empty())
914 int size = shapeData.mPoints.size();
915 const VPointF *points = shapeData.mPoints.data();
916 path.moveTo(points[0]);
917 for (int i = 1 ; i < size; i+=3) {
918 path.cubicTo(points[i], points[i+1], points[i+2]);
920 if (shapeData.mClosed)
927 LOTPolystarItem::LOTPolystarItem(LOTPolystarData *data):LOTPathDataItem(data->isStatic()),mData(data)
932 VPath LOTPolystarItem::getPath(int frameNo)
934 VPointF pos = mData->mPos.value(frameNo);
935 float points = mData->mPointCount.value(frameNo);
936 float innerRadius = mData->mInnerRadius.value(frameNo);
937 float outerRadius = mData->mOuterRadius.value(frameNo);
938 float innerRoundness = mData->mInnerRoundness.value(frameNo);
939 float outerRoundness = mData->mOuterRoundness.value(frameNo);
940 float rotation = mData->mRotation.value(frameNo);
945 if (mData->mType == LOTPolystarData::PolyType::Star) {
946 path.addPolystar(points, innerRadius, outerRadius,
947 innerRoundness, outerRoundness,
948 0.0, 0.0, 0.0, mData->direction());
950 path.addPolygon(points, outerRadius, outerRoundness,
951 0.0, 0.0, 0.0, mData->direction());
954 m.translate(pos.x(), pos.y()).rotate(rotation);
964 * PaintData Node handling
968 void LOTPaintDataItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
970 mContentChanged = false;
971 mParentAlpha = parentAlpha;
972 mParentMatrix = parentMatrix;
975 // 1. update the local content if needed
976 // if (!(mInit && mStaticContent)) {
978 updateContent(frameNo);
979 mContentChanged = true;
984 LOTFillItem::LOTFillItem(LOTFillData *data):LOTPaintDataItem(data->isStatic()),mData(data)
988 void LOTFillItem::updateContent(int frameNo)
990 LottieColor c = mData->mColor.value(frameNo);
991 float opacity = mData->opacity(frameNo);
992 mColor = c.toColor(opacity);
993 mFillRule = mData->fillRule();
996 void LOTFillItem::updateRenderNode(LOTPathDataItem *pathNode, VDrawable *drawable, bool sameParent)
998 VColor color = mColor;
1000 color.setAlpha(color.a * pathNode->combinedAlpha());
1002 color.setAlpha(color.a * parentAlpha() * pathNode->combinedAlpha());
1003 VBrush brush(color);
1004 drawable->setBrush(brush);
1005 drawable->setFillRule(mFillRule);
1009 LOTGFillItem::LOTGFillItem(LOTGFillData *data):LOTPaintDataItem(data->isStatic()),mData(data)
1013 void LOTGFillItem::updateContent(int frameNo)
1015 mData->update(mGradient, frameNo);
1016 mGradient->mMatrix = mParentMatrix;
1017 mFillRule = mData->fillRule();
1020 void LOTGFillItem::updateRenderNode(LOTPathDataItem *pathNode, VDrawable *drawable, bool sameParent)
1022 drawable->setBrush(VBrush(mGradient.get()));
1023 drawable->setFillRule(mFillRule);
1026 LOTStrokeItem::LOTStrokeItem(LOTStrokeData *data):LOTPaintDataItem(data->isStatic()),mData(data)
1031 void LOTStrokeItem::updateContent(int frameNo)
1033 LottieColor c = mData->mColor.value(frameNo);
1034 float opacity = mData->opacity(frameNo);
1035 mColor = c.toColor(opacity);
1036 mCap = mData->capStyle();
1037 mJoin = mData->joinStyle();
1038 mMiterLimit = mData->meterLimit();
1039 mWidth = mData->width(frameNo);
1040 if (mData->hasDashInfo()) {
1041 mDashArraySize = mData->getDashInfo(frameNo, mDashArray);
1045 static float getScale(const VMatrix &matrix)
1047 constexpr float SQRT_2 = 1.41421;
1049 VPointF p2(SQRT_2,SQRT_2);
1050 p1 = matrix.map(p1);
1051 p2 = matrix.map(p2);
1052 VPointF final = p2 - p1;
1054 return std::sqrt( final.x() * final.x() + final.y() * final.y());
1057 void LOTStrokeItem::updateRenderNode(LOTPathDataItem *pathNode, VDrawable *drawable, bool sameParent)
1059 VColor color = mColor;
1061 color.setAlpha(color.a * pathNode->combinedAlpha());
1063 color.setAlpha(color.a * parentAlpha() * pathNode->combinedAlpha());
1065 VBrush brush(color);
1066 drawable->setBrush(brush);
1068 drawable->setStrokeInfo(mCap, mJoin, mMiterLimit, mWidth * getScale(mParentMatrix));
1069 if (mDashArraySize) {
1070 drawable->setDashInfo(mDashArray, mDashArraySize);
1074 LOTGStrokeItem::LOTGStrokeItem(LOTGStrokeData *data):LOTPaintDataItem(data->isStatic()),mData(data)
1079 void LOTGStrokeItem::updateContent(int frameNo)
1081 mData->update(mGradient, frameNo);
1082 mGradient->mMatrix = mParentMatrix;
1083 mCap = mData->capStyle();
1084 mJoin = mData->joinStyle();
1085 mMiterLimit = mData->meterLimit();
1086 mWidth = mData->width(frameNo);
1087 if (mData->hasDashInfo()) {
1088 mDashArraySize = mData->getDashInfo(frameNo, mDashArray);
1092 void LOTGStrokeItem::updateRenderNode(LOTPathDataItem *pathNode, VDrawable *drawable, bool sameParent)
1094 drawable->setBrush(VBrush(mGradient.get()));
1095 drawable->setStrokeInfo(mCap, mJoin, mMiterLimit, mWidth * getScale(mParentMatrix));
1096 if (mDashArraySize) {
1097 drawable->setDashInfo(mDashArray, mDashArraySize);
1101 LOTTrimItem::LOTTrimItem(LOTTrimData *data):mData(data)
1105 void LOTTrimItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
1109 LOTRepeaterItem::LOTRepeaterItem(LOTRepeaterData *data):mData(data)
1114 void LOTRepeaterItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
1119 void LOTRepeaterItem::renderList(std::vector<VDrawable *> &list)