blob: 17ca75b20e9ae092bf2459a9cb52b371c719b056 [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 Osmanc04cadb2019-05-09 14:05:04 -040017#include "src/sksl/SkSLCompiler.h"
18#include "src/sksl/SkSLInterpreter.h"
Brian Osman3d76d1b2019-02-28 15:48:05 -050019
Brian Osman7c979f52019-02-12 13:27:51 -050020
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050021void SkParticleAffector::apply(const SkParticleUpdateParams& params,
22 SkParticleState ps[], int count) {
Brian Osman1b20cd82019-02-25 14:15:02 -050023 if (fEnabled) {
Brian Osman14a67a32019-02-25 14:30:44 -050024 this->onApply(params, ps, count);
Brian Osman1b20cd82019-02-25 14:15:02 -050025 }
26}
27
28void SkParticleAffector::visitFields(SkFieldVisitor* v) {
29 v->visit("Enabled", fEnabled);
30}
31
Brian Osman8b6283f2019-02-14 16:55:21 -050032class SkLinearVelocityAffector : public SkParticleAffector {
Brian Osman7c979f52019-02-12 13:27:51 -050033public:
Brian Osman8b6283f2019-02-14 16:55:21 -050034 SkLinearVelocityAffector(const SkCurve& angle = 0.0f,
35 const SkCurve& strength = 0.0f,
Brian Osmand5c57fe2019-02-22 11:48:18 -050036 bool force = true,
Brian Osman0c486812019-02-26 10:02:15 -050037 SkParticleFrame frame = kWorld_ParticleFrame)
Brian Osman8b6283f2019-02-14 16:55:21 -050038 : fAngle(angle)
39 , fStrength(strength)
Brian Osmand5c57fe2019-02-22 11:48:18 -050040 , fForce(force)
Brian Osman0c486812019-02-26 10:02:15 -050041 , fFrame(frame) {}
Brian Osman7c979f52019-02-12 13:27:51 -050042
Brian Osman8b6283f2019-02-14 16:55:21 -050043 REFLECTED(SkLinearVelocityAffector, SkParticleAffector)
Brian Osman7c979f52019-02-12 13:27:51 -050044
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050045 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -050046 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050047 float angle = fAngle.eval(params, ps[i]);
Brian Osman4428f2c2019-04-02 10:59:28 -040048 SkScalar rad = SkDegreesToRadians(angle);
49 SkScalar s_local = SkScalarSin(rad),
50 c_local = SkScalarCos(rad);
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050051 SkVector heading = ps[i].getFrameHeading(static_cast<SkParticleFrame>(fFrame));
Brian Osman14a67a32019-02-25 14:30:44 -050052 SkScalar c = heading.fX * c_local - heading.fY * s_local;
53 SkScalar s = heading.fX * s_local + heading.fY * c_local;
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050054 float strength = fStrength.eval(params, ps[i]);
Brian Osman14a67a32019-02-25 14:30:44 -050055 SkVector force = { c * strength, s * strength };
56 if (fForce) {
57 ps[i].fVelocity.fLinear += force * params.fDeltaTime;
58 } else {
59 ps[i].fVelocity.fLinear = force;
60 }
Brian Osman8b6283f2019-02-14 16:55:21 -050061 }
Brian Osman7c979f52019-02-12 13:27:51 -050062 }
63
64 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -050065 SkParticleAffector::visitFields(v);
Brian Osman7c979f52019-02-12 13:27:51 -050066 v->visit("Force", fForce);
Brian Osmane5d532e2019-02-26 14:58:40 -050067 v->visit("Frame", fFrame, gParticleFrameMapping, SK_ARRAY_COUNT(gParticleFrameMapping));
Brian Osman7c979f52019-02-12 13:27:51 -050068 v->visit("Angle", fAngle);
69 v->visit("Strength", fStrength);
Brian Osman7c979f52019-02-12 13:27:51 -050070 }
71
72private:
73 SkCurve fAngle;
74 SkCurve fStrength;
Brian Osman8b6283f2019-02-14 16:55:21 -050075 bool fForce;
Brian Osman0c486812019-02-26 10:02:15 -050076 int fFrame;
77};
78
79class SkAngularVelocityAffector : public SkParticleAffector {
80public:
81 SkAngularVelocityAffector(const SkCurve& strength = 0.0f, bool force = true)
82 : fStrength(strength)
83 , fForce(force) {}
84
85 REFLECTED(SkAngularVelocityAffector, SkParticleAffector)
86
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050087 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman0c486812019-02-26 10:02:15 -050088 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050089 float strength = fStrength.eval(params, ps[i]);
Brian Osman0c486812019-02-26 10:02:15 -050090 if (fForce) {
91 ps[i].fVelocity.fAngular += strength * params.fDeltaTime;
92 } else {
93 ps[i].fVelocity.fAngular = strength;
94 }
95 }
96 }
97
98 void visitFields(SkFieldVisitor* v) override {
99 SkParticleAffector::visitFields(v);
100 v->visit("Force", fForce);
101 v->visit("Strength", fStrength);
102 }
103
104private:
105 SkCurve fStrength;
106 bool fForce;
Brian Osman7c979f52019-02-12 13:27:51 -0500107};
108
109class SkPointForceAffector : public SkParticleAffector {
110public:
111 SkPointForceAffector(SkPoint point = { 0.0f, 0.0f }, SkScalar constant = 0.0f,
112 SkScalar invSquare = 0.0f)
113 : fPoint(point), fConstant(constant), fInvSquare(invSquare) {}
114
115 REFLECTED(SkPointForceAffector, SkParticleAffector)
116
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500117 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -0500118 for (int i = 0; i < count; ++i) {
119 SkVector toPoint = fPoint - ps[i].fPose.fPosition;
120 SkScalar lenSquare = toPoint.dot(toPoint);
121 toPoint.normalize();
122 ps[i].fVelocity.fLinear +=
123 toPoint * (fConstant + (fInvSquare / lenSquare)) * params.fDeltaTime;
124 }
Brian Osman7c979f52019-02-12 13:27:51 -0500125 }
126
127 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500128 SkParticleAffector::visitFields(v);
Brian Osman7c979f52019-02-12 13:27:51 -0500129 v->visit("Point", fPoint);
130 v->visit("Constant", fConstant);
131 v->visit("InvSquare", fInvSquare);
132 }
133
134private:
135 SkPoint fPoint;
136 SkScalar fConstant;
137 SkScalar fInvSquare;
138};
139
Brian Osman0c486812019-02-26 10:02:15 -0500140class SkOrientationAffector : public SkParticleAffector {
Brian Osman7c979f52019-02-12 13:27:51 -0500141public:
Brian Osman0c486812019-02-26 10:02:15 -0500142 SkOrientationAffector(const SkCurve& angle = 0.0f,
143 SkParticleFrame frame = kLocal_ParticleFrame)
144 : fAngle(angle)
145 , fFrame(frame) {}
Brian Osman7c979f52019-02-12 13:27:51 -0500146
Brian Osman0c486812019-02-26 10:02:15 -0500147 REFLECTED(SkOrientationAffector, SkParticleAffector)
Brian Osman7c979f52019-02-12 13:27:51 -0500148
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500149 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -0500150 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500151 float angle = fAngle.eval(params, ps[i]);
Brian Osman4428f2c2019-04-02 10:59:28 -0400152 SkScalar rad = SkDegreesToRadians(angle);
153 SkScalar s_local = SkScalarSin(rad),
154 c_local = SkScalarCos(rad);
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500155 SkVector heading = ps[i].getFrameHeading(static_cast<SkParticleFrame>(fFrame));
Brian Osman0c486812019-02-26 10:02:15 -0500156 ps[i].fPose.fHeading.set(heading.fX * c_local - heading.fY * s_local,
157 heading.fX * s_local + heading.fY * c_local);
Brian Osman7c979f52019-02-12 13:27:51 -0500158 }
Brian Osman7c979f52019-02-12 13:27:51 -0500159 }
160
Brian Osman1b20cd82019-02-25 14:15:02 -0500161 void visitFields(SkFieldVisitor *v) override {
162 SkParticleAffector::visitFields(v);
Brian Osmane5d532e2019-02-26 14:58:40 -0500163 v->visit("Frame", fFrame, gParticleFrameMapping, SK_ARRAY_COUNT(gParticleFrameMapping));
Brian Osman0c486812019-02-26 10:02:15 -0500164 v->visit("Angle", fAngle);
Brian Osman1b20cd82019-02-25 14:15:02 -0500165 }
Brian Osman0c486812019-02-26 10:02:15 -0500166
167private:
168 SkCurve fAngle;
169 int fFrame;
Brian Osman7c979f52019-02-12 13:27:51 -0500170};
171
Brian Osman3d76d1b2019-02-28 15:48:05 -0500172class SkPositionInCircleAffector : public SkParticleAffector {
173public:
174 SkPositionInCircleAffector(const SkCurve& x = 0.0f, const SkCurve& y = 0.0f,
175 const SkCurve& radius = 0.0f, bool setHeading = true)
176 : fX(x)
177 , fY(y)
178 , fRadius(radius)
179 , fSetHeading(setHeading) {}
180
181 REFLECTED(SkPositionInCircleAffector, SkParticleAffector)
182
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500183 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman3d76d1b2019-02-28 15:48:05 -0500184 for (int i = 0; i < count; ++i) {
185 SkVector v;
186 do {
187 v.fX = ps[i].fRandom.nextSScalar1();
188 v.fY = ps[i].fRandom.nextSScalar1();
189 } while (v.dot(v) > 1);
190
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500191 SkPoint center = { fX.eval(params, ps[i]), fY.eval(params, ps[i]) };
192 SkScalar radius = fRadius.eval(params, ps[i]);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500193 ps[i].fPose.fPosition = center + (v * radius);
194 if (fSetHeading) {
195 if (!v.normalize()) {
196 v.set(0, -1);
197 }
198 ps[i].fPose.fHeading = v;
199 }
200 }
201 }
202
203 void visitFields(SkFieldVisitor* v) override {
204 SkParticleAffector::visitFields(v);
205 v->visit("SetHeading", fSetHeading);
206 v->visit("X", fX);
207 v->visit("Y", fY);
208 v->visit("Radius", fRadius);
209 }
210
211private:
212 SkCurve fX;
213 SkCurve fY;
214 SkCurve fRadius;
215 bool fSetHeading;
216};
217
218class SkPositionOnPathAffector : public SkParticleAffector {
219public:
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500220 SkPositionOnPathAffector(const char* path = "", bool setHeading = true,
221 SkParticleValue input = SkParticleValue())
Brian Osman3d76d1b2019-02-28 15:48:05 -0500222 : fPath(path)
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500223 , fInput(input)
224 , fSetHeading(setHeading) {
Brian Osman3d76d1b2019-02-28 15:48:05 -0500225 this->rebuild();
226 }
227
228 REFLECTED(SkPositionOnPathAffector, SkParticleAffector)
229
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500230 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman3d76d1b2019-02-28 15:48:05 -0500231 if (fContours.empty()) {
232 return;
233 }
234
235 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500236 float t = fInput.eval(params, ps[i]);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500237 SkScalar len = fTotalLength * t;
238 int idx = 0;
239 while (idx < fContours.count() && len > fContours[idx]->length()) {
240 len -= fContours[idx++]->length();
241 }
242 SkVector localXAxis;
243 if (!fContours[idx]->getPosTan(len, &ps[i].fPose.fPosition, &localXAxis)) {
244 ps[i].fPose.fPosition = { 0, 0 };
245 localXAxis = { 1, 0 };
246 }
247 if (fSetHeading) {
248 ps[i].fPose.fHeading.set(localXAxis.fY, -localXAxis.fX);
249 }
250 }
251 }
252
253 void visitFields(SkFieldVisitor* v) override {
254 SkString oldPath = fPath;
255
256 SkParticleAffector::visitFields(v);
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500257 v->visit("Input", fInput);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500258 v->visit("SetHeading", fSetHeading);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500259 v->visit("Path", fPath);
260
261 if (fPath != oldPath) {
262 this->rebuild();
263 }
264 }
265
266private:
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500267 SkString fPath;
268 SkParticleValue fInput;
269 bool fSetHeading;
Brian Osman3d76d1b2019-02-28 15:48:05 -0500270
271 void rebuild() {
272 SkPath path;
273 if (!SkParsePath::FromSVGString(fPath.c_str(), &path)) {
274 return;
275 }
276
277 fTotalLength = 0;
278 fContours.reset();
279
280 SkContourMeasureIter iter(path, false);
281 while (auto contour = iter.next()) {
282 fContours.push_back(contour);
283 fTotalLength += contour->length();
284 }
285 }
286
287 // Cached
288 SkScalar fTotalLength;
289 SkTArray<sk_sp<SkContourMeasure>> fContours;
290};
291
292class SkPositionOnTextAffector : public SkParticleAffector {
293public:
294 SkPositionOnTextAffector(const char* text = "", SkScalar fontSize = 96, bool setHeading = true,
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500295 SkParticleValue input = SkParticleValue())
Brian Osman3d76d1b2019-02-28 15:48:05 -0500296 : fText(text)
297 , fFontSize(fontSize)
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500298 , fInput(input)
299 , fSetHeading(setHeading) {
Brian Osman3d76d1b2019-02-28 15:48:05 -0500300 this->rebuild();
301 }
302
303 REFLECTED(SkPositionOnTextAffector, SkParticleAffector)
304
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500305 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman3d76d1b2019-02-28 15:48:05 -0500306 if (fContours.empty()) {
307 return;
308 }
309
310 // TODO: Refactor to share code with PositionOnPathAffector
311 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500312 float t = fInput.eval(params, ps[i]);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500313 SkScalar len = fTotalLength * t;
314 int idx = 0;
315 while (idx < fContours.count() && len > fContours[idx]->length()) {
316 len -= fContours[idx++]->length();
317 }
318 SkVector localXAxis;
319 if (!fContours[idx]->getPosTan(len, &ps[i].fPose.fPosition, &localXAxis)) {
320 ps[i].fPose.fPosition = { 0, 0 };
321 localXAxis = { 1, 0 };
322 }
323 if (fSetHeading) {
324 ps[i].fPose.fHeading.set(localXAxis.fY, -localXAxis.fX);
325 }
326 }
327 }
328
329 void visitFields(SkFieldVisitor* v) override {
330 SkString oldText = fText;
331 SkScalar oldSize = fFontSize;
332
333 SkParticleAffector::visitFields(v);
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500334 v->visit("Input", fInput);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500335 v->visit("SetHeading", fSetHeading);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500336 v->visit("Text", fText);
337 v->visit("FontSize", fFontSize);
338
339 if (fText != oldText || fFontSize != oldSize) {
340 this->rebuild();
341 }
342 }
343
344private:
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500345 SkString fText;
346 SkScalar fFontSize;
347 SkParticleValue fInput;
348 bool fSetHeading;
Brian Osman3d76d1b2019-02-28 15:48:05 -0500349
350 void rebuild() {
351 fTotalLength = 0;
352 fContours.reset();
353
354 if (fText.isEmpty()) {
355 return;
356 }
357
Kevin Lubick96634842019-03-05 14:09:24 -0500358 // Use the font manager's default font
359 SkFont font(nullptr, fFontSize);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500360 SkPath path;
Ben Wagner51e15a62019-05-07 15:38:46 -0400361 SkTextUtils::GetPath(fText.c_str(), fText.size(), SkTextEncoding::kUTF8, 0, 0, font, &path);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500362 SkContourMeasureIter iter(path, false);
363 while (auto contour = iter.next()) {
364 fContours.push_back(contour);
365 fTotalLength += contour->length();
366 }
367 }
368
369 // Cached
370 SkScalar fTotalLength;
371 SkTArray<sk_sp<SkContourMeasure>> fContours;
372};
373
Brian Osman8b6283f2019-02-14 16:55:21 -0500374class SkSizeAffector : public SkParticleAffector {
Brian Osman7c979f52019-02-12 13:27:51 -0500375public:
Brian Osman8b6283f2019-02-14 16:55:21 -0500376 SkSizeAffector(const SkCurve& curve = 1.0f) : fCurve(curve) {}
Brian Osman7c979f52019-02-12 13:27:51 -0500377
Brian Osman8b6283f2019-02-14 16:55:21 -0500378 REFLECTED(SkSizeAffector, SkParticleAffector)
Brian Osman7c979f52019-02-12 13:27:51 -0500379
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500380 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -0500381 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500382 ps[i].fPose.fScale = fCurve.eval(params, ps[i]);
Brian Osman14a67a32019-02-25 14:30:44 -0500383 }
Brian Osman7c979f52019-02-12 13:27:51 -0500384 }
385
386 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500387 SkParticleAffector::visitFields(v);
Brian Osman8b6283f2019-02-14 16:55:21 -0500388 v->visit("Curve", fCurve);
Brian Osman7c979f52019-02-12 13:27:51 -0500389 }
390
391private:
Brian Osman8b6283f2019-02-14 16:55:21 -0500392 SkCurve fCurve;
Brian Osman7c979f52019-02-12 13:27:51 -0500393};
394
Brian Osman125daa42019-02-20 12:25:20 -0500395class SkFrameAffector : public SkParticleAffector {
396public:
397 SkFrameAffector(const SkCurve& curve = 1.0f) : fCurve(curve) {}
398
399 REFLECTED(SkFrameAffector, SkParticleAffector)
400
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500401 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -0500402 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500403 ps[i].fFrame = fCurve.eval(params, ps[i]);
Brian Osman14a67a32019-02-25 14:30:44 -0500404 }
Brian Osman125daa42019-02-20 12:25:20 -0500405 }
406
407 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500408 SkParticleAffector::visitFields(v);
Brian Osman125daa42019-02-20 12:25:20 -0500409 v->visit("Curve", fCurve);
410 }
411
412private:
413 SkCurve fCurve;
414};
415
416class SkColorAffector : public SkParticleAffector {
417public:
418 SkColorAffector(const SkColorCurve& curve = SkColor4f{ 1.0f, 1.0f, 1.0f, 1.0f })
419 : fCurve(curve) {}
420
421 REFLECTED(SkColorAffector, SkParticleAffector)
422
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500423 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -0500424 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500425 ps[i].fColor = fCurve.eval(params, ps[i]);
Brian Osman14a67a32019-02-25 14:30:44 -0500426 }
Brian Osman125daa42019-02-20 12:25:20 -0500427 }
428
429 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500430 SkParticleAffector::visitFields(v);
Brian Osman125daa42019-02-20 12:25:20 -0500431 v->visit("Curve", fCurve);
432 }
433
434private:
435 SkColorCurve fCurve;
436};
437
Brian Osmanc04cadb2019-05-09 14:05:04 -0400438static const char* kDefaultCode =
439 "layout(ctype=float) in uniform float dt;\n"
440 "layout(ctype=float) in uniform float effectAge;\n"
441 "\n"
442 "void main(in float age,\n"
443 " in float invLifetime,\n"
444 " inout float2 pos,\n"
445 " inout float2 dir,\n"
446 " inout float scale,\n"
447 " inout float2 vel,\n"
448 " inout float spin,\n"
449 " inout float4 color,\n"
450 " in float t) {\n"
451 "}\n";
452
453class SkInterpreterAffector : public SkParticleAffector {
454public:
455 SkInterpreterAffector() : fCode(kDefaultCode) {
456 this->rebuild();
457 }
458
459 REFLECTED(SkInterpreterAffector, SkParticleAffector)
460
461 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
462 fInterpreter->setInputs((SkSL::Interpreter::Value*)&params);
463 for (int i = 0; i < count; ++i) {
464 fInterpreter->run(*fMain, (SkSL::Interpreter::Value*)&ps[i].fAge, nullptr);
465 }
466 }
467
468 void visitFields(SkFieldVisitor* v) override {
469 SkString oldCode = fCode;
470
471 SkParticleAffector::visitFields(v);
472 v->visit("Code", fCode);
473
474 if (fCode != oldCode) {
475 this->rebuild();
476 }
477 }
478
479private:
480 SkString fCode;
481
482 // Cached
483 std::unique_ptr<SkSL::Interpreter> fInterpreter;
484 SkSL::ByteCodeFunction* fMain;
485
486 void rebuild() {
487 SkSL::Compiler compiler;
488 SkSL::Program::Settings settings;
489 auto program = compiler.convertProgram(SkSL::Program::kGeneric_Kind,
490 SkSL::String(fCode.c_str()), settings);
491 if (!program) {
492 SkDebugf("%s\n", compiler.errorText().c_str());
493 return;
494 }
495
496 auto byteCode = compiler.toByteCode(*program);
497 if (compiler.errorCount()) {
498 SkDebugf("%s\n", compiler.errorText().c_str());
499 return;
500 }
501
502 // These will be replaced with the real inputs in onApply, before running
503 SkParticleUpdateParams defaultInputs = { 0.0f, 0.0f, 0 };
504 fMain = byteCode->fFunctions[0].get();
505 fInterpreter.reset(new SkSL::Interpreter(std::move(program), std::move(byteCode),
506 (SkSL::Interpreter::Value*)&defaultInputs));
507 }
508};
509
Brian Osman7c979f52019-02-12 13:27:51 -0500510void SkParticleAffector::RegisterAffectorTypes() {
511 REGISTER_REFLECTED(SkParticleAffector);
Brian Osman8b6283f2019-02-14 16:55:21 -0500512 REGISTER_REFLECTED(SkLinearVelocityAffector);
Brian Osman0c486812019-02-26 10:02:15 -0500513 REGISTER_REFLECTED(SkAngularVelocityAffector);
Brian Osman7c979f52019-02-12 13:27:51 -0500514 REGISTER_REFLECTED(SkPointForceAffector);
Brian Osman0c486812019-02-26 10:02:15 -0500515 REGISTER_REFLECTED(SkOrientationAffector);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500516 REGISTER_REFLECTED(SkPositionInCircleAffector);
517 REGISTER_REFLECTED(SkPositionOnPathAffector);
518 REGISTER_REFLECTED(SkPositionOnTextAffector);
Brian Osman8b6283f2019-02-14 16:55:21 -0500519 REGISTER_REFLECTED(SkSizeAffector);
Brian Osman125daa42019-02-20 12:25:20 -0500520 REGISTER_REFLECTED(SkFrameAffector);
521 REGISTER_REFLECTED(SkColorAffector);
Brian Osmanc04cadb2019-05-09 14:05:04 -0400522 REGISTER_REFLECTED(SkInterpreterAffector);
Brian Osman7c979f52019-02-12 13:27:51 -0500523}
524
Brian Osman8b6283f2019-02-14 16:55:21 -0500525sk_sp<SkParticleAffector> SkParticleAffector::MakeLinearVelocity(const SkCurve& angle,
526 const SkCurve& strength,
Brian Osmand5c57fe2019-02-22 11:48:18 -0500527 bool force,
Brian Osman0c486812019-02-26 10:02:15 -0500528 SkParticleFrame frame) {
529 return sk_sp<SkParticleAffector>(new SkLinearVelocityAffector(angle, strength, force, frame));
530}
531
532sk_sp<SkParticleAffector> SkParticleAffector::MakeAngularVelocity(const SkCurve& strength,
533 bool force) {
534 return sk_sp<SkParticleAffector>(new SkAngularVelocityAffector(strength, force));
Brian Osman7c979f52019-02-12 13:27:51 -0500535}
536
Brian Osman8b6283f2019-02-14 16:55:21 -0500537sk_sp<SkParticleAffector> SkParticleAffector::MakePointForce(SkPoint point, SkScalar constant,
538 SkScalar invSquare) {
Brian Osman7c979f52019-02-12 13:27:51 -0500539 return sk_sp<SkParticleAffector>(new SkPointForceAffector(point, constant, invSquare));
540}
541
Brian Osman0c486812019-02-26 10:02:15 -0500542sk_sp<SkParticleAffector> SkParticleAffector::MakeOrientation(const SkCurve& angle,
543 SkParticleFrame frame) {
544 return sk_sp<SkParticleAffector>(new SkOrientationAffector(angle, frame));
Brian Osman7c979f52019-02-12 13:27:51 -0500545}
Brian Osman8b6283f2019-02-14 16:55:21 -0500546
Brian Osman125daa42019-02-20 12:25:20 -0500547sk_sp<SkParticleAffector> SkParticleAffector::MakeSize(const SkCurve& curve) {
Brian Osman8b6283f2019-02-14 16:55:21 -0500548 return sk_sp<SkParticleAffector>(new SkSizeAffector(curve));
549}
Brian Osman125daa42019-02-20 12:25:20 -0500550
551sk_sp<SkParticleAffector> SkParticleAffector::MakeFrame(const SkCurve& curve) {
552 return sk_sp<SkParticleAffector>(new SkFrameAffector(curve));
553}
554
555sk_sp<SkParticleAffector> SkParticleAffector::MakeColor(const SkColorCurve& curve) {
556 return sk_sp<SkParticleAffector>(new SkColorAffector(curve));
557}