1 /*
2 * Copyright 2019 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkParticleAffector.h"
9
10 #include "SkContourMeasure.h"
11 #include "SkCurve.h"
12 #include "SkParsePath.h"
13 #include "SkParticleData.h"
14 #include "SkPath.h"
15 #include "SkRandom.h"
16 #include "SkTextUtils.h"
17
18
apply(const SkParticleUpdateParams & params,SkParticleState ps[],int count)19 void SkParticleAffector::apply(const SkParticleUpdateParams& params,
20 SkParticleState ps[], int count) {
21 if (fEnabled) {
22 this->onApply(params, ps, count);
23 }
24 }
25
visitFields(SkFieldVisitor * v)26 void SkParticleAffector::visitFields(SkFieldVisitor* v) {
27 v->visit("Enabled", fEnabled);
28 }
29
30 class SkLinearVelocityAffector : public SkParticleAffector {
31 public:
SkLinearVelocityAffector(const SkCurve & angle=0.0f,const SkCurve & strength=0.0f,bool force=true,SkParticleFrame frame=kWorld_ParticleFrame)32 SkLinearVelocityAffector(const SkCurve& angle = 0.0f,
33 const SkCurve& strength = 0.0f,
34 bool force = true,
35 SkParticleFrame frame = kWorld_ParticleFrame)
36 : fAngle(angle)
37 , fStrength(strength)
38 , fForce(force)
39 , fFrame(frame) {}
40
REFLECTED(SkLinearVelocityAffector,SkParticleAffector)41 REFLECTED(SkLinearVelocityAffector, SkParticleAffector)
42
43 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
44 for (int i = 0; i < count; ++i) {
45 float angle = fAngle.eval(params, ps[i]);
46 SkScalar c_local, s_local = SkScalarSinCos(SkDegreesToRadians(angle), &c_local);
47 SkVector heading = ps[i].getFrameHeading(static_cast<SkParticleFrame>(fFrame));
48 SkScalar c = heading.fX * c_local - heading.fY * s_local;
49 SkScalar s = heading.fX * s_local + heading.fY * c_local;
50 float strength = fStrength.eval(params, ps[i]);
51 SkVector force = { c * strength, s * strength };
52 if (fForce) {
53 ps[i].fVelocity.fLinear += force * params.fDeltaTime;
54 } else {
55 ps[i].fVelocity.fLinear = force;
56 }
57 }
58 }
59
visitFields(SkFieldVisitor * v)60 void visitFields(SkFieldVisitor* v) override {
61 SkParticleAffector::visitFields(v);
62 v->visit("Force", fForce);
63 v->visit("Frame", fFrame, gParticleFrameMapping, SK_ARRAY_COUNT(gParticleFrameMapping));
64 v->visit("Angle", fAngle);
65 v->visit("Strength", fStrength);
66 }
67
68 private:
69 SkCurve fAngle;
70 SkCurve fStrength;
71 bool fForce;
72 int fFrame;
73 };
74
75 class SkAngularVelocityAffector : public SkParticleAffector {
76 public:
SkAngularVelocityAffector(const SkCurve & strength=0.0f,bool force=true)77 SkAngularVelocityAffector(const SkCurve& strength = 0.0f, bool force = true)
78 : fStrength(strength)
79 , fForce(force) {}
80
REFLECTED(SkAngularVelocityAffector,SkParticleAffector)81 REFLECTED(SkAngularVelocityAffector, SkParticleAffector)
82
83 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
84 for (int i = 0; i < count; ++i) {
85 float strength = fStrength.eval(params, ps[i]);
86 if (fForce) {
87 ps[i].fVelocity.fAngular += strength * params.fDeltaTime;
88 } else {
89 ps[i].fVelocity.fAngular = strength;
90 }
91 }
92 }
93
visitFields(SkFieldVisitor * v)94 void visitFields(SkFieldVisitor* v) override {
95 SkParticleAffector::visitFields(v);
96 v->visit("Force", fForce);
97 v->visit("Strength", fStrength);
98 }
99
100 private:
101 SkCurve fStrength;
102 bool fForce;
103 };
104
105 class SkPointForceAffector : public SkParticleAffector {
106 public:
SkPointForceAffector(SkPoint point={ 0.0f, 0.0f },SkScalar constant=0.0f,SkScalar invSquare=0.0f)107 SkPointForceAffector(SkPoint point = { 0.0f, 0.0f }, SkScalar constant = 0.0f,
108 SkScalar invSquare = 0.0f)
109 : fPoint(point), fConstant(constant), fInvSquare(invSquare) {}
110
REFLECTED(SkPointForceAffector,SkParticleAffector)111 REFLECTED(SkPointForceAffector, SkParticleAffector)
112
113 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
114 for (int i = 0; i < count; ++i) {
115 SkVector toPoint = fPoint - ps[i].fPose.fPosition;
116 SkScalar lenSquare = toPoint.dot(toPoint);
117 toPoint.normalize();
118 ps[i].fVelocity.fLinear +=
119 toPoint * (fConstant + (fInvSquare / lenSquare)) * params.fDeltaTime;
120 }
121 }
122
visitFields(SkFieldVisitor * v)123 void visitFields(SkFieldVisitor* v) override {
124 SkParticleAffector::visitFields(v);
125 v->visit("Point", fPoint);
126 v->visit("Constant", fConstant);
127 v->visit("InvSquare", fInvSquare);
128 }
129
130 private:
131 SkPoint fPoint;
132 SkScalar fConstant;
133 SkScalar fInvSquare;
134 };
135
136 class SkOrientationAffector : public SkParticleAffector {
137 public:
SkOrientationAffector(const SkCurve & angle=0.0f,SkParticleFrame frame=kLocal_ParticleFrame)138 SkOrientationAffector(const SkCurve& angle = 0.0f,
139 SkParticleFrame frame = kLocal_ParticleFrame)
140 : fAngle(angle)
141 , fFrame(frame) {}
142
REFLECTED(SkOrientationAffector,SkParticleAffector)143 REFLECTED(SkOrientationAffector, SkParticleAffector)
144
145 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
146 for (int i = 0; i < count; ++i) {
147 float angle = fAngle.eval(params, ps[i]);
148 SkScalar c_local, s_local = SkScalarSinCos(SkDegreesToRadians(angle), &c_local);
149 SkVector heading = ps[i].getFrameHeading(static_cast<SkParticleFrame>(fFrame));
150 ps[i].fPose.fHeading.set(heading.fX * c_local - heading.fY * s_local,
151 heading.fX * s_local + heading.fY * c_local);
152 }
153 }
154
visitFields(SkFieldVisitor * v)155 void visitFields(SkFieldVisitor *v) override {
156 SkParticleAffector::visitFields(v);
157 v->visit("Frame", fFrame, gParticleFrameMapping, SK_ARRAY_COUNT(gParticleFrameMapping));
158 v->visit("Angle", fAngle);
159 }
160
161 private:
162 SkCurve fAngle;
163 int fFrame;
164 };
165
166 class SkPositionInCircleAffector : public SkParticleAffector {
167 public:
SkPositionInCircleAffector(const SkCurve & x=0.0f,const SkCurve & y=0.0f,const SkCurve & radius=0.0f,bool setHeading=true)168 SkPositionInCircleAffector(const SkCurve& x = 0.0f, const SkCurve& y = 0.0f,
169 const SkCurve& radius = 0.0f, bool setHeading = true)
170 : fX(x)
171 , fY(y)
172 , fRadius(radius)
173 , fSetHeading(setHeading) {}
174
REFLECTED(SkPositionInCircleAffector,SkParticleAffector)175 REFLECTED(SkPositionInCircleAffector, SkParticleAffector)
176
177 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
178 for (int i = 0; i < count; ++i) {
179 SkVector v;
180 do {
181 v.fX = ps[i].fRandom.nextSScalar1();
182 v.fY = ps[i].fRandom.nextSScalar1();
183 } while (v.dot(v) > 1);
184
185 SkPoint center = { fX.eval(params, ps[i]), fY.eval(params, ps[i]) };
186 SkScalar radius = fRadius.eval(params, ps[i]);
187 ps[i].fPose.fPosition = center + (v * radius);
188 if (fSetHeading) {
189 if (!v.normalize()) {
190 v.set(0, -1);
191 }
192 ps[i].fPose.fHeading = v;
193 }
194 }
195 }
196
visitFields(SkFieldVisitor * v)197 void visitFields(SkFieldVisitor* v) override {
198 SkParticleAffector::visitFields(v);
199 v->visit("SetHeading", fSetHeading);
200 v->visit("X", fX);
201 v->visit("Y", fY);
202 v->visit("Radius", fRadius);
203 }
204
205 private:
206 SkCurve fX;
207 SkCurve fY;
208 SkCurve fRadius;
209 bool fSetHeading;
210 };
211
212 class SkPositionOnPathAffector : public SkParticleAffector {
213 public:
SkPositionOnPathAffector(const char * path="",bool setHeading=true,SkParticleValue input=SkParticleValue ())214 SkPositionOnPathAffector(const char* path = "", bool setHeading = true,
215 SkParticleValue input = SkParticleValue())
216 : fPath(path)
217 , fInput(input)
218 , fSetHeading(setHeading) {
219 this->rebuild();
220 }
221
REFLECTED(SkPositionOnPathAffector,SkParticleAffector)222 REFLECTED(SkPositionOnPathAffector, SkParticleAffector)
223
224 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
225 if (fContours.empty()) {
226 return;
227 }
228
229 for (int i = 0; i < count; ++i) {
230 float t = fInput.eval(params, ps[i]);
231 SkScalar len = fTotalLength * t;
232 int idx = 0;
233 while (idx < fContours.count() && len > fContours[idx]->length()) {
234 len -= fContours[idx++]->length();
235 }
236 SkVector localXAxis;
237 if (!fContours[idx]->getPosTan(len, &ps[i].fPose.fPosition, &localXAxis)) {
238 ps[i].fPose.fPosition = { 0, 0 };
239 localXAxis = { 1, 0 };
240 }
241 if (fSetHeading) {
242 ps[i].fPose.fHeading.set(localXAxis.fY, -localXAxis.fX);
243 }
244 }
245 }
246
visitFields(SkFieldVisitor * v)247 void visitFields(SkFieldVisitor* v) override {
248 SkString oldPath = fPath;
249
250 SkParticleAffector::visitFields(v);
251 v->visit("Input", fInput);
252 v->visit("SetHeading", fSetHeading);
253 v->visit("Path", fPath);
254
255 if (fPath != oldPath) {
256 this->rebuild();
257 }
258 }
259
260 private:
261 SkString fPath;
262 SkParticleValue fInput;
263 bool fSetHeading;
264
rebuild()265 void rebuild() {
266 SkPath path;
267 if (!SkParsePath::FromSVGString(fPath.c_str(), &path)) {
268 return;
269 }
270
271 fTotalLength = 0;
272 fContours.reset();
273
274 SkContourMeasureIter iter(path, false);
275 while (auto contour = iter.next()) {
276 fContours.push_back(contour);
277 fTotalLength += contour->length();
278 }
279 }
280
281 // Cached
282 SkScalar fTotalLength;
283 SkTArray<sk_sp<SkContourMeasure>> fContours;
284 };
285
286 class SkPositionOnTextAffector : public SkParticleAffector {
287 public:
SkPositionOnTextAffector(const char * text="",SkScalar fontSize=96,bool setHeading=true,SkParticleValue input=SkParticleValue ())288 SkPositionOnTextAffector(const char* text = "", SkScalar fontSize = 96, bool setHeading = true,
289 SkParticleValue input = SkParticleValue())
290 : fText(text)
291 , fFontSize(fontSize)
292 , fInput(input)
293 , fSetHeading(setHeading) {
294 this->rebuild();
295 }
296
REFLECTED(SkPositionOnTextAffector,SkParticleAffector)297 REFLECTED(SkPositionOnTextAffector, SkParticleAffector)
298
299 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
300 if (fContours.empty()) {
301 return;
302 }
303
304 // TODO: Refactor to share code with PositionOnPathAffector
305 for (int i = 0; i < count; ++i) {
306 float t = fInput.eval(params, ps[i]);
307 SkScalar len = fTotalLength * t;
308 int idx = 0;
309 while (idx < fContours.count() && len > fContours[idx]->length()) {
310 len -= fContours[idx++]->length();
311 }
312 SkVector localXAxis;
313 if (!fContours[idx]->getPosTan(len, &ps[i].fPose.fPosition, &localXAxis)) {
314 ps[i].fPose.fPosition = { 0, 0 };
315 localXAxis = { 1, 0 };
316 }
317 if (fSetHeading) {
318 ps[i].fPose.fHeading.set(localXAxis.fY, -localXAxis.fX);
319 }
320 }
321 }
322
visitFields(SkFieldVisitor * v)323 void visitFields(SkFieldVisitor* v) override {
324 SkString oldText = fText;
325 SkScalar oldSize = fFontSize;
326
327 SkParticleAffector::visitFields(v);
328 v->visit("Input", fInput);
329 v->visit("SetHeading", fSetHeading);
330 v->visit("Text", fText);
331 v->visit("FontSize", fFontSize);
332
333 if (fText != oldText || fFontSize != oldSize) {
334 this->rebuild();
335 }
336 }
337
338 private:
339 SkString fText;
340 SkScalar fFontSize;
341 SkParticleValue fInput;
342 bool fSetHeading;
343
rebuild()344 void rebuild() {
345 fTotalLength = 0;
346 fContours.reset();
347
348 if (fText.isEmpty()) {
349 return;
350 }
351
352 // Use the font manager's default font
353 SkFont font(nullptr, fFontSize);
354 SkPath path;
355 SkTextUtils::GetPath(fText.c_str(), fText.size(), kUTF8_SkTextEncoding, 0, 0, font, &path);
356 SkContourMeasureIter iter(path, false);
357 while (auto contour = iter.next()) {
358 fContours.push_back(contour);
359 fTotalLength += contour->length();
360 }
361 }
362
363 // Cached
364 SkScalar fTotalLength;
365 SkTArray<sk_sp<SkContourMeasure>> fContours;
366 };
367
368 class SkSizeAffector : public SkParticleAffector {
369 public:
SkSizeAffector(const SkCurve & curve=1.0f)370 SkSizeAffector(const SkCurve& curve = 1.0f) : fCurve(curve) {}
371
REFLECTED(SkSizeAffector,SkParticleAffector)372 REFLECTED(SkSizeAffector, SkParticleAffector)
373
374 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
375 for (int i = 0; i < count; ++i) {
376 ps[i].fPose.fScale = fCurve.eval(params, ps[i]);
377 }
378 }
379
visitFields(SkFieldVisitor * v)380 void visitFields(SkFieldVisitor* v) override {
381 SkParticleAffector::visitFields(v);
382 v->visit("Curve", fCurve);
383 }
384
385 private:
386 SkCurve fCurve;
387 };
388
389 class SkFrameAffector : public SkParticleAffector {
390 public:
SkFrameAffector(const SkCurve & curve=1.0f)391 SkFrameAffector(const SkCurve& curve = 1.0f) : fCurve(curve) {}
392
REFLECTED(SkFrameAffector,SkParticleAffector)393 REFLECTED(SkFrameAffector, SkParticleAffector)
394
395 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
396 for (int i = 0; i < count; ++i) {
397 ps[i].fFrame = fCurve.eval(params, ps[i]);
398 }
399 }
400
visitFields(SkFieldVisitor * v)401 void visitFields(SkFieldVisitor* v) override {
402 SkParticleAffector::visitFields(v);
403 v->visit("Curve", fCurve);
404 }
405
406 private:
407 SkCurve fCurve;
408 };
409
410 class SkColorAffector : public SkParticleAffector {
411 public:
SkColorAffector(const SkColorCurve & curve=SkColor4f{ 1.0f, 1.0f, 1.0f, 1.0f })412 SkColorAffector(const SkColorCurve& curve = SkColor4f{ 1.0f, 1.0f, 1.0f, 1.0f })
413 : fCurve(curve) {}
414
REFLECTED(SkColorAffector,SkParticleAffector)415 REFLECTED(SkColorAffector, SkParticleAffector)
416
417 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
418 for (int i = 0; i < count; ++i) {
419 ps[i].fColor = fCurve.eval(params, ps[i]);
420 }
421 }
422
visitFields(SkFieldVisitor * v)423 void visitFields(SkFieldVisitor* v) override {
424 SkParticleAffector::visitFields(v);
425 v->visit("Curve", fCurve);
426 }
427
428 private:
429 SkColorCurve fCurve;
430 };
431
RegisterAffectorTypes()432 void SkParticleAffector::RegisterAffectorTypes() {
433 REGISTER_REFLECTED(SkParticleAffector);
434 REGISTER_REFLECTED(SkLinearVelocityAffector);
435 REGISTER_REFLECTED(SkAngularVelocityAffector);
436 REGISTER_REFLECTED(SkPointForceAffector);
437 REGISTER_REFLECTED(SkOrientationAffector);
438 REGISTER_REFLECTED(SkPositionInCircleAffector);
439 REGISTER_REFLECTED(SkPositionOnPathAffector);
440 REGISTER_REFLECTED(SkPositionOnTextAffector);
441 REGISTER_REFLECTED(SkSizeAffector);
442 REGISTER_REFLECTED(SkFrameAffector);
443 REGISTER_REFLECTED(SkColorAffector);
444 }
445
MakeLinearVelocity(const SkCurve & angle,const SkCurve & strength,bool force,SkParticleFrame frame)446 sk_sp<SkParticleAffector> SkParticleAffector::MakeLinearVelocity(const SkCurve& angle,
447 const SkCurve& strength,
448 bool force,
449 SkParticleFrame frame) {
450 return sk_sp<SkParticleAffector>(new SkLinearVelocityAffector(angle, strength, force, frame));
451 }
452
MakeAngularVelocity(const SkCurve & strength,bool force)453 sk_sp<SkParticleAffector> SkParticleAffector::MakeAngularVelocity(const SkCurve& strength,
454 bool force) {
455 return sk_sp<SkParticleAffector>(new SkAngularVelocityAffector(strength, force));
456 }
457
MakePointForce(SkPoint point,SkScalar constant,SkScalar invSquare)458 sk_sp<SkParticleAffector> SkParticleAffector::MakePointForce(SkPoint point, SkScalar constant,
459 SkScalar invSquare) {
460 return sk_sp<SkParticleAffector>(new SkPointForceAffector(point, constant, invSquare));
461 }
462
MakeOrientation(const SkCurve & angle,SkParticleFrame frame)463 sk_sp<SkParticleAffector> SkParticleAffector::MakeOrientation(const SkCurve& angle,
464 SkParticleFrame frame) {
465 return sk_sp<SkParticleAffector>(new SkOrientationAffector(angle, frame));
466 }
467
MakeSize(const SkCurve & curve)468 sk_sp<SkParticleAffector> SkParticleAffector::MakeSize(const SkCurve& curve) {
469 return sk_sp<SkParticleAffector>(new SkSizeAffector(curve));
470 }
471
MakeFrame(const SkCurve & curve)472 sk_sp<SkParticleAffector> SkParticleAffector::MakeFrame(const SkCurve& curve) {
473 return sk_sp<SkParticleAffector>(new SkFrameAffector(curve));
474 }
475
MakeColor(const SkColorCurve & curve)476 sk_sp<SkParticleAffector> SkParticleAffector::MakeColor(const SkColorCurve& curve) {
477 return sk_sp<SkParticleAffector>(new SkColorAffector(curve));
478 }
479