1 #include "lottieitem.h"
9 VDrawable::VDrawable():mFlag(DirtyState::All),
11 mFillRule(FillRule::Winding)
13 mStroke.dashArraySize = 0;
14 mStroke.cap = CapStyle::Round;
15 mStroke.join= JoinStyle::Round;
16 mStroke.meterLimit = 10;
17 mStroke.enable = false;
20 void VDrawable::preprocess()
22 if (mFlag & (DirtyState::Path)) {
24 VPath newPath = mPath;
25 if (mStroke.dashArraySize) {
26 VDasher dasher(mStroke.dashArray, mStroke.dashArraySize);
27 newPath = dasher.dashed(mPath);
29 FTOutline *outline = VRaster::toFTOutline(newPath);
30 mRleTask = VRaster::instance().generateStrokeInfo(outline, mStroke.cap, mStroke.join,
31 mStroke.width, mStroke.meterLimit);
33 FTOutline *outline = VRaster::toFTOutline(mPath);
34 mRleTask = VRaster::instance().generateFillInfo(outline, mFillRule);
36 mFlag &= ~DirtyFlag(DirtyState::Path);
42 if (mRleTask.valid()) {
43 mRle = std::move(mRleTask.get());
48 void VDrawable::setStrokeInfo(CapStyle cap, JoinStyle join, float meterLimit, float strokeWidth)
50 mStroke.enable = true;
53 mStroke.meterLimit = meterLimit;
54 mStroke.width = strokeWidth;
55 mFlag |= DirtyState::Path;
57 void VDrawable::setDashInfo(float *array, int size)
59 mStroke.dashArray = array;
60 mStroke.dashArraySize = size;
61 mFlag |= DirtyState::Path;
64 void VDrawable::sync()
66 mCNode.mFlag = ChangeFlagNone;
67 if (mFlag & DirtyState::None) return;
69 if (mFlag & DirtyState::Path) {
70 const std::vector<VPath::Element> &elm = mPath.elements();
71 const std::vector<VPointF> &pts = mPath.points();
72 const float *ptPtr = reinterpret_cast<const float *>(pts.data());
73 const char *elmPtr = reinterpret_cast<const char *>(elm.data());
74 mCNode.mPath.elmPtr = elmPtr;
75 mCNode.mPath.elmCount = elm.size();
76 mCNode.mPath.ptPtr = ptPtr;
77 mCNode.mPath.ptCount = 2 * pts.size();
78 mCNode.mFlag |= ChangeFlagPath;
82 mCNode.mStroke.width = mStroke.width;
83 mCNode.mStroke.meterLimit = mStroke.meterLimit;
84 mCNode.mStroke.enable = 1;
87 case FillRule::EvenOdd:
88 mCNode.mFillRule = LOTNode::EvenOdd;
91 mCNode.mFillRule = LOTNode::Winding;
95 switch (mStroke.cap) {
97 mCNode.mStroke.cap = LOTNode::FlatCap;
99 case CapStyle::Square:
100 mCNode.mStroke.cap = LOTNode::SquareCap;
102 case CapStyle::Round:
103 mCNode.mStroke.cap = LOTNode::RoundCap;
106 mCNode.mStroke.cap = LOTNode::FlatCap;
110 switch (mStroke.join) {
111 case JoinStyle::Miter:
112 mCNode.mStroke.join = LOTNode::MiterJoin;
114 case JoinStyle::Bevel:
115 mCNode.mStroke.join = LOTNode::BevelJoin;
117 case JoinStyle::Round:
118 mCNode.mStroke.join = LOTNode::RoundJoin;
121 mCNode.mStroke.join = LOTNode::MiterJoin;
125 mCNode.mStroke.dashArray = mStroke.dashArray;
126 mCNode.mStroke.dashArraySize = mStroke.dashArraySize;
129 mCNode.mStroke.enable = 0;
132 switch (mBrush.type()) {
133 case VBrush::Type::Solid:
134 mCNode.mType = LOTNode::BrushSolid;
135 mCNode.mColor.r = mBrush.mColor.r;
136 mCNode.mColor.g = mBrush.mColor.g;
137 mCNode.mColor.b = mBrush.mColor.b;
138 mCNode.mColor.a = mBrush.mColor.a;
140 case VBrush::Type::LinearGradient:
141 mCNode.mType = LOTNode::BrushGradient;
142 mCNode.mGradient.type = LOTNode::Gradient::Linear;
143 mCNode.mGradient.start.x = mBrush.mGradient->linear.x1;
144 mCNode.mGradient.start.y = mBrush.mGradient->linear.y1;
145 mCNode.mGradient.end.x = mBrush.mGradient->linear.x2;
146 mCNode.mGradient.end.y = mBrush.mGradient->linear.y2;
148 case VBrush::Type::RadialGradient:
149 mCNode.mType = LOTNode::BrushGradient;
150 mCNode.mGradient.type = LOTNode::Gradient::Radial;
151 mCNode.mGradient.center.x = mBrush.mGradient->radial.cx;
152 mCNode.mGradient.center.y = mBrush.mGradient->radial.cy;
153 mCNode.mGradient.focal.x = mBrush.mGradient->radial.fx;
154 mCNode.mGradient.focal.y = mBrush.mGradient->radial.fy;
155 mCNode.mGradient.cradius = mBrush.mGradient->radial.cradius;
156 mCNode.mGradient.fradius = mBrush.mGradient->radial.fradius;
163 /* Lottie Layer Rules
164 * 1. time stretch is pre calculated and applied to all the properties of the lottilayer model and all its children
165 * 2. The frame property could be reversed using,time-reverse layer property in AE. which means (start frame > endFrame)
169 LOTCompItem::LOTCompItem(LOTModel *model):mRootModel(model), mUpdateViewBox(false),mCurFrameNo(-1)
171 // 1. build layer item list
172 mCompData = model->mRoot.get();
173 for(auto i : mCompData->mChildren) {
174 LOTLayerData *layerData = dynamic_cast<LOTLayerData *>(i.get());
176 LOTLayerItem *layerItem = LOTCompItem::createLayerItem(layerData);
178 mLayers.push_back(layerItem);
179 mLayerMap[layerItem->id()] = layerItem;
184 //2. update parent layer
185 for(auto i : mLayers) {
186 int id = i->parentId();
188 auto search = mLayerMap.find(id);
189 if (search != mLayerMap.end()) {
190 LOTLayerItem *parentLayer = search->second;
191 i->setParentLayer(parentLayer);
195 //3. update static property of each layer
196 for(auto i : mLayers) {
197 i->updateStaticProperty();
200 mViewSize = mCompData->size();
203 LOTCompItem::~LOTCompItem()
205 for(auto i : mLayers) {
211 LOTCompItem::createLayerItem(LOTLayerData *layerData)
213 switch(layerData->mLayerType) {
214 case LayerType::Precomp: {
215 return new LOTCompLayerItem(layerData);
218 case LayerType::Solid: {
219 return new LOTSolidLayerItem(layerData);
222 case LayerType::Shape: {
223 return new LOTShapeLayerItem(layerData);
226 case LayerType::Null: {
227 return new LOTNullLayerItem(layerData);
236 void LOTCompItem::resize(const VSize &size)
238 if (mViewSize == size) return;
240 mUpdateViewBox = true;
243 VSize LOTCompItem::size() const
248 bool LOTCompItem::update(int frameNo)
253 // check if cached frame is same as requested frame.
254 if (!mUpdateViewBox && (mCurFrameNo == frameNo)) return false;
256 sx = mViewSize.width() / float(mCompData->size().width());
257 sy = mViewSize.height() / float(mCompData->size().height());
258 float scale = fmin(sx, sy);
259 m.scale(scale, scale);
261 // update the layer from back to front
262 for (auto i = mLayers.rbegin(); i != mLayers.rend(); ++i) {
263 LOTLayerItem *layer = *i;
264 layer->update(frameNo, m, 1.0);
267 mCurFrameNo = frameNo;
268 mUpdateViewBox = false;
272 void LOTCompItem::buildRenderList()
275 std::vector<VDrawable *> list;
276 for (auto i = mLayers.rbegin(); i != mLayers.rend(); ++i) {
277 LOTLayerItem *layer = *i;
278 layer->renderList(list);
283 mRenderList.push_back(&i->mCNode);
287 const std::vector<LOTNode *>& LOTCompItem::renderList() const
292 bool LOTCompItem::render(const LOTBuffer &buffer)
294 VBitmap bitmap((uchar *)buffer.buffer, buffer.width, buffer.height,
295 buffer.bytesPerLine, VBitmap::Format::ARGB32_Premultiplied, nullptr, nullptr);
297 VPainter painter(&bitmap);
299 for (auto i = mLayers.rbegin(); i != mLayers.rend(); ++i) {
300 LOTLayerItem *layer = *i;
301 layer->render(&painter, mask);
307 void LOTMaskItem::update(int frameNo, const VMatrix &parentMatrix,
308 float parentAlpha, const DirtyFlag &flag)
310 if (mData->mShape.isStatic()) {
311 if (mLocalPath.isEmpty()) {
312 mLocalPath = mData->mShape.value(frameNo).toPath();
315 mLocalPath = mData->mShape.value(frameNo).toPath();
317 float opacity = mData->opacity(frameNo);
318 opacity = opacity * parentAlpha;
319 mCombinedAlpha = opacity;
321 VPath path = mLocalPath;
322 path.transform(parentMatrix);
324 FTOutline *outline = VRaster::toFTOutline(path);
325 mRleTask = VRaster::instance().generateFillInfo(outline);
328 VRle LOTMaskItem::rle()
330 if (mRleTask.valid()) {
331 mRle = std::move(mRleTask.get());
332 if (!vCompare(mCombinedAlpha, 1.0f))
333 mRle = mRle * (mCombinedAlpha * 255);
340 void LOTLayerItem::render(VPainter *painter, const VRle &inheritMask)
342 std::vector<VDrawable *> list;
344 VRle mask = inheritMask;
347 mask = maskRle(painter->clipBoundingRect());
349 mask = mask & inheritMask;
352 // do preprocessing first to take advantage of thread pool.
358 painter->setBrush(i->mBrush);
359 if (!mask.isEmpty()) {
360 VRle rle = i->rle() & mask;
361 painter->drawRle(VPoint(), rle);
363 painter->drawRle(VPoint(), i->rle());
368 VRle LOTLayerItem::maskRle(const VRect &clipRect)
372 for (auto &i : mMasks) {
373 switch (i->maskMode()) {
374 case LOTMaskData::Mode::Add: {
375 rle = rle + i->rle();
378 case LOTMaskData::Mode::Substarct: {
379 if (rle.isEmpty() && !clipRect.isEmpty())
380 rle = VRle::toRle(clipRect);
381 rle = rle - i->rle();
384 case LOTMaskData::Mode::Intersect: {
385 rle = rle & i->rle();
395 LOTLayerItem::LOTLayerItem(LOTLayerData *layerData):mLayerData(layerData),
396 mParentLayer(nullptr),
397 mPrecompLayer(nullptr),
398 mCombinedAlpha(0.0f),
400 mDirtyFlag(DirtyFlagBit::All)
402 if (mLayerData->mHasMask) {
403 for (auto i : mLayerData->mMasks) {
404 mMasks.push_back(std::unique_ptr<LOTMaskItem>(new LOTMaskItem(i.get())));
409 void LOTLayerItem::updateStaticProperty()
412 mParentLayer->updateStaticProperty();
414 mStatic = mLayerData->isStatic();
415 mStatic = mParentLayer ? (mStatic & mParentLayer->isStatic()) : mStatic;
416 mStatic = mPrecompLayer ? (mStatic & mPrecompLayer->isStatic()) : mStatic;
419 void LOTLayerItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha)
422 // 1. check if the layer is part of the current frame
423 if (!visible()) return;
425 // 2. calculate the parent matrix and alpha
426 VMatrix m = matrix(frameNo) * parentMatrix;
427 float alpha = parentAlpha * opacity(frameNo);
431 for (auto &i : mMasks)
432 i->update(frameNo, m, alpha, mDirtyFlag);
435 // 3. update the dirty flag based on the change
436 if (!mCombinedMatrix.fuzzyCompare(m)) {
437 mDirtyFlag |= DirtyFlagBit::Matrix;
439 if (!vCompare(mCombinedAlpha, alpha)) {
440 mDirtyFlag |= DirtyFlagBit::Alpha;
443 mCombinedAlpha = alpha;
445 // 4. if no parent property change and layer is static then nothing to do.
446 if ((flag() & DirtyFlagBit::None) && isStatic())
449 //5. update the content of the layer
452 //6. reset the dirty flag
453 mDirtyFlag = DirtyFlagBit::None;
457 LOTLayerItem::opacity(int frameNo) const
459 return mLayerData->mTransform->opacity(frameNo);
463 LOTLayerItem::matrix(int frameNo) const
466 return mLayerData->mTransform->matrix(frameNo) * mParentLayer->matrix(frameNo);
468 return mLayerData->mTransform->matrix(frameNo);
471 bool LOTLayerItem::visible() const
473 if (frameNo() >= mLayerData->inFrame() && frameNo() < mLayerData->outFrame())
481 LOTCompLayerItem::LOTCompLayerItem(LOTLayerData *layerModel):LOTLayerItem(layerModel)
483 for(auto i : mLayerData->mChildren) {
484 LOTLayerData *layerModel = dynamic_cast<LOTLayerData *>(i.get());
486 LOTLayerItem *layerItem = LOTCompItem::createLayerItem(layerModel);
488 mLayers.push_back(layerItem);
489 mLayerMap[layerItem->id()] = layerItem;
494 //2. update parent layer
495 for(auto i : mLayers) {
496 int id = i->parentId();
498 auto search = mLayerMap.find(id);
499 if (search != mLayerMap.end()) {
500 LOTLayerItem *parentLayer = search->second;
501 i->setParentLayer(parentLayer);
504 i->setPrecompLayer(this);
508 void LOTCompLayerItem::updateStaticProperty()
510 LOTLayerItem::updateStaticProperty();
512 for(auto i : mLayers) {
513 i->updateStaticProperty();
517 void LOTCompLayerItem::render(VPainter *painter, const VRle &inheritMask)
519 VRle mask = inheritMask;
523 mask = maskRle(painter->clipBoundingRect());
525 mask = mask & inheritMask;
528 for(auto i : mLayers) {
529 i->render(painter, mask);
533 LOTCompLayerItem::~LOTCompLayerItem()
535 for(auto i : mLayers) {
540 void LOTCompLayerItem::updateContent()
542 // update the layer from back to front
543 for (auto i = mLayers.rbegin(); i != mLayers.rend(); ++i) {
544 LOTLayerItem *layer = *i;
545 layer->update(frameNo(), combinedMatrix(), combinedAlpha());
549 void LOTCompLayerItem::renderList(std::vector<VDrawable *> &list)
551 if (!visible()) return;
553 // update the layer from back to front
554 for (auto i = mLayers.rbegin(); i != mLayers.rend(); ++i) {
555 LOTLayerItem *layer = *i;
556 layer->renderList(list);
560 LOTSolidLayerItem::LOTSolidLayerItem(LOTLayerData *layerData):LOTLayerItem(layerData)
565 void LOTSolidLayerItem::updateContent()
568 mRenderNode = std::unique_ptr<VDrawable>(new VDrawable());
569 mRenderNode->mType = VDrawable::Type::Fill;
570 mRenderNode->mFlag |= VDrawable::DirtyState::All;
573 if (flag() & DirtyFlagBit::Matrix) {
575 path.addRect(VRectF(0, 0, mLayerData->solidWidth(), mLayerData->solidHeight()));
576 path.transform(combinedMatrix());
577 mRenderNode->mFlag |= VDrawable::DirtyState::Path;
578 mRenderNode->mPath = path;
580 if (flag() & DirtyFlagBit::Alpha) {
581 LottieColor color = mLayerData->solidColor();
582 VBrush brush(color.toColor(combinedAlpha()));
583 mRenderNode->setBrush(brush);
584 mRenderNode->mFlag |= VDrawable::DirtyState::Brush;
588 void LOTSolidLayerItem::renderList(std::vector<VDrawable *> &list)
590 if (!visible()) return;
592 list.push_back(mRenderNode.get());
595 LOTNullLayerItem::LOTNullLayerItem(LOTLayerData *layerData):LOTLayerItem(layerData)
599 void LOTNullLayerItem::updateContent()
605 LOTShapeLayerItem::LOTShapeLayerItem(LOTLayerData *layerData):LOTLayerItem(layerData)
607 mRoot = new LOTContentGroupItem(nullptr);
608 mRoot->addChildren(layerData);
609 mRoot->processPaintOperation();
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));
666 void LOTShapeLayerItem::updateContent()
668 mRoot->update(frameNo(), combinedMatrix(), combinedAlpha(), flag());
671 void LOTShapeLayerItem::renderList(std::vector<VDrawable *> &list)
673 if (!visible()) return;
674 mRoot->renderList(list);
677 LOTContentGroupItem::LOTContentGroupItem(LOTShapeGroupData *data):mData(data)
682 void LOTContentGroupItem::addChildren(LOTGroupData *data)
686 for(auto i : data->mChildren) {
687 LOTData *data = i.get();
688 LOTContentItem *content = LOTShapeLayerItem::createContentItem(data);
690 mContents.push_back(content);
694 LOTContentGroupItem::~LOTContentGroupItem()
696 for(auto i : mContents) {
702 void LOTContentGroupItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
704 VMatrix m = parentMatrix;
705 float alpha = parentAlpha;
706 DirtyFlag newFlag = flag;
709 // update the matrix and the flag
710 if ((flag & DirtyFlagBit::Matrix) || !mData->mTransform->staticMatrix() ) {
711 newFlag |= DirtyFlagBit::Matrix;
713 m = mData->mTransform->matrix(frameNo) * parentMatrix;
714 alpha *= mData->mTransform->opacity(frameNo);
716 if (!vCompare(alpha, parentAlpha)) {
717 newFlag |= DirtyFlagBit::Alpha;
721 for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) {
722 (*i)->update(frameNo, m, alpha, newFlag);
726 void LOTContentGroupItem::renderList(std::vector<VDrawable *> &list)
728 for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) {
729 (*i)->renderList(list);
733 void LOTContentGroupItem::processPaintOperation()
735 std::vector<LOTPaintDataItem *> list;
736 paintOperationHelper(list);
739 void LOTContentGroupItem::paintOperationHelper(std::vector<LOTPaintDataItem *> &list)
741 int curOpCount = list.size();
742 for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) {
744 if (auto pathNode = dynamic_cast<LOTPathDataItem *>(child)) {
745 // the node is a path data node add the paint operation list to it.
746 pathNode->addPaintOperation(list, curOpCount);
747 } else if (auto paintNode = dynamic_cast<LOTPaintDataItem *>(child)) {
748 // add it to the paint operation list
749 list.push_back(paintNode);
750 } else if (auto groupNode = dynamic_cast<LOTContentGroupItem *>(child)) {
751 // update the groups node with current list
752 groupNode->paintOperationHelper(list);
755 list.erase(list.begin() + curOpCount, list.end());
758 void LOTPathDataItem::addPaintOperation(std::vector<LOTPaintDataItem *> &list, int externalCount)
760 for(auto paintItem : list) {
761 bool sameGroup = (externalCount-- > 0) ? false : true;
762 mNodeList.push_back(std::unique_ptr<VDrawable>(new VDrawable()));
763 mRenderList.push_back(LOTRenderNode(this, paintItem, mNodeList.back().get(), sameGroup));
768 void LOTPathDataItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
770 mPathChanged = false;
771 mCombinedAlpha = parentAlpha;
773 // 1. update the local path if needed
774 if (!(mInit && mStaticPath)) {
775 mLocalPath = getPath(frameNo);
780 // 2. apply path operation if needed
783 // 3. compute the final path with parentMatrix
784 if ((flag & DirtyFlagBit::Matrix) || mPathChanged) {
785 mFinalPath = mLocalPath;
786 mFinalPath.transform(parentMatrix);
790 // 2. update the rendernode list
791 for (const auto &i : mRenderList) {
792 i.drawable->mFlag = VDrawable::DirtyState::None;
793 i.paintNodeRef->updateRenderNode(i.pathNodeRef, i.drawable, i.sameGroup);
795 i.drawable->mPath = mFinalPath;
796 i.drawable->mFlag |= VDrawable::DirtyState::Path;
801 void LOTPathDataItem::renderList(std::vector<VDrawable *> &list)
803 for (const auto &i : mRenderList) {
804 list.push_back(i.drawable);
808 VPath LOTPathDataItem::path() const
814 LOTRectItem::LOTRectItem(LOTRectData *data):LOTPathDataItem(data->isStatic()),mData(data)
818 VPath LOTRectItem::getPath(int frameNo)
820 VPointF pos = mData->mPos.value(frameNo);
821 VPointF size = mData->mSize.value(frameNo);
822 float radius = mData->mRound.value(frameNo);
823 VRectF r(pos.x() - size.x()/2, pos.y() - size.y()/2, size.x(), size.y());
826 path.addRoundRect(r, radius, radius, mData->direction());
831 LOTEllipseItem::LOTEllipseItem(LOTEllipseData *data):LOTPathDataItem(data->isStatic()),mData(data)
836 VPath LOTEllipseItem::getPath(int frameNo)
838 VPointF pos = mData->mPos.value(frameNo);
839 VPointF size = mData->mSize.value(frameNo);
840 VRectF r(pos.x() - size.x()/2, pos.y() - size.y()/2, size.x(), size.y());
843 path.addOval(r, mData->direction());
848 LOTShapeItem::LOTShapeItem(LOTShapeData *data):LOTPathDataItem(data->isStatic()),mData(data)
853 VPath LOTShapeItem::getPath(int frameNo)
855 LottieShapeData shapeData = mData->mShape.value(frameNo);
857 if (shapeData.mPoints.empty())
862 int size = shapeData.mPoints.size();
863 const VPointF *points = shapeData.mPoints.data();
864 path.moveTo(points[0]);
865 for (int i = 1 ; i < size; i+=3) {
866 path.cubicTo(points[i], points[i+1], points[i+2]);
868 if (shapeData.mClosed)
875 LOTPolystarItem::LOTPolystarItem(LOTPolystarData *data):LOTPathDataItem(data->isStatic()),mData(data)
880 VPath LOTPolystarItem::getPath(int frameNo)
882 VPointF pos = mData->mPos.value(frameNo);
883 float points = mData->mPointCount.value(frameNo);
884 float innerRadius = mData->mInnerRadius.value(frameNo);
885 float outerRadius = mData->mOuterRadius.value(frameNo);
886 float innerRoundness = mData->mInnerRoundness.value(frameNo);
887 float outerRoundness = mData->mOuterRoundness.value(frameNo);
888 float rotation = mData->mRotation.value(frameNo);
893 if (mData->mType == LOTPolystarData::PolyType::Star) {
894 path.addPolystarStar(0.0, 0.0, 0.0, points,
895 innerRadius, outerRadius,
896 innerRoundness, outerRoundness,
899 path.addPolystarPolygon(0.0, 0.0, 0.0, points,
900 outerRadius, outerRoundness,
904 m.translate(pos.x(), pos.y()).rotate(rotation);
914 * PaintData Node handling
918 void LOTPaintDataItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
920 mContentChanged = false;
921 mParentAlpha = parentAlpha;
922 mParentMatrix = parentMatrix;
925 // 1. update the local content if needed
926 // if (!(mInit && mStaticContent)) {
928 updateContent(frameNo);
929 mContentChanged = true;
934 LOTFillItem::LOTFillItem(LOTFillData *data):LOTPaintDataItem(data->isStatic()),mData(data)
938 void LOTFillItem::updateContent(int frameNo)
940 LottieColor c = mData->mColor.value(frameNo);
941 float opacity = mData->opacity(frameNo);
942 mColor = c.toColor(opacity);
943 mFillRule = mData->fillRule();
946 void LOTFillItem::updateRenderNode(LOTPathDataItem *pathNode, VDrawable *drawable, bool sameParent)
948 VColor color = mColor;
950 color.setAlpha(color.a * pathNode->combinedAlpha());
952 color.setAlpha(color.a * parentAlpha() * pathNode->combinedAlpha());
954 drawable->setBrush(brush);
955 drawable->setFillRule(mFillRule);
959 LOTGFillItem::LOTGFillItem(LOTGFillData *data):LOTPaintDataItem(data->isStatic()),mData(data)
963 void LOTGFillItem::updateContent(int frameNo)
965 mData->update(mGradient, frameNo);
966 mGradient->mMatrix = mParentMatrix;
967 mFillRule = mData->fillRule();
970 void LOTGFillItem::updateRenderNode(LOTPathDataItem *pathNode, VDrawable *drawable, bool sameParent)
972 drawable->setBrush(VBrush(mGradient.get()));
973 drawable->setFillRule(mFillRule);
976 LOTStrokeItem::LOTStrokeItem(LOTStrokeData *data):LOTPaintDataItem(data->isStatic()),mData(data)
981 void LOTStrokeItem::updateContent(int frameNo)
983 LottieColor c = mData->mColor.value(frameNo);
984 float opacity = mData->opacity(frameNo);
985 mColor = c.toColor(opacity);
986 mCap = mData->capStyle();
987 mJoin = mData->joinStyle();
988 mMiterLimit = mData->meterLimit();
989 mWidth = mData->width(frameNo);
990 if (mData->hasDashInfo()) {
991 mDashArraySize = mData->getDashInfo(frameNo, mDashArray);
995 static float getScale(const VMatrix &matrix)
997 constexpr float SQRT_2 = 1.41421;
999 VPointF p2(SQRT_2,SQRT_2);
1000 p1 = matrix.map(p1);
1001 p2 = matrix.map(p2);
1002 VPointF final = p2 - p1;
1004 return std::sqrt( final.x() * final.x() + final.y() * final.y());
1007 void LOTStrokeItem::updateRenderNode(LOTPathDataItem *pathNode, VDrawable *drawable, bool sameParent)
1009 VColor color = mColor;
1011 color.setAlpha(color.a * pathNode->combinedAlpha());
1013 color.setAlpha(color.a * parentAlpha() * pathNode->combinedAlpha());
1015 VBrush brush(color);
1016 drawable->setBrush(brush);
1018 drawable->setStrokeInfo(mCap, mJoin, mMiterLimit, mWidth * getScale(mParentMatrix));
1019 if (mDashArraySize) {
1020 drawable->setDashInfo(mDashArray, mDashArraySize);
1024 LOTGStrokeItem::LOTGStrokeItem(LOTGStrokeData *data):LOTPaintDataItem(data->isStatic()),mData(data)
1029 void LOTGStrokeItem::updateContent(int frameNo)
1031 mData->update(mGradient, frameNo);
1032 mGradient->mMatrix = mParentMatrix;
1033 mCap = mData->capStyle();
1034 mJoin = mData->joinStyle();
1035 mMiterLimit = mData->meterLimit();
1036 mWidth = mData->width(frameNo);
1037 if (mData->hasDashInfo()) {
1038 mDashArraySize = mData->getDashInfo(frameNo, mDashArray);
1042 void LOTGStrokeItem::updateRenderNode(LOTPathDataItem *pathNode, VDrawable *drawable, bool sameParent)
1044 drawable->setBrush(VBrush(mGradient.get()));
1045 drawable->setStrokeInfo(mCap, mJoin, mMiterLimit, mWidth * getScale(mParentMatrix));
1046 if (mDashArraySize) {
1047 drawable->setDashInfo(mDashArray, mDashArraySize);
1051 LOTTrimItem::LOTTrimItem(LOTTrimData *data):mData(data)
1056 LOTRepeaterItem::LOTRepeaterItem(LOTRepeaterData *data):mData(data)
1061 void LOTRepeaterItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
1066 void LOTRepeaterItem::renderList(std::vector<VDrawable *> &list)