• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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