switch (contentData->type()) {
case LOTData::Type::ShapeGroup: {
return std::make_unique<LOTContentGroupItem>(
- static_cast<LOTShapeGroupData *>(contentData));
+ static_cast<LOTGroupData *>(contentData));
break;
}
case LOTData::Type::Rect: {
mRoot->renderList(list);
}
-LOTContentGroupItem::LOTContentGroupItem(LOTShapeGroupData *data) : mData(data)
+LOTContentGroupItem::LOTContentGroupItem(LOTGroupData *data) : mData(data)
{
addChildren(mData);
}
float alpha = parentAlpha;
DirtyFlag newFlag = flag;
- if (mData) {
+ if (mData && mData->mTransform) {
// update the matrix and the flag
if ((flag & DirtyFlagBit::Matrix) ||
!mData->mTransform->staticMatrix()) {
}
-LOTRepeaterItem::LOTRepeaterItem(LOTRepeaterData *data) : mData(data) {}
-
-void LOTRepeaterItem::update(int /*frameNo*/, const VMatrix &/*parentMatrix*/,
- float /*parentAlpha*/, const DirtyFlag &/*flag*/)
+LOTRepeaterItem::LOTRepeaterItem(LOTRepeaterData *data) : mData(data)
{
+ assert(mData->mChildren.size() == 1);
+ LOTGroupData *root = reinterpret_cast<LOTGroupData *>(mData->mChildren[0].get());
+ assert(root);
+
+ for (int i= 0; i < mData->copies(0); i++) {
+ auto content = std::make_unique<LOTContentGroupItem>(static_cast<LOTGroupData *>(root));
+ content->setParent(this);
+ mContents.push_back(std::move(content));
+ }
}
-void LOTRepeaterItem::renderList(std::vector<VDrawable *> &/*list*/) {}
+void LOTRepeaterItem::update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag)
+{
+
+ DirtyFlag newFlag = flag;
+
+ if (mData->hasMtrixChange(frameNo)) {
+ newFlag |= DirtyFlagBit::Matrix;
+ }
+
+ float multiplier = mData->offset(frameNo);
+ float startOpacity = mData->mTransform->startOpacity(frameNo);
+ float endOpacity = mData->mTransform->endOpacity(frameNo);
+ float index = 0;
+ float copies = mData->copies(frameNo);
+ if (!vCompare(copies, 1)) copies -=1;
+
+ newFlag |= DirtyFlagBit::Alpha;
+ for (const auto &content : mContents) {
+ float newAlpha = parentAlpha * lerp(startOpacity, endOpacity, index / copies);
+ VMatrix result = mData->mTransform->matrixForRepeater(frameNo, multiplier) * parentMatrix;
+ content->update(frameNo, result, newAlpha, newFlag);
+ multiplier += 1;
+ index +=1;
+ }
+}
static void updateGStops(LOTNode *n, const VGradient *grad)
{
class LOTContentGroupItem: public LOTContentItem
{
public:
- LOTContentGroupItem(LOTShapeGroupData *data);
+ LOTContentGroupItem(){}
+ LOTContentGroupItem(LOTGroupData *data);
void addChildren(LOTGroupData *data);
- void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag) final;
+ void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag);
void applyTrim();
void processTrimItems(std::vector<LOTPathDataItem *> &list);
void processPaintItems(std::vector<LOTPathDataItem *> &list);
void renderList(std::vector<VDrawable *> &list) final;
const VMatrix & matrix() const { return mMatrix;}
-private:
- LOTShapeGroupData *mData;
+protected:
+ LOTGroupData *mData{nullptr};
std::vector<std::unique_ptr<LOTContentItem>> mContents;
VMatrix mMatrix;
};
bool mDirty{true};
};
-class LOTRepeaterItem : public LOTContentItem
+class LOTRepeaterItem : public LOTContentGroupItem
{
public:
LOTRepeaterItem(LOTRepeaterData *data);
void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag) final;
- void renderList(std::vector<VDrawable *> &list) final;
private:
LOTRepeaterData *mData;
};
#include <cassert>
#include <stack>
+/*
+ * We process the iterator objects in the children list
+ * by iterating from back to front. when we find a repeater object
+ * we remove the objects from satrt till repeater object and then place
+ * under a new shape group object which we add it as children to the repeater
+ * object.
+ * Then we visit the childrens of the newly created shape group object to
+ * process the remaining repeater object(when children list contains more than one
+ * repeater).
+ *
+ */
class LottieRepeaterProcesser {
public:
- void visitChildren(LOTGroupData *obj)
- {
- for (const auto& child : obj->mChildren) {
- if (child->mType == LOTData::Type::Repeater) {
- LOTRepeaterData *repeater =
- static_cast<LOTRepeaterData *>(child.get());
- std::shared_ptr<LOTShapeGroupData> sharedShapeGroup =
- std::make_shared<LOTShapeGroupData>();
+ void visitChildren(LOTGroupData *obj) {
+ for (auto i = obj->mChildren.rbegin(); i != obj->mChildren.rend(); ++i ) {
+ auto child = (*i).get();
+ if (child->type() == LOTData::Type::Repeater) {
+ LOTRepeaterData *repeater = static_cast<LOTRepeaterData *>(child);
+ auto sharedShapeGroup = std::make_shared<LOTShapeGroupData>();
LOTShapeGroupData *shapeGroup = sharedShapeGroup.get();
+ // 1. increment the reverse iterator to point to the
+ // object before the repeater
+ ++i;
+ // 2. move all the children till repater to the group
+ std::move(obj->mChildren.begin(),
+ i.base(), back_inserter(shapeGroup->mChildren));
+ // 3. erase the objects from the original children list
+ obj->mChildren.erase(obj->mChildren.begin(),
+ i.base());
+ // 4. Add the newly created group to the repeater object.
repeater->mChildren.push_back(sharedShapeGroup);
- // copy all the child of the object till repeater and
- // move that in to a group and then add that group to
- // the repeater object.
- for (const auto& cpChild : obj->mChildren) {
- if (cpChild == child) break;
- shapeGroup->mChildren.push_back(cpChild);
- }
+
+ // 5. visit newly created group to process remaining repeater object.
+ visitChildren(shapeGroup);
+ // 6. exit the loop as the current iterators are invalid
+ break;
+ } else {
+ visit(child);
}
+
}
}
visitor.visit(mRootLayer.get());
}
+VMatrix LOTTransformData::matrixForRepeater(int frameNo, float multiplier) const
+{
+ VPointF scale = mScale.value(frameNo) / 100.f;
+ scale.setX(std::pow(scale.x(), multiplier));
+ scale.setY(std::pow(scale.y(), multiplier));
+ VMatrix m;
+ m.translate(mPosition.value(frameNo) * multiplier)
+ .rotate(mRotation.value(frameNo) * multiplier)
+ .scale(scale)
+ .translate(mAnchor.value(frameNo));
+ return m;
+}
+
+
VMatrix LOTTransformData::matrix(int frameNo, bool autoOrient) const
{
if (mStaticMatrix)
public:
LOTTransformData():LOTData(LOTData::Type::Transform),mScale({100, 100}){}
VMatrix matrix(int frameNo, bool autoOrient = false) const;
+ VMatrix matrixForRepeater(int frameNo, float multiplier) const;
float opacity(int frameNo) const { return mOpacity.value(frameNo)/100;}
float startOpacity(int frameNo) const { return mStartOpacity.value(frameNo)/100;}
float endOpacity(int frameNo) const { return mEndOpacity.value(frameNo)/100;}
{
public:
LOTRepeaterData():LOTGroupData(LOTData::Type::Repeater){}
+ bool hasMtrixChange(int /*frameNo*/) const {
+ return !(mTransform->isStatic() && mOffset.isStatic());
+ }
+ float copies(int frameNo) const {return mCopies.value(frameNo);}
+ float offset(int frameNo) const {return mOffset.value(frameNo);}
public:
LOTAnimatable<float> mCopies{0};
LOTAnimatable<float> mOffset{0};
void visit(LOTData *obj, std::string level) {
switch (obj->mType) {
case LOTData::Type::Repeater: {
- vDebug << level << "{ Repeater:";
+ auto r = static_cast<LOTRepeaterData *>(obj);
+ vDebug << level << "{ Repeater: a:" << !obj->isStatic()
+ << ", copies:" << r->copies(0)
+ << ", offset:" << r->offset(0);
visitChildren(static_cast<LOTGroupData *>(obj), level);
vDebug << level << "} Repeater";
break;