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),
399 mDirtyFlag(DirtyFlagBit::All)
401 if (mLayerData->mHasMask) {
402 for (auto i : mLayerData->mMasks) {
403 mMasks.push_back(std::unique_ptr<LOTMaskItem>(new LOTMaskItem(i.get())));
408 void LOTLayerItem::updateStaticProperty()
411 mParentLayer->updateStaticProperty();
413 mStatic = mLayerData->isStatic();
414 mStatic = mParentLayer ? (mStatic & mParentLayer->isStatic()) : mStatic;
415 mStatic = mPrecompLayer ? (mStatic & mPrecompLayer->isStatic()) : mStatic;
418 void LOTLayerItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha)
421 // 1. check if the layer is part of the current frame
422 if (!visible()) return;
424 // 2. calculate the parent matrix and alpha
425 VMatrix m = matrix(frameNo) * parentMatrix;
426 float alpha = parentAlpha * opacity(frameNo);
430 for (auto &i : mMasks)
431 i->update(frameNo, m, alpha, mDirtyFlag);
434 // 3. update the dirty flag based on the change
435 if (!mCombinedMatrix.fuzzyCompare(m)) {
436 mDirtyFlag |= DirtyFlagBit::Matrix;
438 if (!vCompare(mCombinedAlpha, alpha)) {
439 mDirtyFlag |= DirtyFlagBit::Alpha;
442 mCombinedAlpha = alpha;
444 // 4. if no parent property change and layer is static then nothing to do.
445 if ((flag() & DirtyFlagBit::None) && isStatic())
448 //5. update the content of the layer
451 //6. reset the dirty flag
452 mDirtyFlag = DirtyFlagBit::None;
456 LOTLayerItem::opacity(int frameNo) const
458 return mLayerData->mTransform->opacity(frameNo);
462 LOTLayerItem::matrix(int frameNo) const
465 return mLayerData->mTransform->matrix(frameNo) * mParentLayer->matrix(frameNo);
467 return mLayerData->mTransform->matrix(frameNo);
470 bool LOTLayerItem::visible() const
472 if (frameNo() >= mLayerData->inFrame() && frameNo() < mLayerData->outFrame())
480 LOTCompLayerItem::LOTCompLayerItem(LOTLayerData *layerModel):LOTLayerItem(layerModel)
482 for(auto i : mLayerData->mChildren) {
483 LOTLayerData *layerModel = dynamic_cast<LOTLayerData *>(i.get());
485 LOTLayerItem *layerItem = LOTCompItem::createLayerItem(layerModel);
487 mLayers.push_back(layerItem);
488 mLayerMap[layerItem->id()] = layerItem;
493 //2. update parent layer
494 for(auto i : mLayers) {
495 int id = i->parentId();
497 auto search = mLayerMap.find(id);
498 if (search != mLayerMap.end()) {
499 LOTLayerItem *parentLayer = search->second;
500 i->setParentLayer(parentLayer);
503 i->setPrecompLayer(this);
507 void LOTCompLayerItem::updateStaticProperty()
509 LOTLayerItem::updateStaticProperty();
511 for(auto i : mLayers) {
512 i->updateStaticProperty();
516 void LOTCompLayerItem::render(VPainter *painter, const VRle &inheritMask)
518 VRle mask = inheritMask;
522 mask = maskRle(painter->clipBoundingRect());
524 mask = mask & inheritMask;
527 for(auto i : mLayers) {
528 i->render(painter, mask);
532 LOTCompLayerItem::~LOTCompLayerItem()
534 for(auto i : mLayers) {
539 void LOTCompLayerItem::updateContent()
541 // update the layer from back to front
542 for (auto i = mLayers.rbegin(); i != mLayers.rend(); ++i) {
543 LOTLayerItem *layer = *i;
544 layer->update(frameNo(), combinedMatrix(), combinedAlpha());
548 void LOTCompLayerItem::renderList(std::vector<VDrawable *> &list)
550 if (!visible()) return;
552 // update the layer from back to front
553 for (auto i = mLayers.rbegin(); i != mLayers.rend(); ++i) {
554 LOTLayerItem *layer = *i;
555 layer->renderList(list);
559 LOTSolidLayerItem::LOTSolidLayerItem(LOTLayerData *layerData):LOTLayerItem(layerData)
564 void LOTSolidLayerItem::updateContent()
567 mRenderNode = std::unique_ptr<VDrawable>(new VDrawable());
568 mRenderNode->mType = VDrawable::Type::Fill;
569 mRenderNode->mFlag |= VDrawable::DirtyState::All;
572 if (flag() & DirtyFlagBit::Matrix) {
574 path.addRect(VRectF(0, 0, mLayerData->solidWidth(), mLayerData->solidHeight()));
575 path.transform(combinedMatrix());
576 mRenderNode->mFlag |= VDrawable::DirtyState::Path;
577 mRenderNode->mPath = path;
579 if (flag() & DirtyFlagBit::Alpha) {
580 LottieColor color = mLayerData->solidColor();
581 VBrush brush(color.toColor(combinedAlpha()));
582 mRenderNode->setBrush(brush);
583 mRenderNode->mFlag |= VDrawable::DirtyState::Brush;
587 void LOTSolidLayerItem::renderList(std::vector<VDrawable *> &list)
589 if (!visible()) return;
591 list.push_back(mRenderNode.get());
594 LOTNullLayerItem::LOTNullLayerItem(LOTLayerData *layerData):LOTLayerItem(layerData)
598 void LOTNullLayerItem::updateContent()
604 LOTShapeLayerItem::LOTShapeLayerItem(LOTLayerData *layerData):LOTLayerItem(layerData)
606 mRoot = new LOTContentGroupItem(nullptr);
607 mRoot->addChildren(layerData);
608 mRoot->processPaintOperation();
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));
665 void LOTShapeLayerItem::updateContent()
667 mRoot->update(frameNo(), combinedMatrix(), combinedAlpha(), flag());
670 void LOTShapeLayerItem::renderList(std::vector<VDrawable *> &list)
672 if (!visible()) return;
673 mRoot->renderList(list);
676 LOTContentGroupItem::LOTContentGroupItem(LOTShapeGroupData *data):mData(data)
681 void LOTContentGroupItem::addChildren(LOTGroupData *data)
685 for(auto i : data->mChildren) {
686 LOTData *data = i.get();
687 LOTContentItem *content = LOTShapeLayerItem::createContentItem(data);
689 mContents.push_back(content);
693 LOTContentGroupItem::~LOTContentGroupItem()
695 for(auto i : mContents) {
701 void LOTContentGroupItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
703 VMatrix m = parentMatrix;
704 float alpha = parentAlpha;
705 DirtyFlag newFlag = flag;
708 // update the matrix and the flag
709 if ((flag & DirtyFlagBit::Matrix) || !mData->mTransform->staticMatrix() ) {
710 newFlag |= DirtyFlagBit::Matrix;
712 m = mData->mTransform->matrix(frameNo) * parentMatrix;
713 alpha *= mData->mTransform->opacity(frameNo);
715 if (!vCompare(alpha, parentAlpha)) {
716 newFlag |= DirtyFlagBit::Alpha;
720 for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) {
721 (*i)->update(frameNo, m, alpha, newFlag);
725 void LOTContentGroupItem::renderList(std::vector<VDrawable *> &list)
727 for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) {
728 (*i)->renderList(list);
732 void LOTContentGroupItem::processPaintOperation()
734 std::vector<LOTPaintDataItem *> list;
735 paintOperationHelper(list);
738 void LOTContentGroupItem::paintOperationHelper(std::vector<LOTPaintDataItem *> &list)
740 int curOpCount = list.size();
741 for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) {
743 if (auto pathNode = dynamic_cast<LOTPathDataItem *>(child)) {
744 // the node is a path data node add the paint operation list to it.
745 pathNode->addPaintOperation(list, curOpCount);
746 } else if (auto paintNode = dynamic_cast<LOTPaintDataItem *>(child)) {
747 // add it to the paint operation list
748 list.push_back(paintNode);
749 } else if (auto groupNode = dynamic_cast<LOTContentGroupItem *>(child)) {
750 // update the groups node with current list
751 groupNode->paintOperationHelper(list);
754 list.erase(list.begin() + curOpCount, list.end());
757 void LOTPathDataItem::addPaintOperation(std::vector<LOTPaintDataItem *> &list, int externalCount)
759 for(auto paintItem : list) {
760 bool sameGroup = (externalCount-- > 0) ? false : true;
761 mNodeList.push_back(std::unique_ptr<VDrawable>(new VDrawable()));
762 mRenderList.push_back(LOTRenderNode(this, paintItem, mNodeList.back().get(), sameGroup));
767 void LOTPathDataItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
769 mPathChanged = false;
770 mCombinedAlpha = parentAlpha;
772 // 1. update the local path if needed
773 if (!(mInit && mStaticPath)) {
774 mLocalPath = getPath(frameNo);
779 // 2. apply path operation if needed
782 // 3. compute the final path with parentMatrix
783 if ((flag & DirtyFlagBit::Matrix) || mPathChanged) {
784 mFinalPath = mLocalPath;
785 mFinalPath.transform(parentMatrix);
789 // 2. update the rendernode list
790 for (const auto &i : mRenderList) {
791 i.drawable->mFlag = VDrawable::DirtyState::None;
792 i.paintNodeRef->updateRenderNode(i.pathNodeRef, i.drawable, i.sameGroup);
794 i.drawable->mPath = mFinalPath;
795 i.drawable->mFlag |= VDrawable::DirtyState::Path;
800 void LOTPathDataItem::renderList(std::vector<VDrawable *> &list)
802 for (const auto &i : mRenderList) {
803 list.push_back(i.drawable);
807 VPath LOTPathDataItem::path() const
813 LOTRectItem::LOTRectItem(LOTRectData *data):LOTPathDataItem(data->isStatic()),mData(data)
817 VPath LOTRectItem::getPath(int frameNo)
819 VPointF pos = mData->mPos.value(frameNo);
820 VPointF size = mData->mSize.value(frameNo);
821 float radius = mData->mRound.value(frameNo);
822 VRectF r(pos.x() - size.x()/2, pos.y() - size.y()/2, size.x(), size.y());
825 path.addRoundRect(r, radius, radius, mData->direction());
830 LOTEllipseItem::LOTEllipseItem(LOTEllipseData *data):LOTPathDataItem(data->isStatic()),mData(data)
835 VPath LOTEllipseItem::getPath(int frameNo)
837 VPointF pos = mData->mPos.value(frameNo);
838 VPointF size = mData->mSize.value(frameNo);
839 VRectF r(pos.x() - size.x()/2, pos.y() - size.y()/2, size.x(), size.y());
842 path.addOval(r, mData->direction());
847 LOTShapeItem::LOTShapeItem(LOTShapeData *data):LOTPathDataItem(data->isStatic()),mData(data)
852 VPath LOTShapeItem::getPath(int frameNo)
854 LottieShapeData shapeData = mData->mShape.value(frameNo);
856 if (shapeData.mPoints.empty())
861 int size = shapeData.mPoints.size();
862 const VPointF *points = shapeData.mPoints.data();
863 path.moveTo(points[0]);
864 for (int i = 1 ; i < size; i+=3) {
865 path.cubicTo(points[i], points[i+1], points[i+2]);
867 if (shapeData.mClosed)
874 LOTPolystarItem::LOTPolystarItem(LOTPolystarData *data):LOTPathDataItem(data->isStatic()),mData(data)
879 VPath LOTPolystarItem::getPath(int frameNo)
881 VPointF pos = mData->mPos.value(frameNo);
882 float points = mData->mPointCount.value(frameNo);
883 float innerRadius = mData->mInnerRadius.value(frameNo);
884 float outerRadius = mData->mOuterRadius.value(frameNo);
885 float innerRoundness = mData->mInnerRoundness.value(frameNo);
886 float outerRoundness = mData->mOuterRoundness.value(frameNo);
887 float rotation = mData->mRotation.value(frameNo);
892 if (mData->mType == LOTPolystarData::PolyType::Star) {
893 path.addPolystarStar(0.0, 0.0, 0.0, points,
894 innerRadius, outerRadius,
895 innerRoundness, outerRoundness,
898 path.addPolystarPolygon(0.0, 0.0, 0.0, points,
899 outerRadius, outerRoundness,
903 m.translate(pos.x(), pos.y()).rotate(rotation);
913 * PaintData Node handling
917 void LOTPaintDataItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
919 mContentChanged = false;
920 mParentAlpha = parentAlpha;
921 mParentMatrix = parentMatrix;
924 // 1. update the local content if needed
925 // if (!(mInit && mStaticContent)) {
927 updateContent(frameNo);
928 mContentChanged = true;
933 LOTFillItem::LOTFillItem(LOTFillData *data):LOTPaintDataItem(data->isStatic()),mData(data)
937 void LOTFillItem::updateContent(int frameNo)
939 LottieColor c = mData->mColor.value(frameNo);
940 float opacity = mData->opacity(frameNo);
941 mColor = c.toColor(opacity);
942 mFillRule = mData->fillRule();
945 void LOTFillItem::updateRenderNode(LOTPathDataItem *pathNode, VDrawable *drawable, bool sameParent)
947 VColor color = mColor;
949 color.setAlpha(color.a * pathNode->combinedAlpha());
951 color.setAlpha(color.a * parentAlpha() * pathNode->combinedAlpha());
953 drawable->setBrush(brush);
954 drawable->setFillRule(mFillRule);
958 LOTGFillItem::LOTGFillItem(LOTGFillData *data):LOTPaintDataItem(data->isStatic()),mData(data)
962 void LOTGFillItem::updateContent(int frameNo)
964 mData->update(mGradient, frameNo);
965 mGradient->mMatrix = mParentMatrix;
966 mFillRule = mData->fillRule();
969 void LOTGFillItem::updateRenderNode(LOTPathDataItem *pathNode, VDrawable *drawable, bool sameParent)
971 drawable->setBrush(VBrush(mGradient.get()));
972 drawable->setFillRule(mFillRule);
975 LOTStrokeItem::LOTStrokeItem(LOTStrokeData *data):LOTPaintDataItem(data->isStatic()),mData(data)
980 void LOTStrokeItem::updateContent(int frameNo)
982 LottieColor c = mData->mColor.value(frameNo);
983 float opacity = mData->opacity(frameNo);
984 mColor = c.toColor(opacity);
985 mCap = mData->capStyle();
986 mJoin = mData->joinStyle();
987 mMiterLimit = mData->meterLimit();
988 mWidth = mData->width(frameNo);
989 if (mData->hasDashInfo()) {
990 mDashArraySize = mData->getDashInfo(frameNo, mDashArray);
994 static float getScale(const VMatrix &matrix)
996 constexpr float SQRT_2 = 1.41421;
998 VPointF p2(SQRT_2,SQRT_2);
1000 p2 = matrix.map(p2);
1001 VPointF final = p2 - p1;
1003 return std::sqrt( final.x() * final.x() + final.y() * final.y());
1006 void LOTStrokeItem::updateRenderNode(LOTPathDataItem *pathNode, VDrawable *drawable, bool sameParent)
1008 VColor color = mColor;
1010 color.setAlpha(color.a * pathNode->combinedAlpha());
1012 color.setAlpha(color.a * parentAlpha() * pathNode->combinedAlpha());
1014 VBrush brush(color);
1015 drawable->setBrush(brush);
1017 drawable->setStrokeInfo(mCap, mJoin, mMiterLimit, mWidth * getScale(mParentMatrix));
1018 if (mDashArraySize) {
1019 drawable->setDashInfo(mDashArray, mDashArraySize);
1023 LOTGStrokeItem::LOTGStrokeItem(LOTGStrokeData *data):LOTPaintDataItem(data->isStatic()),mData(data)
1028 void LOTGStrokeItem::updateContent(int frameNo)
1030 mData->update(mGradient, frameNo);
1031 mGradient->mMatrix = mParentMatrix;
1032 mCap = mData->capStyle();
1033 mJoin = mData->joinStyle();
1034 mMiterLimit = mData->meterLimit();
1035 mWidth = mData->width(frameNo);
1036 if (mData->hasDashInfo()) {
1037 mDashArraySize = mData->getDashInfo(frameNo, mDashArray);
1041 void LOTGStrokeItem::updateRenderNode(LOTPathDataItem *pathNode, VDrawable *drawable, bool sameParent)
1043 drawable->setBrush(VBrush(mGradient.get()));
1044 drawable->setStrokeInfo(mCap, mJoin, mMiterLimit, mWidth * getScale(mParentMatrix));
1045 if (mDashArraySize) {
1046 drawable->setDashInfo(mDashArray, mDashArraySize);
1050 LOTTrimItem::LOTTrimItem(LOTTrimData *data):mData(data)
1055 LOTRepeaterItem::LOTRepeaterItem(LOTRepeaterData *data):mData(data)
1060 void LOTRepeaterItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
1065 void LOTRepeaterItem::renderList(std::vector<VDrawable *> &list)