blob: 29008810f9e9382296fa5afa6251ad364aa494d2 [file] [log] [blame]
Brian Osman7c979f52019-02-12 13:27:51 -05001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "modules/particles/include/SkParticleAffector.h"
Brian Osman7c979f52019-02-12 13:27:51 -05009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkContourMeasure.h"
11#include "include/core/SkPath.h"
12#include "include/utils/SkParsePath.h"
13#include "include/utils/SkRandom.h"
14#include "include/utils/SkTextUtils.h"
15#include "modules/particles/include/SkCurve.h"
16#include "modules/particles/include/SkParticleData.h"
Brian Osmane246b132019-05-09 15:42:21 -040017
18#if SK_SUPPORT_GPU
Brian Osmanc04cadb2019-05-09 14:05:04 -040019#include "src/sksl/SkSLCompiler.h"
20#include "src/sksl/SkSLInterpreter.h"
Brian Osmane246b132019-05-09 15:42:21 -040021#endif
Brian Osman7c979f52019-02-12 13:27:51 -050022
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050023void SkParticleAffector::apply(const SkParticleUpdateParams& params,
24 SkParticleState ps[], int count) {
Brian Osman1b20cd82019-02-25 14:15:02 -050025 if (fEnabled) {
Brian Osman14a67a32019-02-25 14:30:44 -050026 this->onApply(params, ps, count);
Brian Osman1b20cd82019-02-25 14:15:02 -050027 }
28}
29
30void SkParticleAffector::visitFields(SkFieldVisitor* v) {
31 v->visit("Enabled", fEnabled);
32}
33
Brian Osman8b6283f2019-02-14 16:55:21 -050034class SkLinearVelocityAffector : public SkParticleAffector {
Brian Osman7c979f52019-02-12 13:27:51 -050035public:
Brian Osman8b6283f2019-02-14 16:55:21 -050036 SkLinearVelocityAffector(const SkCurve& angle = 0.0f,
37 const SkCurve& strength = 0.0f,
Brian Osmand5c57fe2019-02-22 11:48:18 -050038 bool force = true,
Brian Osman0c486812019-02-26 10:02:15 -050039 SkParticleFrame frame = kWorld_ParticleFrame)
Brian Osman8b6283f2019-02-14 16:55:21 -050040 : fAngle(angle)
41 , fStrength(strength)
Brian Osmand5c57fe2019-02-22 11:48:18 -050042 , fForce(force)
Brian Osman0c486812019-02-26 10:02:15 -050043 , fFrame(frame) {}
Brian Osman7c979f52019-02-12 13:27:51 -050044
Brian Osman8b6283f2019-02-14 16:55:21 -050045 REFLECTED(SkLinearVelocityAffector, SkParticleAffector)
Brian Osman7c979f52019-02-12 13:27:51 -050046
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050047 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -050048 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050049 float angle = fAngle.eval(params, ps[i]);
Brian Osman4428f2c2019-04-02 10:59:28 -040050 SkScalar rad = SkDegreesToRadians(angle);
51 SkScalar s_local = SkScalarSin(rad),
52 c_local = SkScalarCos(rad);
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050053 SkVector heading = ps[i].getFrameHeading(static_cast<SkParticleFrame>(fFrame));
Brian Osman14a67a32019-02-25 14:30:44 -050054 SkScalar c = heading.fX * c_local - heading.fY * s_local;
55 SkScalar s = heading.fX * s_local + heading.fY * c_local;
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050056 float strength = fStrength.eval(params, ps[i]);
Brian Osman14a67a32019-02-25 14:30:44 -050057 SkVector force = { c * strength, s * strength };
58 if (fForce) {
59 ps[i].fVelocity.fLinear += force * params.fDeltaTime;
60 } else {
61 ps[i].fVelocity.fLinear = force;
62 }
Brian Osman8b6283f2019-02-14 16:55:21 -050063 }
Brian Osman7c979f52019-02-12 13:27:51 -050064 }
65
66 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -050067 SkParticleAffector::visitFields(v);
Brian Osman7c979f52019-02-12 13:27:51 -050068 v->visit("Force", fForce);
Brian Osmane5d532e2019-02-26 14:58:40 -050069 v->visit("Frame", fFrame, gParticleFrameMapping, SK_ARRAY_COUNT(gParticleFrameMapping));
Brian Osman7c979f52019-02-12 13:27:51 -050070 v->visit("Angle", fAngle);
71 v->visit("Strength", fStrength);
Brian Osman7c979f52019-02-12 13:27:51 -050072 }
73
74private:
75 SkCurve fAngle;
76 SkCurve fStrength;
Brian Osman8b6283f2019-02-14 16:55:21 -050077 bool fForce;
Brian Osman0c486812019-02-26 10:02:15 -050078 int fFrame;
79};
80
81class SkAngularVelocityAffector : public SkParticleAffector {
82public:
83 SkAngularVelocityAffector(const SkCurve& strength = 0.0f, bool force = true)
84 : fStrength(strength)
85 , fForce(force) {}
86
87 REFLECTED(SkAngularVelocityAffector, SkParticleAffector)
88
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050089 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman0c486812019-02-26 10:02:15 -050090 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050091 float strength = fStrength.eval(params, ps[i]);
Brian Osman0c486812019-02-26 10:02:15 -050092 if (fForce) {
93 ps[i].fVelocity.fAngular += strength * params.fDeltaTime;
94 } else {
95 ps[i].fVelocity.fAngular = strength;
96 }
97 }
98 }
99
100 void visitFields(SkFieldVisitor* v) override {
101 SkParticleAffector::visitFields(v);
102 v->visit("Force", fForce);
103 v->visit("Strength", fStrength);
104 }
105
106private:
107 SkCurve fStrength;
108 bool fForce;
Brian Osman7c979f52019-02-12 13:27:51 -0500109};
110
111class SkPointForceAffector : public SkParticleAffector {
112public:
113 SkPointForceAffector(SkPoint point = { 0.0f, 0.0f }, SkScalar constant = 0.0f,
114 SkScalar invSquare = 0.0f)
115 : fPoint(point), fConstant(constant), fInvSquare(invSquare) {}
116
117 REFLECTED(SkPointForceAffector, SkParticleAffector)
118
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500119 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -0500120 for (int i = 0; i < count; ++i) {
121 SkVector toPoint = fPoint - ps[i].fPose.fPosition;
122 SkScalar lenSquare = toPoint.dot(toPoint);
123 toPoint.normalize();
124 ps[i].fVelocity.fLinear +=
125 toPoint * (fConstant + (fInvSquare / lenSquare)) * params.fDeltaTime;
126 }
Brian Osman7c979f52019-02-12 13:27:51 -0500127 }
128
129 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500130 SkParticleAffector::visitFields(v);
Brian Osman7c979f52019-02-12 13:27:51 -0500131 v->visit("Point", fPoint);
132 v->visit("Constant", fConstant);
133 v->visit("InvSquare", fInvSquare);
134 }
135
136private:
137 SkPoint fPoint;
138 SkScalar fConstant;
139 SkScalar fInvSquare;
140};
141
Brian Osman0c486812019-02-26 10:02:15 -0500142class SkOrientationAffector : public SkParticleAffector {
Brian Osman7c979f52019-02-12 13:27:51 -0500143public:
Brian Osman0c486812019-02-26 10:02:15 -0500144 SkOrientationAffector(const SkCurve& angle = 0.0f,
145 SkParticleFrame frame = kLocal_ParticleFrame)
146 : fAngle(angle)
147 , fFrame(frame) {}
Brian Osman7c979f52019-02-12 13:27:51 -0500148
Brian Osman0c486812019-02-26 10:02:15 -0500149 REFLECTED(SkOrientationAffector, SkParticleAffector)
Brian Osman7c979f52019-02-12 13:27:51 -0500150
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500151 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -0500152 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500153 float angle = fAngle.eval(params, ps[i]);
Brian Osman4428f2c2019-04-02 10:59:28 -0400154 SkScalar rad = SkDegreesToRadians(angle);
155 SkScalar s_local = SkScalarSin(rad),
156 c_local = SkScalarCos(rad);
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500157 SkVector heading = ps[i].getFrameHeading(static_cast<SkParticleFrame>(fFrame));
Brian Osman0c486812019-02-26 10:02:15 -0500158 ps[i].fPose.fHeading.set(heading.fX * c_local - heading.fY * s_local,
159 heading.fX * s_local + heading.fY * c_local);
Brian Osman7c979f52019-02-12 13:27:51 -0500160 }
Brian Osman7c979f52019-02-12 13:27:51 -0500161 }
162
Brian Osman1b20cd82019-02-25 14:15:02 -0500163 void visitFields(SkFieldVisitor *v) override {
164 SkParticleAffector::visitFields(v);
Brian Osmane5d532e2019-02-26 14:58:40 -0500165 v->visit("Frame", fFrame, gParticleFrameMapping, SK_ARRAY_COUNT(gParticleFrameMapping));
Brian Osman0c486812019-02-26 10:02:15 -0500166 v->visit("Angle", fAngle);
Brian Osman1b20cd82019-02-25 14:15:02 -0500167 }
Brian Osman0c486812019-02-26 10:02:15 -0500168
169private:
170 SkCurve fAngle;
171 int fFrame;
Brian Osman7c979f52019-02-12 13:27:51 -0500172};
173
Brian Osman3d76d1b2019-02-28 15:48:05 -0500174class SkPositionInCircleAffector : public SkParticleAffector {
175public:
176 SkPositionInCircleAffector(const SkCurve& x = 0.0f, const SkCurve& y = 0.0f,
177 const SkCurve& radius = 0.0f, bool setHeading = true)
178 : fX(x)
179 , fY(y)
180 , fRadius(radius)
181 , fSetHeading(setHeading) {}
182
183 REFLECTED(SkPositionInCircleAffector, SkParticleAffector)
184
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500185 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman3d76d1b2019-02-28 15:48:05 -0500186 for (int i = 0; i < count; ++i) {
187 SkVector v;
188 do {
189 v.fX = ps[i].fRandom.nextSScalar1();
190 v.fY = ps[i].fRandom.nextSScalar1();
191 } while (v.dot(v) > 1);
192
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500193 SkPoint center = { fX.eval(params, ps[i]), fY.eval(params, ps[i]) };
194 SkScalar radius = fRadius.eval(params, ps[i]);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500195 ps[i].fPose.fPosition = center + (v * radius);
196 if (fSetHeading) {
197 if (!v.normalize()) {
198 v.set(0, -1);
199 }
200 ps[i].fPose.fHeading = v;
201 }
202 }
203 }
204
205 void visitFields(SkFieldVisitor* v) override {
206 SkParticleAffector::visitFields(v);
207 v->visit("SetHeading", fSetHeading);
208 v->visit("X", fX);
209 v->visit("Y", fY);
210 v->visit("Radius", fRadius);
211 }
212
213private:
214 SkCurve fX;
215 SkCurve fY;
216 SkCurve fRadius;
217 bool fSetHeading;
218};
219
220class SkPositionOnPathAffector : public SkParticleAffector {
221public:
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500222 SkPositionOnPathAffector(const char* path = "", bool setHeading = true,
223 SkParticleValue input = SkParticleValue())
Brian Osman3d76d1b2019-02-28 15:48:05 -0500224 : fPath(path)
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500225 , fInput(input)
226 , fSetHeading(setHeading) {
Brian Osman3d76d1b2019-02-28 15:48:05 -0500227 this->rebuild();
228 }
229
230 REFLECTED(SkPositionOnPathAffector, SkParticleAffector)
231
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500232 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman3d76d1b2019-02-28 15:48:05 -0500233 if (fContours.empty()) {
234 return;
235 }
236
237 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500238 float t = fInput.eval(params, ps[i]);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500239 SkScalar len = fTotalLength * t;
240 int idx = 0;
241 while (idx < fContours.count() && len > fContours[idx]->length()) {
242 len -= fContours[idx++]->length();
243 }
244 SkVector localXAxis;
245 if (!fContours[idx]->getPosTan(len, &ps[i].fPose.fPosition, &localXAxis)) {
246 ps[i].fPose.fPosition = { 0, 0 };
247 localXAxis = { 1, 0 };
248 }
249 if (fSetHeading) {
250 ps[i].fPose.fHeading.set(localXAxis.fY, -localXAxis.fX);
251 }
252 }
253 }
254
255 void visitFields(SkFieldVisitor* v) override {
256 SkString oldPath = fPath;
257
258 SkParticleAffector::visitFields(v);
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500259 v->visit("Input", fInput);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500260 v->visit("SetHeading", fSetHeading);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500261 v->visit("Path", fPath);
262
263 if (fPath != oldPath) {
264 this->rebuild();
265 }
266 }
267
268private:
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500269 SkString fPath;
270 SkParticleValue fInput;
271 bool fSetHeading;
Brian Osman3d76d1b2019-02-28 15:48:05 -0500272
273 void rebuild() {
274 SkPath path;
275 if (!SkParsePath::FromSVGString(fPath.c_str(), &path)) {
276 return;
277 }
278
279 fTotalLength = 0;
280 fContours.reset();
281
282 SkContourMeasureIter iter(path, false);
283 while (auto contour = iter.next()) {
284 fContours.push_back(contour);
285 fTotalLength += contour->length();
286 }
287 }
288
289 // Cached
290 SkScalar fTotalLength;
291 SkTArray<sk_sp<SkContourMeasure>> fContours;
292};
293
294class SkPositionOnTextAffector : public SkParticleAffector {
295public:
296 SkPositionOnTextAffector(const char* text = "", SkScalar fontSize = 96, bool setHeading = true,
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500297 SkParticleValue input = SkParticleValue())
Brian Osman3d76d1b2019-02-28 15:48:05 -0500298 : fText(text)
299 , fFontSize(fontSize)
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500300 , fInput(input)
301 , fSetHeading(setHeading) {
Brian Osman3d76d1b2019-02-28 15:48:05 -0500302 this->rebuild();
303 }
304
305 REFLECTED(SkPositionOnTextAffector, SkParticleAffector)
306
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500307 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman3d76d1b2019-02-28 15:48:05 -0500308 if (fContours.empty()) {
309 return;
310 }
311
312 // TODO: Refactor to share code with PositionOnPathAffector
313 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500314 float t = fInput.eval(params, ps[i]);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500315 SkScalar len = fTotalLength * t;
316 int idx = 0;
317 while (idx < fContours.count() && len > fContours[idx]->length()) {
318 len -= fContours[idx++]->length();
319 }
320 SkVector localXAxis;
321 if (!fContours[idx]->getPosTan(len, &ps[i].fPose.fPosition, &localXAxis)) {
322 ps[i].fPose.fPosition = { 0, 0 };
323 localXAxis = { 1, 0 };
324 }
325 if (fSetHeading) {
326 ps[i].fPose.fHeading.set(localXAxis.fY, -localXAxis.fX);
327 }
328 }
329 }
330
331 void visitFields(SkFieldVisitor* v) override {
332 SkString oldText = fText;
333 SkScalar oldSize = fFontSize;
334
335 SkParticleAffector::visitFields(v);
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500336 v->visit("Input", fInput);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500337 v->visit("SetHeading", fSetHeading);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500338 v->visit("Text", fText);
339 v->visit("FontSize", fFontSize);
340
341 if (fText != oldText || fFontSize != oldSize) {
342 this->rebuild();
343 }
344 }
345
346private:
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500347 SkString fText;
348 SkScalar fFontSize;
349 SkParticleValue fInput;
350 bool fSetHeading;
Brian Osman3d76d1b2019-02-28 15:48:05 -0500351
352 void rebuild() {
353 fTotalLength = 0;
354 fContours.reset();
355
356 if (fText.isEmpty()) {
357 return;
358 }
359
Kevin Lubick96634842019-03-05 14:09:24 -0500360 // Use the font manager's default font
361 SkFont font(nullptr, fFontSize);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500362 SkPath path;
Ben Wagner51e15a62019-05-07 15:38:46 -0400363 SkTextUtils::GetPath(fText.c_str(), fText.size(), SkTextEncoding::kUTF8, 0, 0, font, &path);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500364 SkContourMeasureIter iter(path, false);
365 while (auto contour = iter.next()) {
366 fContours.push_back(contour);
367 fTotalLength += contour->length();
368 }
369 }
370
371 // Cached
372 SkScalar fTotalLength;
373 SkTArray<sk_sp<SkContourMeasure>> fContours;
374};
375
Brian Osman8b6283f2019-02-14 16:55:21 -0500376class SkSizeAffector : public SkParticleAffector {
Brian Osman7c979f52019-02-12 13:27:51 -0500377public:
Brian Osman8b6283f2019-02-14 16:55:21 -0500378 SkSizeAffector(const SkCurve& curve = 1.0f) : fCurve(curve) {}
Brian Osman7c979f52019-02-12 13:27:51 -0500379
Brian Osman8b6283f2019-02-14 16:55:21 -0500380 REFLECTED(SkSizeAffector, SkParticleAffector)
Brian Osman7c979f52019-02-12 13:27:51 -0500381
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500382 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -0500383 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500384 ps[i].fPose.fScale = fCurve.eval(params, ps[i]);
Brian Osman14a67a32019-02-25 14:30:44 -0500385 }
Brian Osman7c979f52019-02-12 13:27:51 -0500386 }
387
388 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500389 SkParticleAffector::visitFields(v);
Brian Osman8b6283f2019-02-14 16:55:21 -0500390 v->visit("Curve", fCurve);
Brian Osman7c979f52019-02-12 13:27:51 -0500391 }
392
393private:
Brian Osman8b6283f2019-02-14 16:55:21 -0500394 SkCurve fCurve;
Brian Osman7c979f52019-02-12 13:27:51 -0500395};
396
Brian Osman125daa42019-02-20 12:25:20 -0500397class SkFrameAffector : public SkParticleAffector {
398public:
399 SkFrameAffector(const SkCurve& curve = 1.0f) : fCurve(curve) {}
400
401 REFLECTED(SkFrameAffector, SkParticleAffector)
402
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500403 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -0500404 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500405 ps[i].fFrame = fCurve.eval(params, ps[i]);
Brian Osman14a67a32019-02-25 14:30:44 -0500406 }
Brian Osman125daa42019-02-20 12:25:20 -0500407 }
408
409 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500410 SkParticleAffector::visitFields(v);
Brian Osman125daa42019-02-20 12:25:20 -0500411 v->visit("Curve", fCurve);
412 }
413
414private:
415 SkCurve fCurve;
416};
417
418class SkColorAffector : public SkParticleAffector {
419public:
420 SkColorAffector(const SkColorCurve& curve = SkColor4f{ 1.0f, 1.0f, 1.0f, 1.0f })
421 : fCurve(curve) {}
422
423 REFLECTED(SkColorAffector, SkParticleAffector)
424
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500425 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -0500426 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500427 ps[i].fColor = fCurve.eval(params, ps[i]);
Brian Osman14a67a32019-02-25 14:30:44 -0500428 }
Brian Osman125daa42019-02-20 12:25:20 -0500429 }
430
431 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500432 SkParticleAffector::visitFields(v);
Brian Osman125daa42019-02-20 12:25:20 -0500433 v->visit("Curve", fCurve);
434 }
435
436private:
437 SkColorCurve fCurve;
438};
439
Brian Osmane246b132019-05-09 15:42:21 -0400440#if SK_SUPPORT_GPU
Brian Osmanc04cadb2019-05-09 14:05:04 -0400441static const char* kDefaultCode =
442 "layout(ctype=float) in uniform float dt;\n"
443 "layout(ctype=float) in uniform float effectAge;\n"
444 "\n"
445 "void main(in float age,\n"
446 " in float invLifetime,\n"
447 " inout float2 pos,\n"
448 " inout float2 dir,\n"
449 " inout float scale,\n"
450 " inout float2 vel,\n"
451 " inout float spin,\n"
452 " inout float4 color,\n"
453 " in float t) {\n"
454 "}\n";
455
456class SkInterpreterAffector : public SkParticleAffector {
457public:
458 SkInterpreterAffector() : fCode(kDefaultCode) {
459 this->rebuild();
460 }
461
462 REFLECTED(SkInterpreterAffector, SkParticleAffector)
463
464 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
465 fInterpreter->setInputs((SkSL::Interpreter::Value*)&params);
466 for (int i = 0; i < count; ++i) {
467 fInterpreter->run(*fMain, (SkSL::Interpreter::Value*)&ps[i].fAge, nullptr);
468 }
469 }
470
471 void visitFields(SkFieldVisitor* v) override {
472 SkString oldCode = fCode;
473
474 SkParticleAffector::visitFields(v);
475 v->visit("Code", fCode);
476
477 if (fCode != oldCode) {
478 this->rebuild();
479 }
480 }
481
482private:
483 SkString fCode;
484
485 // Cached
486 std::unique_ptr<SkSL::Interpreter> fInterpreter;
487 SkSL::ByteCodeFunction* fMain;
488
489 void rebuild() {
490 SkSL::Compiler compiler;
491 SkSL::Program::Settings settings;
492 auto program = compiler.convertProgram(SkSL::Program::kGeneric_Kind,
493 SkSL::String(fCode.c_str()), settings);
494 if (!program) {
495 SkDebugf("%s\n", compiler.errorText().c_str());
496 return;
497 }
498
499 auto byteCode = compiler.toByteCode(*program);
500 if (compiler.errorCount()) {
501 SkDebugf("%s\n", compiler.errorText().c_str());
502 return;
503 }
504
505 // These will be replaced with the real inputs in onApply, before running
506 SkParticleUpdateParams defaultInputs = { 0.0f, 0.0f, 0 };
507 fMain = byteCode->fFunctions[0].get();
508 fInterpreter.reset(new SkSL::Interpreter(std::move(program), std::move(byteCode),
509 (SkSL::Interpreter::Value*)&defaultInputs));
510 }
511};
Brian Osmane246b132019-05-09 15:42:21 -0400512#endif
Brian Osmanc04cadb2019-05-09 14:05:04 -0400513
Brian Osman7c979f52019-02-12 13:27:51 -0500514void SkParticleAffector::RegisterAffectorTypes() {
515 REGISTER_REFLECTED(SkParticleAffector);
Brian Osman8b6283f2019-02-14 16:55:21 -0500516 REGISTER_REFLECTED(SkLinearVelocityAffector);
Brian Osman0c486812019-02-26 10:02:15 -0500517 REGISTER_REFLECTED(SkAngularVelocityAffector);
Brian Osman7c979f52019-02-12 13:27:51 -0500518 REGISTER_REFLECTED(SkPointForceAffector);
Brian Osman0c486812019-02-26 10:02:15 -0500519 REGISTER_REFLECTED(SkOrientationAffector);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500520 REGISTER_REFLECTED(SkPositionInCircleAffector);
521 REGISTER_REFLECTED(SkPositionOnPathAffector);
522 REGISTER_REFLECTED(SkPositionOnTextAffector);
Brian Osman8b6283f2019-02-14 16:55:21 -0500523 REGISTER_REFLECTED(SkSizeAffector);
Brian Osman125daa42019-02-20 12:25:20 -0500524 REGISTER_REFLECTED(SkFrameAffector);
525 REGISTER_REFLECTED(SkColorAffector);
Brian Osmane246b132019-05-09 15:42:21 -0400526#if SK_SUPPORT_GPU
Brian Osmanc04cadb2019-05-09 14:05:04 -0400527 REGISTER_REFLECTED(SkInterpreterAffector);
Brian Osmane246b132019-05-09 15:42:21 -0400528#endif
Brian Osman7c979f52019-02-12 13:27:51 -0500529}
530
Brian Osman8b6283f2019-02-14 16:55:21 -0500531sk_sp<SkParticleAffector> SkParticleAffector::MakeLinearVelocity(const SkCurve& angle,
532 const SkCurve& strength,
Brian Osmand5c57fe2019-02-22 11:48:18 -0500533 bool force,
Brian Osman0c486812019-02-26 10:02:15 -0500534 SkParticleFrame frame) {
535 return sk_sp<SkParticleAffector>(new SkLinearVelocityAffector(angle, strength, force, frame));
536}
537
538sk_sp<SkParticleAffector> SkParticleAffector::MakeAngularVelocity(const SkCurve& strength,
539 bool force) {
540 return sk_sp<SkParticleAffector>(new SkAngularVelocityAffector(strength, force));
Brian Osman7c979f52019-02-12 13:27:51 -0500541}
542
Brian Osman8b6283f2019-02-14 16:55:21 -0500543sk_sp<SkParticleAffector> SkParticleAffector::MakePointForce(SkPoint point, SkScalar constant,
544 SkScalar invSquare) {
Brian Osman7c979f52019-02-12 13:27:51 -0500545 return sk_sp<SkParticleAffector>(new SkPointForceAffector(point, constant, invSquare));
546}
547
Brian Osman0c486812019-02-26 10:02:15 -0500548sk_sp<SkParticleAffector> SkParticleAffector::MakeOrientation(const SkCurve& angle,
549 SkParticleFrame frame) {
550 return sk_sp<SkParticleAffector>(new SkOrientationAffector(angle, frame));
Brian Osman7c979f52019-02-12 13:27:51 -0500551}
Brian Osman8b6283f2019-02-14 16:55:21 -0500552
Brian Osman125daa42019-02-20 12:25:20 -0500553sk_sp<SkParticleAffector> SkParticleAffector::MakeSize(const SkCurve& curve) {
Brian Osman8b6283f2019-02-14 16:55:21 -0500554 return sk_sp<SkParticleAffector>(new SkSizeAffector(curve));
555}
Brian Osman125daa42019-02-20 12:25:20 -0500556
557sk_sp<SkParticleAffector> SkParticleAffector::MakeFrame(const SkCurve& curve) {
558 return sk_sp<SkParticleAffector>(new SkFrameAffector(curve));
559}
560
561sk_sp<SkParticleAffector> SkParticleAffector::MakeColor(const SkColorCurve& curve) {
562 return sk_sp<SkParticleAffector>(new SkColorAffector(curve));
563}