blob: 7c7fe0bef2dba04215b222fa3addbe923683d43c [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 Osman08a84962019-06-14 10:17:16 -040018#include "src/sksl/SkSLByteCode.h"
Brian Osmanc04cadb2019-05-09 14:05:04 -040019#include "src/sksl/SkSLCompiler.h"
Brian Osman4c63a1e2019-05-16 15:11:46 -040020#include "src/sksl/SkSLExternalValue.h"
Brian Osman7c979f52019-02-12 13:27:51 -050021
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050022void SkParticleAffector::apply(const SkParticleUpdateParams& params,
23 SkParticleState ps[], int count) {
Brian Osman1b20cd82019-02-25 14:15:02 -050024 if (fEnabled) {
Brian Osman14a67a32019-02-25 14:30:44 -050025 this->onApply(params, ps, count);
Brian Osman1b20cd82019-02-25 14:15:02 -050026 }
27}
28
29void SkParticleAffector::visitFields(SkFieldVisitor* v) {
30 v->visit("Enabled", fEnabled);
31}
32
Brian Osman8b6283f2019-02-14 16:55:21 -050033class SkLinearVelocityAffector : public SkParticleAffector {
Brian Osman7c979f52019-02-12 13:27:51 -050034public:
Brian Osman8b6283f2019-02-14 16:55:21 -050035 SkLinearVelocityAffector(const SkCurve& angle = 0.0f,
36 const SkCurve& strength = 0.0f,
Brian Osmand5c57fe2019-02-22 11:48:18 -050037 bool force = true,
Brian Osman0c486812019-02-26 10:02:15 -050038 SkParticleFrame frame = kWorld_ParticleFrame)
Brian Osman8b6283f2019-02-14 16:55:21 -050039 : fAngle(angle)
40 , fStrength(strength)
Brian Osmand5c57fe2019-02-22 11:48:18 -050041 , fForce(force)
Brian Osman0c486812019-02-26 10:02:15 -050042 , fFrame(frame) {}
Brian Osman7c979f52019-02-12 13:27:51 -050043
Brian Osman8b6283f2019-02-14 16:55:21 -050044 REFLECTED(SkLinearVelocityAffector, SkParticleAffector)
Brian Osman7c979f52019-02-12 13:27:51 -050045
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050046 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -050047 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050048 float angle = fAngle.eval(params, ps[i]);
Brian Osman4428f2c2019-04-02 10:59:28 -040049 SkScalar rad = SkDegreesToRadians(angle);
50 SkScalar s_local = SkScalarSin(rad),
51 c_local = SkScalarCos(rad);
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050052 SkVector heading = ps[i].getFrameHeading(static_cast<SkParticleFrame>(fFrame));
Brian Osman14a67a32019-02-25 14:30:44 -050053 SkScalar c = heading.fX * c_local - heading.fY * s_local;
54 SkScalar s = heading.fX * s_local + heading.fY * c_local;
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050055 float strength = fStrength.eval(params, ps[i]);
Brian Osman14a67a32019-02-25 14:30:44 -050056 SkVector force = { c * strength, s * strength };
57 if (fForce) {
58 ps[i].fVelocity.fLinear += force * params.fDeltaTime;
59 } else {
60 ps[i].fVelocity.fLinear = force;
61 }
Brian Osman8b6283f2019-02-14 16:55:21 -050062 }
Brian Osman7c979f52019-02-12 13:27:51 -050063 }
64
65 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -050066 SkParticleAffector::visitFields(v);
Brian Osman7c979f52019-02-12 13:27:51 -050067 v->visit("Force", fForce);
Brian Osmane5d532e2019-02-26 14:58:40 -050068 v->visit("Frame", fFrame, gParticleFrameMapping, SK_ARRAY_COUNT(gParticleFrameMapping));
Brian Osman7c979f52019-02-12 13:27:51 -050069 v->visit("Angle", fAngle);
70 v->visit("Strength", fStrength);
Brian Osman7c979f52019-02-12 13:27:51 -050071 }
72
73private:
74 SkCurve fAngle;
75 SkCurve fStrength;
Brian Osman8b6283f2019-02-14 16:55:21 -050076 bool fForce;
Brian Osman0c486812019-02-26 10:02:15 -050077 int fFrame;
78};
79
80class SkAngularVelocityAffector : public SkParticleAffector {
81public:
82 SkAngularVelocityAffector(const SkCurve& strength = 0.0f, bool force = true)
83 : fStrength(strength)
84 , fForce(force) {}
85
86 REFLECTED(SkAngularVelocityAffector, SkParticleAffector)
87
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050088 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman0c486812019-02-26 10:02:15 -050089 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -050090 float strength = fStrength.eval(params, ps[i]);
Brian Osman0c486812019-02-26 10:02:15 -050091 if (fForce) {
92 ps[i].fVelocity.fAngular += strength * params.fDeltaTime;
93 } else {
94 ps[i].fVelocity.fAngular = strength;
95 }
96 }
97 }
98
99 void visitFields(SkFieldVisitor* v) override {
100 SkParticleAffector::visitFields(v);
101 v->visit("Force", fForce);
102 v->visit("Strength", fStrength);
103 }
104
105private:
106 SkCurve fStrength;
107 bool fForce;
Brian Osman7c979f52019-02-12 13:27:51 -0500108};
109
110class SkPointForceAffector : public SkParticleAffector {
111public:
112 SkPointForceAffector(SkPoint point = { 0.0f, 0.0f }, SkScalar constant = 0.0f,
113 SkScalar invSquare = 0.0f)
114 : fPoint(point), fConstant(constant), fInvSquare(invSquare) {}
115
116 REFLECTED(SkPointForceAffector, SkParticleAffector)
117
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500118 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -0500119 for (int i = 0; i < count; ++i) {
120 SkVector toPoint = fPoint - ps[i].fPose.fPosition;
121 SkScalar lenSquare = toPoint.dot(toPoint);
122 toPoint.normalize();
123 ps[i].fVelocity.fLinear +=
124 toPoint * (fConstant + (fInvSquare / lenSquare)) * params.fDeltaTime;
125 }
Brian Osman7c979f52019-02-12 13:27:51 -0500126 }
127
128 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500129 SkParticleAffector::visitFields(v);
Brian Osman7c979f52019-02-12 13:27:51 -0500130 v->visit("Point", fPoint);
131 v->visit("Constant", fConstant);
132 v->visit("InvSquare", fInvSquare);
133 }
134
135private:
136 SkPoint fPoint;
137 SkScalar fConstant;
138 SkScalar fInvSquare;
139};
140
Brian Osman0c486812019-02-26 10:02:15 -0500141class SkOrientationAffector : public SkParticleAffector {
Brian Osman7c979f52019-02-12 13:27:51 -0500142public:
Brian Osman0c486812019-02-26 10:02:15 -0500143 SkOrientationAffector(const SkCurve& angle = 0.0f,
144 SkParticleFrame frame = kLocal_ParticleFrame)
145 : fAngle(angle)
146 , fFrame(frame) {}
Brian Osman7c979f52019-02-12 13:27:51 -0500147
Brian Osman0c486812019-02-26 10:02:15 -0500148 REFLECTED(SkOrientationAffector, SkParticleAffector)
Brian Osman7c979f52019-02-12 13:27:51 -0500149
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500150 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -0500151 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500152 float angle = fAngle.eval(params, ps[i]);
Brian Osman4428f2c2019-04-02 10:59:28 -0400153 SkScalar rad = SkDegreesToRadians(angle);
154 SkScalar s_local = SkScalarSin(rad),
155 c_local = SkScalarCos(rad);
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500156 SkVector heading = ps[i].getFrameHeading(static_cast<SkParticleFrame>(fFrame));
Brian Osman0c486812019-02-26 10:02:15 -0500157 ps[i].fPose.fHeading.set(heading.fX * c_local - heading.fY * s_local,
158 heading.fX * s_local + heading.fY * c_local);
Brian Osman7c979f52019-02-12 13:27:51 -0500159 }
Brian Osman7c979f52019-02-12 13:27:51 -0500160 }
161
Brian Osman1b20cd82019-02-25 14:15:02 -0500162 void visitFields(SkFieldVisitor *v) override {
163 SkParticleAffector::visitFields(v);
Brian Osmane5d532e2019-02-26 14:58:40 -0500164 v->visit("Frame", fFrame, gParticleFrameMapping, SK_ARRAY_COUNT(gParticleFrameMapping));
Brian Osman0c486812019-02-26 10:02:15 -0500165 v->visit("Angle", fAngle);
Brian Osman1b20cd82019-02-25 14:15:02 -0500166 }
Brian Osman0c486812019-02-26 10:02:15 -0500167
168private:
169 SkCurve fAngle;
170 int fFrame;
Brian Osman7c979f52019-02-12 13:27:51 -0500171};
172
Brian Osman3d76d1b2019-02-28 15:48:05 -0500173class SkPositionInCircleAffector : public SkParticleAffector {
174public:
175 SkPositionInCircleAffector(const SkCurve& x = 0.0f, const SkCurve& y = 0.0f,
176 const SkCurve& radius = 0.0f, bool setHeading = true)
177 : fX(x)
178 , fY(y)
179 , fRadius(radius)
180 , fSetHeading(setHeading) {}
181
182 REFLECTED(SkPositionInCircleAffector, SkParticleAffector)
183
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500184 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman3d76d1b2019-02-28 15:48:05 -0500185 for (int i = 0; i < count; ++i) {
186 SkVector v;
187 do {
188 v.fX = ps[i].fRandom.nextSScalar1();
189 v.fY = ps[i].fRandom.nextSScalar1();
190 } while (v.dot(v) > 1);
191
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500192 SkPoint center = { fX.eval(params, ps[i]), fY.eval(params, ps[i]) };
193 SkScalar radius = fRadius.eval(params, ps[i]);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500194 ps[i].fPose.fPosition = center + (v * radius);
195 if (fSetHeading) {
196 if (!v.normalize()) {
197 v.set(0, -1);
198 }
199 ps[i].fPose.fHeading = v;
200 }
201 }
202 }
203
204 void visitFields(SkFieldVisitor* v) override {
205 SkParticleAffector::visitFields(v);
206 v->visit("SetHeading", fSetHeading);
207 v->visit("X", fX);
208 v->visit("Y", fY);
209 v->visit("Radius", fRadius);
210 }
211
212private:
213 SkCurve fX;
214 SkCurve fY;
215 SkCurve fRadius;
216 bool fSetHeading;
217};
218
219class SkPositionOnPathAffector : public SkParticleAffector {
220public:
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500221 SkPositionOnPathAffector(const char* path = "", bool setHeading = true,
222 SkParticleValue input = SkParticleValue())
Brian Osman3d76d1b2019-02-28 15:48:05 -0500223 : fPath(path)
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500224 , fInput(input)
225 , fSetHeading(setHeading) {
Brian Osman3d76d1b2019-02-28 15:48:05 -0500226 this->rebuild();
227 }
228
229 REFLECTED(SkPositionOnPathAffector, SkParticleAffector)
230
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500231 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman3d76d1b2019-02-28 15:48:05 -0500232 if (fContours.empty()) {
233 return;
234 }
235
236 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500237 float t = fInput.eval(params, ps[i]);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500238 SkScalar len = fTotalLength * t;
239 int idx = 0;
240 while (idx < fContours.count() && len > fContours[idx]->length()) {
241 len -= fContours[idx++]->length();
242 }
243 SkVector localXAxis;
244 if (!fContours[idx]->getPosTan(len, &ps[i].fPose.fPosition, &localXAxis)) {
245 ps[i].fPose.fPosition = { 0, 0 };
246 localXAxis = { 1, 0 };
247 }
248 if (fSetHeading) {
249 ps[i].fPose.fHeading.set(localXAxis.fY, -localXAxis.fX);
250 }
251 }
252 }
253
254 void visitFields(SkFieldVisitor* v) override {
255 SkString oldPath = fPath;
256
257 SkParticleAffector::visitFields(v);
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500258 v->visit("Input", fInput);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500259 v->visit("SetHeading", fSetHeading);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500260 v->visit("Path", fPath);
261
262 if (fPath != oldPath) {
263 this->rebuild();
264 }
265 }
266
267private:
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500268 SkString fPath;
269 SkParticleValue fInput;
270 bool fSetHeading;
Brian Osman3d76d1b2019-02-28 15:48:05 -0500271
272 void rebuild() {
273 SkPath path;
274 if (!SkParsePath::FromSVGString(fPath.c_str(), &path)) {
275 return;
276 }
277
278 fTotalLength = 0;
279 fContours.reset();
280
281 SkContourMeasureIter iter(path, false);
282 while (auto contour = iter.next()) {
283 fContours.push_back(contour);
284 fTotalLength += contour->length();
285 }
286 }
287
288 // Cached
289 SkScalar fTotalLength;
290 SkTArray<sk_sp<SkContourMeasure>> fContours;
291};
292
293class SkPositionOnTextAffector : public SkParticleAffector {
294public:
295 SkPositionOnTextAffector(const char* text = "", SkScalar fontSize = 96, bool setHeading = true,
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500296 SkParticleValue input = SkParticleValue())
Brian Osman3d76d1b2019-02-28 15:48:05 -0500297 : fText(text)
298 , fFontSize(fontSize)
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500299 , fInput(input)
300 , fSetHeading(setHeading) {
Brian Osman3d76d1b2019-02-28 15:48:05 -0500301 this->rebuild();
302 }
303
304 REFLECTED(SkPositionOnTextAffector, SkParticleAffector)
305
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500306 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman3d76d1b2019-02-28 15:48:05 -0500307 if (fContours.empty()) {
308 return;
309 }
310
311 // TODO: Refactor to share code with PositionOnPathAffector
312 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500313 float t = fInput.eval(params, ps[i]);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500314 SkScalar len = fTotalLength * t;
315 int idx = 0;
316 while (idx < fContours.count() && len > fContours[idx]->length()) {
317 len -= fContours[idx++]->length();
318 }
319 SkVector localXAxis;
320 if (!fContours[idx]->getPosTan(len, &ps[i].fPose.fPosition, &localXAxis)) {
321 ps[i].fPose.fPosition = { 0, 0 };
322 localXAxis = { 1, 0 };
323 }
324 if (fSetHeading) {
325 ps[i].fPose.fHeading.set(localXAxis.fY, -localXAxis.fX);
326 }
327 }
328 }
329
330 void visitFields(SkFieldVisitor* v) override {
331 SkString oldText = fText;
332 SkScalar oldSize = fFontSize;
333
334 SkParticleAffector::visitFields(v);
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500335 v->visit("Input", fInput);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500336 v->visit("SetHeading", fSetHeading);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500337 v->visit("Text", fText);
338 v->visit("FontSize", fFontSize);
339
340 if (fText != oldText || fFontSize != oldSize) {
341 this->rebuild();
342 }
343 }
344
345private:
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500346 SkString fText;
347 SkScalar fFontSize;
348 SkParticleValue fInput;
349 bool fSetHeading;
Brian Osman3d76d1b2019-02-28 15:48:05 -0500350
351 void rebuild() {
352 fTotalLength = 0;
353 fContours.reset();
354
355 if (fText.isEmpty()) {
356 return;
357 }
358
Kevin Lubick96634842019-03-05 14:09:24 -0500359 // Use the font manager's default font
360 SkFont font(nullptr, fFontSize);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500361 SkPath path;
Ben Wagner51e15a62019-05-07 15:38:46 -0400362 SkTextUtils::GetPath(fText.c_str(), fText.size(), SkTextEncoding::kUTF8, 0, 0, font, &path);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500363 SkContourMeasureIter iter(path, false);
364 while (auto contour = iter.next()) {
365 fContours.push_back(contour);
366 fTotalLength += contour->length();
367 }
368 }
369
370 // Cached
371 SkScalar fTotalLength;
372 SkTArray<sk_sp<SkContourMeasure>> fContours;
373};
374
Brian Osman8b6283f2019-02-14 16:55:21 -0500375class SkSizeAffector : public SkParticleAffector {
Brian Osman7c979f52019-02-12 13:27:51 -0500376public:
Brian Osman8b6283f2019-02-14 16:55:21 -0500377 SkSizeAffector(const SkCurve& curve = 1.0f) : fCurve(curve) {}
Brian Osman7c979f52019-02-12 13:27:51 -0500378
Brian Osman8b6283f2019-02-14 16:55:21 -0500379 REFLECTED(SkSizeAffector, SkParticleAffector)
Brian Osman7c979f52019-02-12 13:27:51 -0500380
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500381 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -0500382 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500383 ps[i].fPose.fScale = fCurve.eval(params, ps[i]);
Brian Osman14a67a32019-02-25 14:30:44 -0500384 }
Brian Osman7c979f52019-02-12 13:27:51 -0500385 }
386
387 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500388 SkParticleAffector::visitFields(v);
Brian Osman8b6283f2019-02-14 16:55:21 -0500389 v->visit("Curve", fCurve);
Brian Osman7c979f52019-02-12 13:27:51 -0500390 }
391
392private:
Brian Osman8b6283f2019-02-14 16:55:21 -0500393 SkCurve fCurve;
Brian Osman7c979f52019-02-12 13:27:51 -0500394};
395
Brian Osman125daa42019-02-20 12:25:20 -0500396class SkFrameAffector : public SkParticleAffector {
397public:
398 SkFrameAffector(const SkCurve& curve = 1.0f) : fCurve(curve) {}
399
400 REFLECTED(SkFrameAffector, SkParticleAffector)
401
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500402 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -0500403 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500404 ps[i].fFrame = fCurve.eval(params, ps[i]);
Brian Osman14a67a32019-02-25 14:30:44 -0500405 }
Brian Osman125daa42019-02-20 12:25:20 -0500406 }
407
408 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500409 SkParticleAffector::visitFields(v);
Brian Osman125daa42019-02-20 12:25:20 -0500410 v->visit("Curve", fCurve);
411 }
412
413private:
414 SkCurve fCurve;
415};
416
417class SkColorAffector : public SkParticleAffector {
418public:
419 SkColorAffector(const SkColorCurve& curve = SkColor4f{ 1.0f, 1.0f, 1.0f, 1.0f })
420 : fCurve(curve) {}
421
422 REFLECTED(SkColorAffector, SkParticleAffector)
423
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500424 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osman14a67a32019-02-25 14:30:44 -0500425 for (int i = 0; i < count; ++i) {
Brian Osmanbdcdf1a2019-03-04 10:55:22 -0500426 ps[i].fColor = fCurve.eval(params, ps[i]);
Brian Osman14a67a32019-02-25 14:30:44 -0500427 }
Brian Osman125daa42019-02-20 12:25:20 -0500428 }
429
430 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500431 SkParticleAffector::visitFields(v);
Brian Osman125daa42019-02-20 12:25:20 -0500432 v->visit("Curve", fCurve);
433 }
434
435private:
436 SkColorCurve fCurve;
437};
438
Brian Osmanc04cadb2019-05-09 14:05:04 -0400439static const char* kDefaultCode =
Brian Osman4c63a1e2019-05-16 15:11:46 -0400440 "// float rand; Every read returns a random float [0 .. 1)\n"
Brian Osmanc04cadb2019-05-09 14:05:04 -0400441 "layout(ctype=float) in uniform float dt;\n"
442 "layout(ctype=float) in uniform float effectAge;\n"
443 "\n"
444 "void main(in float age,\n"
445 " in float invLifetime,\n"
446 " inout float2 pos,\n"
447 " inout float2 dir,\n"
448 " inout float scale,\n"
449 " inout float2 vel,\n"
450 " inout float spin,\n"
Brian Osman4c63a1e2019-05-16 15:11:46 -0400451 " inout float4 color) {\n"
Brian Osmanc04cadb2019-05-09 14:05:04 -0400452 "}\n";
453
Brian Osman4c63a1e2019-05-16 15:11:46 -0400454class SkRandomExternalValue : public SkSL::ExternalValue {
455public:
456 SkRandomExternalValue(const char* name, SkSL::Compiler& compiler)
457 : INHERITED(name, *compiler.context().fFloat_Type)
458 , fRandom(nullptr) { }
459
460 void setRandom(SkRandom* random) { fRandom = random; }
461 bool canRead() const override { return true; }
Brian Osman1a79f0b2019-06-24 16:32:14 -0400462 void read(int /*unusedIndex*/, float* target) override { *target = fRandom->nextF(); }
Brian Osman4c63a1e2019-05-16 15:11:46 -0400463
464private:
465 SkRandom* fRandom;
466 typedef SkSL::ExternalValue INHERITED;
467};
468
Brian Osmanc04cadb2019-05-09 14:05:04 -0400469class SkInterpreterAffector : public SkParticleAffector {
470public:
471 SkInterpreterAffector() : fCode(kDefaultCode) {
472 this->rebuild();
473 }
474
475 REFLECTED(SkInterpreterAffector, SkParticleAffector)
476
477 void onApply(const SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
Brian Osmanc04cadb2019-05-09 14:05:04 -0400478 for (int i = 0; i < count; ++i) {
Brian Osman4c63a1e2019-05-16 15:11:46 -0400479 fRandomValue->setRandom(&ps[i].fRandom);
Brian Osman08a84962019-06-14 10:17:16 -0400480 fByteCode->run(fMain, &ps[i].fAge, nullptr, 1, &params.fDeltaTime, 2);
Brian Osmanc04cadb2019-05-09 14:05:04 -0400481 }
482 }
483
484 void visitFields(SkFieldVisitor* v) override {
485 SkString oldCode = fCode;
486
487 SkParticleAffector::visitFields(v);
488 v->visit("Code", fCode);
489
490 if (fCode != oldCode) {
491 this->rebuild();
492 }
493 }
494
495private:
496 SkString fCode;
497
498 // Cached
Brian Osman80164412019-06-07 13:00:23 -0400499 std::unique_ptr<SkSL::ByteCode> fByteCode;
Brian Osman4c63a1e2019-05-16 15:11:46 -0400500 std::unique_ptr<SkRandomExternalValue> fRandomValue;
Brian Osmanc04cadb2019-05-09 14:05:04 -0400501 SkSL::ByteCodeFunction* fMain;
502
503 void rebuild() {
504 SkSL::Compiler compiler;
505 SkSL::Program::Settings settings;
Brian Osman4c63a1e2019-05-16 15:11:46 -0400506 auto rand = skstd::make_unique<SkRandomExternalValue>("rand", compiler);
507 compiler.registerExternalValue(rand.get());
Brian Osmanc04cadb2019-05-09 14:05:04 -0400508 auto program = compiler.convertProgram(SkSL::Program::kGeneric_Kind,
509 SkSL::String(fCode.c_str()), settings);
510 if (!program) {
511 SkDebugf("%s\n", compiler.errorText().c_str());
512 return;
513 }
514
515 auto byteCode = compiler.toByteCode(*program);
516 if (compiler.errorCount()) {
517 SkDebugf("%s\n", compiler.errorText().c_str());
518 return;
519 }
520
Brian Osmanc04cadb2019-05-09 14:05:04 -0400521 fMain = byteCode->fFunctions[0].get();
Brian Osman80164412019-06-07 13:00:23 -0400522 fByteCode = std::move(byteCode);
Brian Osman4c63a1e2019-05-16 15:11:46 -0400523 fRandomValue = std::move(rand);
Brian Osmanc04cadb2019-05-09 14:05:04 -0400524 }
525};
526
Brian Osman7c979f52019-02-12 13:27:51 -0500527void SkParticleAffector::RegisterAffectorTypes() {
528 REGISTER_REFLECTED(SkParticleAffector);
Brian Osman8b6283f2019-02-14 16:55:21 -0500529 REGISTER_REFLECTED(SkLinearVelocityAffector);
Brian Osman0c486812019-02-26 10:02:15 -0500530 REGISTER_REFLECTED(SkAngularVelocityAffector);
Brian Osman7c979f52019-02-12 13:27:51 -0500531 REGISTER_REFLECTED(SkPointForceAffector);
Brian Osman0c486812019-02-26 10:02:15 -0500532 REGISTER_REFLECTED(SkOrientationAffector);
Brian Osman3d76d1b2019-02-28 15:48:05 -0500533 REGISTER_REFLECTED(SkPositionInCircleAffector);
534 REGISTER_REFLECTED(SkPositionOnPathAffector);
535 REGISTER_REFLECTED(SkPositionOnTextAffector);
Brian Osman8b6283f2019-02-14 16:55:21 -0500536 REGISTER_REFLECTED(SkSizeAffector);
Brian Osman125daa42019-02-20 12:25:20 -0500537 REGISTER_REFLECTED(SkFrameAffector);
538 REGISTER_REFLECTED(SkColorAffector);
Brian Osmanc04cadb2019-05-09 14:05:04 -0400539 REGISTER_REFLECTED(SkInterpreterAffector);
Brian Osman7c979f52019-02-12 13:27:51 -0500540}
541
Brian Osman8b6283f2019-02-14 16:55:21 -0500542sk_sp<SkParticleAffector> SkParticleAffector::MakeLinearVelocity(const SkCurve& angle,
543 const SkCurve& strength,
Brian Osmand5c57fe2019-02-22 11:48:18 -0500544 bool force,
Brian Osman0c486812019-02-26 10:02:15 -0500545 SkParticleFrame frame) {
546 return sk_sp<SkParticleAffector>(new SkLinearVelocityAffector(angle, strength, force, frame));
547}
548
549sk_sp<SkParticleAffector> SkParticleAffector::MakeAngularVelocity(const SkCurve& strength,
550 bool force) {
551 return sk_sp<SkParticleAffector>(new SkAngularVelocityAffector(strength, force));
Brian Osman7c979f52019-02-12 13:27:51 -0500552}
553
Brian Osman8b6283f2019-02-14 16:55:21 -0500554sk_sp<SkParticleAffector> SkParticleAffector::MakePointForce(SkPoint point, SkScalar constant,
555 SkScalar invSquare) {
Brian Osman7c979f52019-02-12 13:27:51 -0500556 return sk_sp<SkParticleAffector>(new SkPointForceAffector(point, constant, invSquare));
557}
558
Brian Osman0c486812019-02-26 10:02:15 -0500559sk_sp<SkParticleAffector> SkParticleAffector::MakeOrientation(const SkCurve& angle,
560 SkParticleFrame frame) {
561 return sk_sp<SkParticleAffector>(new SkOrientationAffector(angle, frame));
Brian Osman7c979f52019-02-12 13:27:51 -0500562}
Brian Osman8b6283f2019-02-14 16:55:21 -0500563
Brian Osman125daa42019-02-20 12:25:20 -0500564sk_sp<SkParticleAffector> SkParticleAffector::MakeSize(const SkCurve& curve) {
Brian Osman8b6283f2019-02-14 16:55:21 -0500565 return sk_sp<SkParticleAffector>(new SkSizeAffector(curve));
566}
Brian Osman125daa42019-02-20 12:25:20 -0500567
568sk_sp<SkParticleAffector> SkParticleAffector::MakeFrame(const SkCurve& curve) {
569 return sk_sp<SkParticleAffector>(new SkFrameAffector(curve));
570}
571
572sk_sp<SkParticleAffector> SkParticleAffector::MakeColor(const SkColorCurve& curve) {
573 return sk_sp<SkParticleAffector>(new SkColorAffector(curve));
574}