blob: ab220883a70a921b8dce5ba01e56f11254285715 [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 Osman4c63a1e2019-05-16 15:11:46 -040017#include "src/core/SkMakeUnique.h"
Brian Osmane246b132019-05-09 15:42:21 -040018
19#if SK_SUPPORT_GPU
Brian Osmanc04cadb2019-05-09 14:05:04 -040020#include "src/sksl/SkSLCompiler.h"
Brian Osman4c63a1e2019-05-16 15:11:46 -040021#include "src/sksl/SkSLExternalValue.h"
Brian Osmanc04cadb2019-05-09 14:05:04 -040022#include "src/sksl/SkSLInterpreter.h"
Brian Osmane246b132019-05-09 15:42:21 -040023#endif
Brian Osman7c979f52019-02-12 13:27:51 -050024
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050025void SkParticleAffector::apply(const SkParticleUpdateParams& params,
26 SkParticleState ps[], int count) {
Brian Osman1b20cd82019-02-25 14:15:02 -050027 if (fEnabled) {
Brian Osman14a67a32019-02-25 14:30:44 -050028 this->onApply(params, ps, count);
Brian Osman1b20cd82019-02-25 14:15:02 -050029 }
30}
31
32void SkParticleAffector::visitFields(SkFieldVisitor* v) {
33 v->visit("Enabled", fEnabled);
34}
35
Brian Osman8b6283f2019-02-14 16:55:21 -050036class SkLinearVelocityAffector : public SkParticleAffector {
Brian Osman7c979f52019-02-12 13:27:51 -050037public:
Brian Osman8b6283f2019-02-14 16:55:21 -050038 SkLinearVelocityAffector(const SkCurve& angle = 0.0f,
39 const SkCurve& strength = 0.0f,
Brian Osmand5c57fe2019-02-22 11:48:18 -050040 bool force = true,
Brian Osman0c486812019-02-26 10:02:15 -050041 SkParticleFrame frame = kWorld_ParticleFrame)
Brian Osman8b6283f2019-02-14 16:55:21 -050042 : fAngle(angle)
43 , fStrength(strength)
Brian Osmand5c57fe2019-02-22 11:48:18 -050044 , fForce(force)
Brian Osman0c486812019-02-26 10:02:15 -050045 , fFrame(frame) {}
Brian Osman7c979f52019-02-12 13:27:51 -050046
Brian Osman8b6283f2019-02-14 16:55:21 -050047 REFLECTED(SkLinearVelocityAffector, SkParticleAffector)
Brian Osman7c979f52019-02-12 13:27:51 -050048
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050049 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -050050 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050051 float angle = fAngle.eval(params, ps[i]);
Brian Osman4428f2c2019-04-02 10:59:28 -040052 SkScalar rad = SkDegreesToRadians(angle);
53 SkScalar s_local = SkScalarSin(rad),
54 c_local = SkScalarCos(rad);
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050055 SkVector heading = ps[i].getFrameHeading(static_cast<SkParticleFrame>(fFrame));
Brian Osman14a67a32019-02-25 14:30:44 -050056 SkScalar c = heading.fX * c_local - heading.fY * s_local;
57 SkScalar s = heading.fX * s_local + heading.fY * c_local;
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050058 float strength = fStrength.eval(params, ps[i]);
Brian Osman14a67a32019-02-25 14:30:44 -050059 SkVector force = { c * strength, s * strength };
60 if (fForce) {
61 ps[i].fVelocity.fLinear += force * params.fDeltaTime;
62 } else {
63 ps[i].fVelocity.fLinear = force;
64 }
Brian Osman8b6283f2019-02-14 16:55:21 -050065 }
Brian Osman7c979f52019-02-12 13:27:51 -050066 }
67
68 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -050069 SkParticleAffector::visitFields(v);
Brian Osman7c979f52019-02-12 13:27:51 -050070 v->visit("Force", fForce);
Brian Osmane5d532e2019-02-26 14:58:40 -050071 v->visit("Frame", fFrame, gParticleFrameMapping, SK_ARRAY_COUNT(gParticleFrameMapping));
Brian Osman7c979f52019-02-12 13:27:51 -050072 v->visit("Angle", fAngle);
73 v->visit("Strength", fStrength);
Brian Osman7c979f52019-02-12 13:27:51 -050074 }
75
76private:
77 SkCurve fAngle;
78 SkCurve fStrength;
Brian Osman8b6283f2019-02-14 16:55:21 -050079 bool fForce;
Brian Osman0c486812019-02-26 10:02:15 -050080 int fFrame;
81};
82
83class SkAngularVelocityAffector : public SkParticleAffector {
84public:
85 SkAngularVelocityAffector(const SkCurve& strength = 0.0f, bool force = true)
86 : fStrength(strength)
87 , fForce(force) {}
88
89 REFLECTED(SkAngularVelocityAffector, SkParticleAffector)
90
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050091 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman0c486812019-02-26 10:02:15 -050092 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050093 float strength = fStrength.eval(params, ps[i]);
Brian Osman0c486812019-02-26 10:02:15 -050094 if (fForce) {
95 ps[i].fVelocity.fAngular += strength * params.fDeltaTime;
96 } else {
97 ps[i].fVelocity.fAngular = strength;
98 }
99 }
100 }
101
102 void visitFields(SkFieldVisitor* v) override {
103 SkParticleAffector::visitFields(v);
104 v->visit("Force", fForce);
105 v->visit("Strength", fStrength);
106 }
107
108private:
109 SkCurve fStrength;
110 bool fForce;
Brian Osman7c979f52019-02-12 13:27:51 -0500111};
112
113class SkPointForceAffector : public SkParticleAffector {
114public:
115 SkPointForceAffector(SkPoint point = { 0.0f, 0.0f }, SkScalar constant = 0.0f,
116 SkScalar invSquare = 0.0f)
117 : fPoint(point), fConstant(constant), fInvSquare(invSquare) {}
118
119 REFLECTED(SkPointForceAffector, SkParticleAffector)
120
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500121 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -0500122 for (int i = 0; i < count; ++i) {
123 SkVector toPoint = fPoint - ps[i].fPose.fPosition;
124 SkScalar lenSquare = toPoint.dot(toPoint);
125 toPoint.normalize();
126 ps[i].fVelocity.fLinear +=
127 toPoint * (fConstant + (fInvSquare / lenSquare)) * params.fDeltaTime;
128 }
Brian Osman7c979f52019-02-12 13:27:51 -0500129 }
130
131 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500132 SkParticleAffector::visitFields(v);
Brian Osman7c979f52019-02-12 13:27:51 -0500133 v->visit("Point", fPoint);
134 v->visit("Constant", fConstant);
135 v->visit("InvSquare", fInvSquare);
136 }
137
138private:
139 SkPoint fPoint;
140 SkScalar fConstant;
141 SkScalar fInvSquare;
142};
143
Brian Osman0c486812019-02-26 10:02:15 -0500144class SkOrientationAffector : public SkParticleAffector {
Brian Osman7c979f52019-02-12 13:27:51 -0500145public:
Brian Osman0c486812019-02-26 10:02:15 -0500146 SkOrientationAffector(const SkCurve& angle = 0.0f,
147 SkParticleFrame frame = kLocal_ParticleFrame)
148 : fAngle(angle)
149 , fFrame(frame) {}
Brian Osman7c979f52019-02-12 13:27:51 -0500150
Brian Osman0c486812019-02-26 10:02:15 -0500151 REFLECTED(SkOrientationAffector, SkParticleAffector)
Brian Osman7c979f52019-02-12 13:27:51 -0500152
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500153 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -0500154 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500155 float angle = fAngle.eval(params, ps[i]);
Brian Osman4428f2c2019-04-02 10:59:28 -0400156 SkScalar rad = SkDegreesToRadians(angle);
157 SkScalar s_local = SkScalarSin(rad),
158 c_local = SkScalarCos(rad);
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500159 SkVector heading = ps[i].getFrameHeading(static_cast<SkParticleFrame>(fFrame));
Brian Osman0c486812019-02-26 10:02:15 -0500160 ps[i].fPose.fHeading.set(heading.fX * c_local - heading.fY * s_local,
161 heading.fX * s_local + heading.fY * c_local);
Brian Osman7c979f52019-02-12 13:27:51 -0500162 }
Brian Osman7c979f52019-02-12 13:27:51 -0500163 }
164
Brian Osman1b20cd82019-02-25 14:15:02 -0500165 void visitFields(SkFieldVisitor *v) override {
166 SkParticleAffector::visitFields(v);
Brian Osmane5d532e2019-02-26 14:58:40 -0500167 v->visit("Frame", fFrame, gParticleFrameMapping, SK_ARRAY_COUNT(gParticleFrameMapping));
Brian Osman0c486812019-02-26 10:02:15 -0500168 v->visit("Angle", fAngle);
Brian Osman1b20cd82019-02-25 14:15:02 -0500169 }
Brian Osman0c486812019-02-26 10:02:15 -0500170
171private:
172 SkCurve fAngle;
173 int fFrame;
Brian Osman7c979f52019-02-12 13:27:51 -0500174};
175
Brian Osman3d76d1b2019-02-28 15:48:05 -0500176class SkPositionInCircleAffector : public SkParticleAffector {
177public:
178 SkPositionInCircleAffector(const SkCurve& x = 0.0f, const SkCurve& y = 0.0f,
179 const SkCurve& radius = 0.0f, bool setHeading = true)
180 : fX(x)
181 , fY(y)
182 , fRadius(radius)
183 , fSetHeading(setHeading) {}
184
185 REFLECTED(SkPositionInCircleAffector, SkParticleAffector)
186
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500187 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman3d76d1b2019-02-28 15:48:05 -0500188 for (int i = 0; i < count; ++i) {
189 SkVector v;
190 do {
191 v.fX = ps[i].fRandom.nextSScalar1();
192 v.fY = ps[i].fRandom.nextSScalar1();
193 } while (v.dot(v) > 1);
194
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500195 SkPoint center = { fX.eval(params, ps[i]), fY.eval(params, ps[i]) };
196 SkScalar radius = fRadius.eval(params, ps[i]);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500197 ps[i].fPose.fPosition = center + (v * radius);
198 if (fSetHeading) {
199 if (!v.normalize()) {
200 v.set(0, -1);
201 }
202 ps[i].fPose.fHeading = v;
203 }
204 }
205 }
206
207 void visitFields(SkFieldVisitor* v) override {
208 SkParticleAffector::visitFields(v);
209 v->visit("SetHeading", fSetHeading);
210 v->visit("X", fX);
211 v->visit("Y", fY);
212 v->visit("Radius", fRadius);
213 }
214
215private:
216 SkCurve fX;
217 SkCurve fY;
218 SkCurve fRadius;
219 bool fSetHeading;
220};
221
222class SkPositionOnPathAffector : public SkParticleAffector {
223public:
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500224 SkPositionOnPathAffector(const char* path = "", bool setHeading = true,
225 SkParticleValue input = SkParticleValue())
Brian Osman3d76d1b2019-02-28 15:48:05 -0500226 : fPath(path)
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500227 , fInput(input)
228 , fSetHeading(setHeading) {
Brian Osman3d76d1b2019-02-28 15:48:05 -0500229 this->rebuild();
230 }
231
232 REFLECTED(SkPositionOnPathAffector, SkParticleAffector)
233
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500234 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman3d76d1b2019-02-28 15:48:05 -0500235 if (fContours.empty()) {
236 return;
237 }
238
239 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500240 float t = fInput.eval(params, ps[i]);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500241 SkScalar len = fTotalLength * t;
242 int idx = 0;
243 while (idx < fContours.count() && len > fContours[idx]->length()) {
244 len -= fContours[idx++]->length();
245 }
246 SkVector localXAxis;
247 if (!fContours[idx]->getPosTan(len, &ps[i].fPose.fPosition, &localXAxis)) {
248 ps[i].fPose.fPosition = { 0, 0 };
249 localXAxis = { 1, 0 };
250 }
251 if (fSetHeading) {
252 ps[i].fPose.fHeading.set(localXAxis.fY, -localXAxis.fX);
253 }
254 }
255 }
256
257 void visitFields(SkFieldVisitor* v) override {
258 SkString oldPath = fPath;
259
260 SkParticleAffector::visitFields(v);
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500261 v->visit("Input", fInput);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500262 v->visit("SetHeading", fSetHeading);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500263 v->visit("Path", fPath);
264
265 if (fPath != oldPath) {
266 this->rebuild();
267 }
268 }
269
270private:
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500271 SkString fPath;
272 SkParticleValue fInput;
273 bool fSetHeading;
Brian Osman3d76d1b2019-02-28 15:48:05 -0500274
275 void rebuild() {
276 SkPath path;
277 if (!SkParsePath::FromSVGString(fPath.c_str(), &path)) {
278 return;
279 }
280
281 fTotalLength = 0;
282 fContours.reset();
283
284 SkContourMeasureIter iter(path, false);
285 while (auto contour = iter.next()) {
286 fContours.push_back(contour);
287 fTotalLength += contour->length();
288 }
289 }
290
291 // Cached
292 SkScalar fTotalLength;
293 SkTArray<sk_sp<SkContourMeasure>> fContours;
294};
295
296class SkPositionOnTextAffector : public SkParticleAffector {
297public:
298 SkPositionOnTextAffector(const char* text = "", SkScalar fontSize = 96, bool setHeading = true,
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500299 SkParticleValue input = SkParticleValue())
Brian Osman3d76d1b2019-02-28 15:48:05 -0500300 : fText(text)
301 , fFontSize(fontSize)
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500302 , fInput(input)
303 , fSetHeading(setHeading) {
Brian Osman3d76d1b2019-02-28 15:48:05 -0500304 this->rebuild();
305 }
306
307 REFLECTED(SkPositionOnTextAffector, SkParticleAffector)
308
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500309 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman3d76d1b2019-02-28 15:48:05 -0500310 if (fContours.empty()) {
311 return;
312 }
313
314 // TODO: Refactor to share code with PositionOnPathAffector
315 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500316 float t = fInput.eval(params, ps[i]);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500317 SkScalar len = fTotalLength * t;
318 int idx = 0;
319 while (idx < fContours.count() && len > fContours[idx]->length()) {
320 len -= fContours[idx++]->length();
321 }
322 SkVector localXAxis;
323 if (!fContours[idx]->getPosTan(len, &ps[i].fPose.fPosition, &localXAxis)) {
324 ps[i].fPose.fPosition = { 0, 0 };
325 localXAxis = { 1, 0 };
326 }
327 if (fSetHeading) {
328 ps[i].fPose.fHeading.set(localXAxis.fY, -localXAxis.fX);
329 }
330 }
331 }
332
333 void visitFields(SkFieldVisitor* v) override {
334 SkString oldText = fText;
335 SkScalar oldSize = fFontSize;
336
337 SkParticleAffector::visitFields(v);
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500338 v->visit("Input", fInput);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500339 v->visit("SetHeading", fSetHeading);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500340 v->visit("Text", fText);
341 v->visit("FontSize", fFontSize);
342
343 if (fText != oldText || fFontSize != oldSize) {
344 this->rebuild();
345 }
346 }
347
348private:
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500349 SkString fText;
350 SkScalar fFontSize;
351 SkParticleValue fInput;
352 bool fSetHeading;
Brian Osman3d76d1b2019-02-28 15:48:05 -0500353
354 void rebuild() {
355 fTotalLength = 0;
356 fContours.reset();
357
358 if (fText.isEmpty()) {
359 return;
360 }
361
Kevin Lubick96634842019-03-05 14:09:24 -0500362 // Use the font manager's default font
363 SkFont font(nullptr, fFontSize);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500364 SkPath path;
Ben Wagner51e15a62019-05-07 15:38:46 -0400365 SkTextUtils::GetPath(fText.c_str(), fText.size(), SkTextEncoding::kUTF8, 0, 0, font, &path);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500366 SkContourMeasureIter iter(path, false);
367 while (auto contour = iter.next()) {
368 fContours.push_back(contour);
369 fTotalLength += contour->length();
370 }
371 }
372
373 // Cached
374 SkScalar fTotalLength;
375 SkTArray<sk_sp<SkContourMeasure>> fContours;
376};
377
Brian Osman8b6283f2019-02-14 16:55:21 -0500378class SkSizeAffector : public SkParticleAffector {
Brian Osman7c979f52019-02-12 13:27:51 -0500379public:
Brian Osman8b6283f2019-02-14 16:55:21 -0500380 SkSizeAffector(const SkCurve& curve = 1.0f) : fCurve(curve) {}
Brian Osman7c979f52019-02-12 13:27:51 -0500381
Brian Osman8b6283f2019-02-14 16:55:21 -0500382 REFLECTED(SkSizeAffector, SkParticleAffector)
Brian Osman7c979f52019-02-12 13:27:51 -0500383
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500384 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -0500385 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500386 ps[i].fPose.fScale = fCurve.eval(params, ps[i]);
Brian Osman14a67a32019-02-25 14:30:44 -0500387 }
Brian Osman7c979f52019-02-12 13:27:51 -0500388 }
389
390 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500391 SkParticleAffector::visitFields(v);
Brian Osman8b6283f2019-02-14 16:55:21 -0500392 v->visit("Curve", fCurve);
Brian Osman7c979f52019-02-12 13:27:51 -0500393 }
394
395private:
Brian Osman8b6283f2019-02-14 16:55:21 -0500396 SkCurve fCurve;
Brian Osman7c979f52019-02-12 13:27:51 -0500397};
398
Brian Osman125daa42019-02-20 12:25:20 -0500399class SkFrameAffector : public SkParticleAffector {
400public:
401 SkFrameAffector(const SkCurve& curve = 1.0f) : fCurve(curve) {}
402
403 REFLECTED(SkFrameAffector, SkParticleAffector)
404
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500405 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -0500406 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500407 ps[i].fFrame = fCurve.eval(params, ps[i]);
Brian Osman14a67a32019-02-25 14:30:44 -0500408 }
Brian Osman125daa42019-02-20 12:25:20 -0500409 }
410
411 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500412 SkParticleAffector::visitFields(v);
Brian Osman125daa42019-02-20 12:25:20 -0500413 v->visit("Curve", fCurve);
414 }
415
416private:
417 SkCurve fCurve;
418};
419
420class SkColorAffector : public SkParticleAffector {
421public:
422 SkColorAffector(const SkColorCurve& curve = SkColor4f{ 1.0f, 1.0f, 1.0f, 1.0f })
423 : fCurve(curve) {}
424
425 REFLECTED(SkColorAffector, SkParticleAffector)
426
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500427 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -0500428 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500429 ps[i].fColor = fCurve.eval(params, ps[i]);
Brian Osman14a67a32019-02-25 14:30:44 -0500430 }
Brian Osman125daa42019-02-20 12:25:20 -0500431 }
432
433 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500434 SkParticleAffector::visitFields(v);
Brian Osman125daa42019-02-20 12:25:20 -0500435 v->visit("Curve", fCurve);
436 }
437
438private:
439 SkColorCurve fCurve;
440};
441
Brian Osmane246b132019-05-09 15:42:21 -0400442#if SK_SUPPORT_GPU
Brian Osmanc04cadb2019-05-09 14:05:04 -0400443static const char* kDefaultCode =
Brian Osman4c63a1e2019-05-16 15:11:46 -0400444 "// float rand; Every read returns a random float [0 .. 1)\n"
Brian Osmanc04cadb2019-05-09 14:05:04 -0400445 "layout(ctype=float) in uniform float dt;\n"
446 "layout(ctype=float) in uniform float effectAge;\n"
447 "\n"
448 "void main(in float age,\n"
449 " in float invLifetime,\n"
450 " inout float2 pos,\n"
451 " inout float2 dir,\n"
452 " inout float scale,\n"
453 " inout float2 vel,\n"
454 " inout float spin,\n"
Brian Osman4c63a1e2019-05-16 15:11:46 -0400455 " inout float4 color) {\n"
Brian Osmanc04cadb2019-05-09 14:05:04 -0400456 "}\n";
457
Brian Osman4c63a1e2019-05-16 15:11:46 -0400458class SkRandomExternalValue : public SkSL::ExternalValue {
459public:
460 SkRandomExternalValue(const char* name, SkSL::Compiler& compiler)
461 : INHERITED(name, *compiler.context().fFloat_Type)
462 , fRandom(nullptr) { }
463
464 void setRandom(SkRandom* random) { fRandom = random; }
465 bool canRead() const override { return true; }
466 void read(void* target) override { *(float*)target = fRandom->nextF(); }
467
468private:
469 SkRandom* fRandom;
470 typedef SkSL::ExternalValue INHERITED;
471};
472
Brian Osmanc04cadb2019-05-09 14:05:04 -0400473class SkInterpreterAffector : public SkParticleAffector {
474public:
475 SkInterpreterAffector() : fCode(kDefaultCode) {
476 this->rebuild();
477 }
478
479 REFLECTED(SkInterpreterAffector, SkParticleAffector)
480
481 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osmanc04cadb2019-05-09 14:05:04 -0400482 for (int i = 0; i < count; ++i) {
Brian Osman4c63a1e2019-05-16 15:11:46 -0400483 fRandomValue->setRandom(&ps[i].fRandom);
Brian Osman80164412019-06-07 13:00:23 -0400484 SkSL::Interpreter::Run(fByteCode.get(), fMain, (SkSL::Interpreter::Value*)&ps[i].fAge,
485 nullptr, (SkSL::Interpreter::Value*)&params, 2);
Brian Osmanc04cadb2019-05-09 14:05:04 -0400486 }
487 }
488
489 void visitFields(SkFieldVisitor* v) override {
490 SkString oldCode = fCode;
491
492 SkParticleAffector::visitFields(v);
493 v->visit("Code", fCode);
494
495 if (fCode != oldCode) {
496 this->rebuild();
497 }
498 }
499
500private:
501 SkString fCode;
502
503 // Cached
Brian Osman80164412019-06-07 13:00:23 -0400504 std::unique_ptr<SkSL::ByteCode> fByteCode;
Brian Osman4c63a1e2019-05-16 15:11:46 -0400505 std::unique_ptr<SkRandomExternalValue> fRandomValue;
Brian Osmanc04cadb2019-05-09 14:05:04 -0400506 SkSL::ByteCodeFunction* fMain;
507
508 void rebuild() {
509 SkSL::Compiler compiler;
510 SkSL::Program::Settings settings;
Brian Osman4c63a1e2019-05-16 15:11:46 -0400511 auto rand = skstd::make_unique<SkRandomExternalValue>("rand", compiler);
512 compiler.registerExternalValue(rand.get());
Brian Osmanc04cadb2019-05-09 14:05:04 -0400513 auto program = compiler.convertProgram(SkSL::Program::kGeneric_Kind,
514 SkSL::String(fCode.c_str()), settings);
515 if (!program) {
516 SkDebugf("%s\n", compiler.errorText().c_str());
517 return;
518 }
519
520 auto byteCode = compiler.toByteCode(*program);
521 if (compiler.errorCount()) {
522 SkDebugf("%s\n", compiler.errorText().c_str());
523 return;
524 }
525
Brian Osmanc04cadb2019-05-09 14:05:04 -0400526 fMain = byteCode->fFunctions[0].get();
Brian Osman80164412019-06-07 13:00:23 -0400527 fByteCode = std::move(byteCode);
Brian Osman4c63a1e2019-05-16 15:11:46 -0400528 fRandomValue = std::move(rand);
Brian Osmanc04cadb2019-05-09 14:05:04 -0400529 }
530};
Brian Osmane246b132019-05-09 15:42:21 -0400531#endif
Brian Osmanc04cadb2019-05-09 14:05:04 -0400532
Brian Osman7c979f52019-02-12 13:27:51 -0500533void SkParticleAffector::RegisterAffectorTypes() {
534 REGISTER_REFLECTED(SkParticleAffector);
Brian Osman8b6283f2019-02-14 16:55:21 -0500535 REGISTER_REFLECTED(SkLinearVelocityAffector);
Brian Osman0c486812019-02-26 10:02:15 -0500536 REGISTER_REFLECTED(SkAngularVelocityAffector);
Brian Osman7c979f52019-02-12 13:27:51 -0500537 REGISTER_REFLECTED(SkPointForceAffector);
Brian Osman0c486812019-02-26 10:02:15 -0500538 REGISTER_REFLECTED(SkOrientationAffector);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500539 REGISTER_REFLECTED(SkPositionInCircleAffector);
540 REGISTER_REFLECTED(SkPositionOnPathAffector);
541 REGISTER_REFLECTED(SkPositionOnTextAffector);
Brian Osman8b6283f2019-02-14 16:55:21 -0500542 REGISTER_REFLECTED(SkSizeAffector);
Brian Osman125daa42019-02-20 12:25:20 -0500543 REGISTER_REFLECTED(SkFrameAffector);
544 REGISTER_REFLECTED(SkColorAffector);
Brian Osmane246b132019-05-09 15:42:21 -0400545#if SK_SUPPORT_GPU
Brian Osmanc04cadb2019-05-09 14:05:04 -0400546 REGISTER_REFLECTED(SkInterpreterAffector);
Brian Osmane246b132019-05-09 15:42:21 -0400547#endif
Brian Osman7c979f52019-02-12 13:27:51 -0500548}
549
Brian Osman8b6283f2019-02-14 16:55:21 -0500550sk_sp<SkParticleAffector> SkParticleAffector::MakeLinearVelocity(const SkCurve& angle,
551 const SkCurve& strength,
Brian Osmand5c57fe2019-02-22 11:48:18 -0500552 bool force,
Brian Osman0c486812019-02-26 10:02:15 -0500553 SkParticleFrame frame) {
554 return sk_sp<SkParticleAffector>(new SkLinearVelocityAffector(angle, strength, force, frame));
555}
556
557sk_sp<SkParticleAffector> SkParticleAffector::MakeAngularVelocity(const SkCurve& strength,
558 bool force) {
559 return sk_sp<SkParticleAffector>(new SkAngularVelocityAffector(strength, force));
Brian Osman7c979f52019-02-12 13:27:51 -0500560}
561
Brian Osman8b6283f2019-02-14 16:55:21 -0500562sk_sp<SkParticleAffector> SkParticleAffector::MakePointForce(SkPoint point, SkScalar constant,
563 SkScalar invSquare) {
Brian Osman7c979f52019-02-12 13:27:51 -0500564 return sk_sp<SkParticleAffector>(new SkPointForceAffector(point, constant, invSquare));
565}
566
Brian Osman0c486812019-02-26 10:02:15 -0500567sk_sp<SkParticleAffector> SkParticleAffector::MakeOrientation(const SkCurve& angle,
568 SkParticleFrame frame) {
569 return sk_sp<SkParticleAffector>(new SkOrientationAffector(angle, frame));
Brian Osman7c979f52019-02-12 13:27:51 -0500570}
Brian Osman8b6283f2019-02-14 16:55:21 -0500571
Brian Osman125daa42019-02-20 12:25:20 -0500572sk_sp<SkParticleAffector> SkParticleAffector::MakeSize(const SkCurve& curve) {
Brian Osman8b6283f2019-02-14 16:55:21 -0500573 return sk_sp<SkParticleAffector>(new SkSizeAffector(curve));
574}
Brian Osman125daa42019-02-20 12:25:20 -0500575
576sk_sp<SkParticleAffector> SkParticleAffector::MakeFrame(const SkCurve& curve) {
577 return sk_sp<SkParticleAffector>(new SkFrameAffector(curve));
578}
579
580sk_sp<SkParticleAffector> SkParticleAffector::MakeColor(const SkColorCurve& curve) {
581 return sk_sp<SkParticleAffector>(new SkColorAffector(curve));
582}