summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsubhransu sekhar mohanty <smohantty@subhransus-MacBook-Air.local>2018-07-02 23:27:03 +0900
committersubhransu sekhar mohanty <smohantty@subhransus-MacBook-Air.local>2018-07-02 23:27:03 +0900
commitbf9e2d789ffa793134f03c026b1429af59ec8ca3 (patch)
treefb7d4388639c67a90afb944feabdf8555a50aee4
parent229ab4379f671d1065a8d68af66f3f84d72d18ef (diff)
lottie: added a dasher object to lottie.
-rw-r--r--src/painting/meson.build3
-rw-r--r--src/painting/vdasher.cpp206
-rw-r--r--src/painting/vdasher.h29
3 files changed, 237 insertions, 1 deletions
diff --git a/src/painting/meson.build b/src/painting/meson.build
index a66e368..62eaf81 100644
--- a/src/painting/meson.build
+++ b/src/painting/meson.build
@@ -1,4 +1,5 @@
1source_file = files('vbitmap.cpp') 1source_file = files('vdasher.cpp')
2source_file += files('vbitmap.cpp')
2source_file += files('vpainter.cpp') 3source_file += files('vpainter.cpp')
3source_file += files('vcompositionfunctions.cpp') 4source_file += files('vcompositionfunctions.cpp')
4source_file += files('vdrawhelper.cpp') 5source_file += files('vdrawhelper.cpp')
diff --git a/src/painting/vdasher.cpp b/src/painting/vdasher.cpp
new file mode 100644
index 0000000..c67d213
--- /dev/null
+++ b/src/painting/vdasher.cpp
@@ -0,0 +1,206 @@
1#include"vdasher.h"
2#include"sgbezier.h"
3
4class VLine
5{
6public:
7 VLine():mX1(0),mY1(0),mX2(0),mY2(0){}
8 VLine(float x1, float y1, float x2, float y2):mX1(x1),mY1(y1),mX2(x2),mY2(y2){}
9 VLine(const SGPointF &p1, const SGPointF &p2):mX1(p1.x()),mY1(p1.y()),mX2(p2.x()),mY2(p2.y()){}
10 float length() const;
11 void splitAtLength(float length, VLine &left, VLine &right) const;
12 SGPointF p1() const {return SGPointF(mX1, mY1);}
13 SGPointF p2() const {return SGPointF(mX2, mY2);}
14private:
15 float mX1;
16 float mY1;
17 float mX2;
18 float mY2;
19};
20
21// approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm.
22// With alpha = 1, beta = 3/8, giving results with the largest error less
23// than 7% compared to the exact value.
24float
25VLine::length() const
26{
27 float x = mX2 - mX1;
28 float y = mY2 - mY1;
29 x = x < 0 ? -x : x;
30 y = y < 0 ? -y : y;
31 return (x > y ? x + 0.375 * y : y + 0.375 * x);
32}
33
34void
35VLine::splitAtLength(float lengthAt, VLine &left, VLine &right) const
36{
37 float len = length();
38 double dx = ((mX2 - mX1)/len) *lengthAt;
39 double dy = ((mY2 - mY1)/len) *lengthAt;
40
41 left.mX1 = mX1;
42 left.mY1 = mY1;
43 left.mX2 = left.mX1 + dx;
44 left.mY2 = left.mY1 + dy;
45
46 right.mX1 = left.mX2;
47 right.mY1 = left.mY2;
48 right.mX2 = mX2;
49 right.mY2 = mY2;
50}
51
52VDasher::VDasher(const float *dashArray, int size)
53{
54 mDashArray = reinterpret_cast<const VDasher::Dash *>(dashArray);
55 mArraySize = size/3;
56 mCurrentDashIndex = 0;
57 mCurrentDashLength = 0;
58 mIsCurrentOperationGap = false;
59}
60
61void VDasher::moveTo(const SGPointF &p)
62{
63 mCurrentDashIndex = 0;
64 mCurrentDashLength = mDashArray[0].length;
65 mIsCurrentOperationGap = false;
66 mStartPt = p;
67 mCurPt = p;
68}
69
70void VDasher::lineTo(const SGPointF &p)
71{
72 VLine left, right;
73 VLine line(mCurPt, p);
74 float length = line.length();
75 if (length < mCurrentDashLength) {
76 mCurrentDashLength -= length;
77 if (!mIsCurrentOperationGap) {
78 mDashedPath.moveTo(mCurPt);
79 mDashedPath.lineTo(p);
80 }
81 } else {
82 while (length > mCurrentDashLength) {
83 length -= mCurrentDashLength;
84 line.splitAtLength(mCurrentDashLength, left, right);
85 if (!mIsCurrentOperationGap) {
86 mDashedPath.moveTo(left.p1());
87 mDashedPath.lineTo(left.p2());
88 mCurrentDashLength = mDashArray[mCurrentDashIndex].gap;
89 } else {
90 mCurrentDashIndex = (mCurrentDashIndex +1) % mArraySize ;
91 mCurrentDashLength = mDashArray[mCurrentDashIndex].length;
92 }
93 mIsCurrentOperationGap = !mIsCurrentOperationGap;
94 line = right;
95 mCurPt = line.p1();
96 }
97 // remainder
98 mCurrentDashLength -= length;
99 if (!mIsCurrentOperationGap) {
100 mDashedPath.moveTo(line.p1());
101 mDashedPath.lineTo(line.p2());
102 }
103 if (mCurrentDashLength < 1.0) {
104 // move to next dash
105 if (!mIsCurrentOperationGap) {
106 mIsCurrentOperationGap = true;
107 mCurrentDashLength = mDashArray[mCurrentDashIndex].gap;
108 } else {
109 mIsCurrentOperationGap = false;
110 mCurrentDashIndex = (mCurrentDashIndex +1) % mArraySize;
111 mCurrentDashLength = mDashArray[mCurrentDashIndex].length;
112 }
113 }
114 }
115 mCurPt = p;
116}
117
118void VDasher::cubicTo(const SGPointF &cp1, const SGPointF &cp2, const SGPointF &e)
119{
120 SGBezier left, right;
121 float bezLen = 0.0;
122 SGBezier b = SGBezier::fromPoints(mCurPt, cp1, cp2, e);
123 bezLen = b.length();
124 if (bezLen < mCurrentDashLength) {
125 mCurrentDashLength -= bezLen;
126 if (!mIsCurrentOperationGap) {
127 mDashedPath.moveTo(mCurPt);
128 mDashedPath.cubicTo(cp1, cp2, e);
129 }
130 } else {
131 while (bezLen > mCurrentDashLength) {
132 bezLen -= mCurrentDashLength;
133 //b.splitAtLength(mCurrentDashLength, left, right);
134 if (!mIsCurrentOperationGap) {
135 mDashedPath.moveTo(left.pt1());
136 mDashedPath.cubicTo(left.pt2(), left.pt3(), left.pt4());;
137 mCurrentDashLength = mDashArray[mCurrentDashIndex].gap;
138 } else {
139 mCurrentDashIndex = (mCurrentDashIndex +1) % mArraySize ;
140 mCurrentDashLength = mDashArray[mCurrentDashIndex].length;
141 }
142 mIsCurrentOperationGap = !mIsCurrentOperationGap;
143 b = right;
144 mCurPt = b.pt1();
145 }
146 // remainder
147 mCurrentDashLength -= bezLen;
148 if (!mIsCurrentOperationGap) {
149 mDashedPath.moveTo(b.pt1());
150 mDashedPath.cubicTo(b.pt2(), b.pt3(), b.pt4());
151 }
152 if (mCurrentDashLength < 1.0) {
153 // move to next dash
154 if (!mIsCurrentOperationGap)
155 {
156 mIsCurrentOperationGap = true;
157 mCurrentDashLength = mDashArray[mCurrentDashIndex].gap;
158 }
159 else
160 {
161 mIsCurrentOperationGap = false;
162 mCurrentDashIndex = (mCurrentDashIndex +1) % mArraySize;
163 mCurrentDashLength = mDashArray[mCurrentDashIndex].length;
164 }
165 }
166 }
167 mCurPt = e;
168}
169
170
171SGPath VDasher::dashed(const SGPath &path)
172{
173 if (path.isEmpty()) return SGPath();
174
175 mDashedPath = SGPath();
176 const std::vector<SGPath::Element> &elms = path.elements();
177 const std::vector<SGPointF> &pts = path.points();
178 const SGPointF *ptPtr = pts.data();
179
180 for (auto i : elms) {
181 switch (i) {
182 case SGPath::Element::MoveTo: {
183 moveTo(*ptPtr++);
184 break;
185 }
186 case SGPath::Element::LineTo: {
187 lineTo(*ptPtr++);
188 break;
189 }
190 case SGPath::Element::CubicTo: {
191 cubicTo(*ptPtr, *(ptPtr + 1), *(ptPtr + 2));
192 ptPtr += 3;
193 break;
194 }
195 case SGPath::Element::Close: {
196 // The point is already joined to start point in SGPath
197 // no need to do anything here.
198 break;
199 }
200 default:
201 break;
202 }
203 }
204 return mDashedPath;
205}
206
diff --git a/src/painting/vdasher.h b/src/painting/vdasher.h
new file mode 100644
index 0000000..8e4d99e
--- /dev/null
+++ b/src/painting/vdasher.h
@@ -0,0 +1,29 @@
1#ifndef VDASHER_H
2#define VDASHER_H
3#include "sgpath.h"
4class VDasher
5{
6 public:
7 VDasher(const float *dashArray, int size);
8 SGPath dashed(const SGPath &path);
9 private:
10 void moveTo(const SGPointF &p);
11 void lineTo(const SGPointF &p);
12 void cubicTo(const SGPointF &cp1, const SGPointF &cp2, const SGPointF &e);
13 void close();
14private:
15 struct Dash {
16 float length;
17 float gap;
18 float offset;
19 };
20 const VDasher::Dash *mDashArray;
21 int mArraySize;
22 SGPointF mStartPt;
23 SGPointF mCurPt;
24 int mCurrentDashIndex;
25 int mCurrentDashLength;
26 bool mIsCurrentOperationGap;
27 SGPath mDashedPath;
28};
29#endif // VDASHER_H