1 #include "lottiemodel.h"
6 class LottieRepeaterProcesser {
8 void visitChildren(LOTGroupData *obj)
10 for (const auto& child : obj->mChildren) {
11 if (child->mType == LOTData::Type::Repeater) {
12 LOTRepeaterData *repeater =
13 static_cast<LOTRepeaterData *>(child.get());
14 std::shared_ptr<LOTShapeGroupData> sharedShapeGroup =
15 std::make_shared<LOTShapeGroupData>();
16 LOTShapeGroupData *shapeGroup = sharedShapeGroup.get();
17 repeater->mChildren.push_back(sharedShapeGroup);
18 // copy all the child of the object till repeater and
19 // move that in to a group and then add that group to
20 // the repeater object.
21 for (const auto& cpChild : obj->mChildren) {
22 if (cpChild == child) break;
23 shapeGroup->mChildren.push_back(cpChild);
29 void visit(LOTData *obj) {
31 case LOTData::Type::Repeater:
32 case LOTData::Type::ShapeGroup:
33 case LOTData::Type::Layer:{
34 visitChildren(static_cast<LOTGroupData *>(obj));
44 void LOTCompositionData::processRepeaterObjects()
46 LottieRepeaterProcesser visitor;
47 visitor.visit(mRootLayer.get());
50 VMatrix LOTTransformData::matrix(int frameNo) const
55 return computeMatrix(frameNo);
58 float LOTTransformData::opacity(int frameNo) const
60 return mOpacity.value(frameNo) / 100.f;
63 void LOTTransformData::cacheMatrix()
65 mCachedMatrix = computeMatrix(0);
68 VMatrix LOTTransformData::computeMatrix(int frameNo) const
71 VPointF position = mPosition.value(frameNo);
73 position.setX(mX.value(frameNo));
74 position.setY(mY.value(frameNo));
77 .rotate(mRotation.value(frameNo))
78 .scale(mScale.value(frameNo) / 100.f)
79 .translate(-mAnchor.value(frameNo));
83 int LOTStrokeData::getDashInfo(int frameNo, float *array) const
85 if (!mDash.mDashCount) return 0;
87 if (mDash.mDashCount % 2) {
88 for (int i = 0; i < mDash.mDashCount; i++) {
89 array[i] = mDash.mDashArray[i].value(frameNo);
91 return mDash.mDashCount;
92 } else { // even case when last gap info is not provided.
94 for (i = 0; i < mDash.mDashCount - 1; i++) {
95 array[i] = mDash.mDashArray[i].value(frameNo);
97 array[i] = array[i - 1];
98 array[i + 1] = mDash.mDashArray[i].value(frameNo);
99 return mDash.mDashCount + 1;
103 int LOTGStrokeData::getDashInfo(int frameNo, float *array) const
105 if (!mDash.mDashCount) return 0;
107 if (mDash.mDashCount % 2) {
108 for (int i = 0; i < mDash.mDashCount; i++) {
109 array[i] = mDash.mDashArray[i].value(frameNo);
111 return mDash.mDashCount;
112 } else { // even case when last gap info is not provided.
114 for (i = 0; i < mDash.mDashCount - 1; i++) {
115 array[i] = mDash.mDashArray[i].value(frameNo);
117 array[i] = array[i - 1];
118 array[i + 1] = mDash.mDashArray[i].value(frameNo);
119 return mDash.mDashCount + 1;
124 * Both the color stops and opacity stops are in the same array.
125 * There are {@link #colorPoints} colors sequentially as:
135 * The remainder of the array is the opacity stops sequentially as:
143 void LOTGradient::populate(VGradientStops &stops, int frameNo)
145 LottieGradient gradData = mGradient.value(frameNo);
146 int size = gradData.mGradient.size();
147 float * ptr = gradData.mGradient.data();
148 int colorPoints = mColorPoints;
149 if (colorPoints == -1) { // for legacy bodymovin (ref: lottie-android)
150 colorPoints = size / 4;
152 int opacityArraySize = size - colorPoints * 4;
153 float *opacityPtr = ptr + (colorPoints * 4);
156 for (int i = 0; i < colorPoints; i++) {
157 float colorStop = ptr[0];
158 LottieColor color = LottieColor(ptr[1], ptr[2], ptr[3]);
159 if (opacityArraySize) {
160 if (j == opacityArraySize) {
161 // already reached the end
162 float stop1 = opacityPtr[j - 4];
163 float op1 = opacityPtr[j - 3];
164 float stop2 = opacityPtr[j - 2];
165 float op2 = opacityPtr[j - 1];
166 if (colorStop > stop2) {
168 std::make_pair(colorStop, color.toColor(op2)));
170 float progress = (colorStop - stop1) / (stop2 - stop1);
171 float opacity = op1 + progress * (op2 - op1);
173 std::make_pair(colorStop, color.toColor(opacity)));
177 for (; j < opacityArraySize; j += 2) {
178 float opacityStop = opacityPtr[j];
179 if (opacityStop < colorStop) {
180 // add a color using opacity stop
181 stops.push_back(std::make_pair(
182 opacityStop, color.toColor(opacityPtr[j + 1])));
185 // add a color using color stop
187 stops.push_back(std::make_pair(
188 colorStop, color.toColor(opacityPtr[j + 1])));
190 float progress = (colorStop - opacityPtr[j - 2]) /
191 (opacityPtr[j] - opacityPtr[j - 2]);
194 progress * (opacityPtr[j + 1] - opacityPtr[j - 1]);
196 std::make_pair(colorStop, color.toColor(opacity)));
202 stops.push_back(std::make_pair(colorStop, color.toColor()));
208 void LOTGradient::update(std::unique_ptr<VGradient> &grad, int frameNo)
212 if (mGradientType == 1)
213 grad = std::make_unique<VLinearGradient>(0, 0, 0, 0);
215 grad = std::make_unique<VRadialGradient>(0, 0, 0, 0, 0, 0);
216 grad->mSpread = VGradient::Spread::Pad;
220 if (!mGradient.isStatic() || init) {
221 populate(grad->mStops, frameNo);
224 if (mGradientType == 1) { // linear gradient
225 VPointF start = mStartPoint.value(frameNo);
226 VPointF end = mEndPoint.value(frameNo);
227 grad->linear.x1 = start.x();
228 grad->linear.y1 = start.y();
229 grad->linear.x2 = end.x();
230 grad->linear.y2 = end.y();
231 } else { // radial gradient
232 VPointF start = mStartPoint.value(frameNo);
233 VPointF end = mEndPoint.value(frameNo);
234 grad->radial.cx = start.x();
235 grad->radial.cy = start.y();
236 grad->radial.cradius =
237 VLine::length(start.x(), start.y(), end.x(), end.y());
239 * Focal point is the point lives in highlight length distance from
240 * center along the line (start, end) and rotated by highlight angle.
241 * below calculation first finds the quadrant(angle) on which the point
242 * lives by applying inverse slope formula then adds the rotation angle
243 * to find the final angle. then point is retrived using circle equation
244 * of center, angle and distance.
246 float progress = mHighlightLength.value(frameNo) / 100.0f;
247 if (vCompare(progress, 1.0f)) progress = 0.99f;
248 float dy = end.y() - start.y();
249 float dx = end.x() - start.x();
250 float slope = (dx == 0) ? dy * INFINITY : dy / dx;
251 float startAngleRad = std::atan(slope);
252 int highlightAngle = mHighlightAngle.value(frameNo);
253 float angle = startAngleRad + (highlightAngle * M_PI / 180.0f);
255 grad->radial.cx + std::cos(angle) * progress * grad->radial.cradius;
257 grad->radial.cy + std::sin(angle) * progress * grad->radial.cradius;
258 // Lottie dosen't have any focal radius concept.
259 grad->radial.fradius = 0;