blob: ba7385529749b89379912676439b868b707f8329 [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
8#include "SkParticleAffector.h"
9
Brian Osman8b6283f2019-02-14 16:55:21 -050010#include "SkCurve.h"
Brian Osman7c979f52019-02-12 13:27:51 -050011#include "SkParticleData.h"
12#include "SkRandom.h"
13
Brian Osmane5d532e2019-02-26 14:58:40 -050014constexpr SkFieldVisitor::EnumStringMapping gParticleFrameMapping[] = {
15 { kWorld_ParticleFrame, "World" },
16 { kLocal_ParticleFrame, "Local" },
17 { kVelocity_ParticleFrame, "Velocity" },
18};
19
Brian Osman14a67a32019-02-25 14:30:44 -050020void SkParticleAffector::apply(SkParticleUpdateParams& params, SkParticleState ps[], int count) {
Brian Osman1b20cd82019-02-25 14:15:02 -050021 if (fEnabled) {
Brian Osman14a67a32019-02-25 14:30:44 -050022 this->onApply(params, ps, count);
Brian Osman1b20cd82019-02-25 14:15:02 -050023 }
24}
25
26void SkParticleAffector::visitFields(SkFieldVisitor* v) {
27 v->visit("Enabled", fEnabled);
28}
29
Brian Osman0c486812019-02-26 10:02:15 -050030static inline SkVector get_heading(const SkParticleState& ps, SkParticleFrame frame) {
31 switch (frame) {
32 case kLocal_ParticleFrame:
33 return ps.fPose.fHeading;
34 case kVelocity_ParticleFrame: {
35 SkVector heading = ps.fVelocity.fLinear;
36 if (!heading.normalize()) {
37 heading.set(0, -1);
38 }
39 return heading;
40 }
41 case kWorld_ParticleFrame:
42 default:
43 return SkVector{ 0, -1 };
44 }
45}
46
Brian Osman8b6283f2019-02-14 16:55:21 -050047class SkLinearVelocityAffector : public SkParticleAffector {
Brian Osman7c979f52019-02-12 13:27:51 -050048public:
Brian Osman8b6283f2019-02-14 16:55:21 -050049 SkLinearVelocityAffector(const SkCurve& angle = 0.0f,
50 const SkCurve& strength = 0.0f,
Brian Osmand5c57fe2019-02-22 11:48:18 -050051 bool force = true,
Brian Osman0c486812019-02-26 10:02:15 -050052 SkParticleFrame frame = kWorld_ParticleFrame)
Brian Osman8b6283f2019-02-14 16:55:21 -050053 : fAngle(angle)
54 , fStrength(strength)
Brian Osmand5c57fe2019-02-22 11:48:18 -050055 , fForce(force)
Brian Osman0c486812019-02-26 10:02:15 -050056 , fFrame(frame) {}
Brian Osman7c979f52019-02-12 13:27:51 -050057
Brian Osman8b6283f2019-02-14 16:55:21 -050058 REFLECTED(SkLinearVelocityAffector, SkParticleAffector)
Brian Osman7c979f52019-02-12 13:27:51 -050059
Brian Osman14a67a32019-02-25 14:30:44 -050060 void onApply(SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
61 for (int i = 0; i < count; ++i) {
Brian Osmane5d532e2019-02-26 14:58:40 -050062 float angle = fAngle.eval(ps[i].fAge, ps[i].fRandom);
Brian Osman14a67a32019-02-25 14:30:44 -050063 SkScalar c_local, s_local = SkScalarSinCos(SkDegreesToRadians(angle), &c_local);
Brian Osman0c486812019-02-26 10:02:15 -050064 SkVector heading = get_heading(ps[i], static_cast<SkParticleFrame>(fFrame));
Brian Osman14a67a32019-02-25 14:30:44 -050065 SkScalar c = heading.fX * c_local - heading.fY * s_local;
66 SkScalar s = heading.fX * s_local + heading.fY * c_local;
Brian Osmane5d532e2019-02-26 14:58:40 -050067 float strength = fStrength.eval(ps[i].fAge, ps[i].fRandom);
Brian Osman14a67a32019-02-25 14:30:44 -050068 SkVector force = { c * strength, s * strength };
69 if (fForce) {
70 ps[i].fVelocity.fLinear += force * params.fDeltaTime;
71 } else {
72 ps[i].fVelocity.fLinear = force;
73 }
Brian Osman8b6283f2019-02-14 16:55:21 -050074 }
Brian Osman7c979f52019-02-12 13:27:51 -050075 }
76
77 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -050078 SkParticleAffector::visitFields(v);
Brian Osman7c979f52019-02-12 13:27:51 -050079 v->visit("Force", fForce);
Brian Osmane5d532e2019-02-26 14:58:40 -050080 v->visit("Frame", fFrame, gParticleFrameMapping, SK_ARRAY_COUNT(gParticleFrameMapping));
Brian Osman7c979f52019-02-12 13:27:51 -050081 v->visit("Angle", fAngle);
82 v->visit("Strength", fStrength);
Brian Osman7c979f52019-02-12 13:27:51 -050083 }
84
85private:
86 SkCurve fAngle;
87 SkCurve fStrength;
Brian Osman8b6283f2019-02-14 16:55:21 -050088 bool fForce;
Brian Osman0c486812019-02-26 10:02:15 -050089 int fFrame;
90};
91
92class SkAngularVelocityAffector : public SkParticleAffector {
93public:
94 SkAngularVelocityAffector(const SkCurve& strength = 0.0f, bool force = true)
95 : fStrength(strength)
96 , fForce(force) {}
97
98 REFLECTED(SkAngularVelocityAffector, SkParticleAffector)
99
100 void onApply(SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
101 for (int i = 0; i < count; ++i) {
Brian Osmane5d532e2019-02-26 14:58:40 -0500102 float strength = fStrength.eval(ps[i].fAge, ps[i].fRandom);
Brian Osman0c486812019-02-26 10:02:15 -0500103 if (fForce) {
104 ps[i].fVelocity.fAngular += strength * params.fDeltaTime;
105 } else {
106 ps[i].fVelocity.fAngular = strength;
107 }
108 }
109 }
110
111 void visitFields(SkFieldVisitor* v) override {
112 SkParticleAffector::visitFields(v);
113 v->visit("Force", fForce);
114 v->visit("Strength", fStrength);
115 }
116
117private:
118 SkCurve fStrength;
119 bool fForce;
Brian Osman7c979f52019-02-12 13:27:51 -0500120};
121
122class SkPointForceAffector : public SkParticleAffector {
123public:
124 SkPointForceAffector(SkPoint point = { 0.0f, 0.0f }, SkScalar constant = 0.0f,
125 SkScalar invSquare = 0.0f)
126 : fPoint(point), fConstant(constant), fInvSquare(invSquare) {}
127
128 REFLECTED(SkPointForceAffector, SkParticleAffector)
129
Brian Osman14a67a32019-02-25 14:30:44 -0500130 void onApply(SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
131 for (int i = 0; i < count; ++i) {
132 SkVector toPoint = fPoint - ps[i].fPose.fPosition;
133 SkScalar lenSquare = toPoint.dot(toPoint);
134 toPoint.normalize();
135 ps[i].fVelocity.fLinear +=
136 toPoint * (fConstant + (fInvSquare / lenSquare)) * params.fDeltaTime;
137 }
Brian Osman7c979f52019-02-12 13:27:51 -0500138 }
139
140 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500141 SkParticleAffector::visitFields(v);
Brian Osman7c979f52019-02-12 13:27:51 -0500142 v->visit("Point", fPoint);
143 v->visit("Constant", fConstant);
144 v->visit("InvSquare", fInvSquare);
145 }
146
147private:
148 SkPoint fPoint;
149 SkScalar fConstant;
150 SkScalar fInvSquare;
151};
152
Brian Osman0c486812019-02-26 10:02:15 -0500153class SkOrientationAffector : public SkParticleAffector {
Brian Osman7c979f52019-02-12 13:27:51 -0500154public:
Brian Osman0c486812019-02-26 10:02:15 -0500155 SkOrientationAffector(const SkCurve& angle = 0.0f,
156 SkParticleFrame frame = kLocal_ParticleFrame)
157 : fAngle(angle)
158 , fFrame(frame) {}
Brian Osman7c979f52019-02-12 13:27:51 -0500159
Brian Osman0c486812019-02-26 10:02:15 -0500160 REFLECTED(SkOrientationAffector, SkParticleAffector)
Brian Osman7c979f52019-02-12 13:27:51 -0500161
Brian Osman14a67a32019-02-25 14:30:44 -0500162 void onApply(SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
163 for (int i = 0; i < count; ++i) {
Brian Osmane5d532e2019-02-26 14:58:40 -0500164 float angle = fAngle.eval(ps[i].fAge, ps[i].fRandom);
Brian Osman0c486812019-02-26 10:02:15 -0500165 SkScalar c_local, s_local = SkScalarSinCos(SkDegreesToRadians(angle), &c_local);
166 SkVector heading = get_heading(ps[i], static_cast<SkParticleFrame>(fFrame));
167 ps[i].fPose.fHeading.set(heading.fX * c_local - heading.fY * s_local,
168 heading.fX * s_local + heading.fY * c_local);
Brian Osman7c979f52019-02-12 13:27:51 -0500169 }
Brian Osman7c979f52019-02-12 13:27:51 -0500170 }
171
Brian Osman1b20cd82019-02-25 14:15:02 -0500172 void visitFields(SkFieldVisitor *v) override {
173 SkParticleAffector::visitFields(v);
Brian Osmane5d532e2019-02-26 14:58:40 -0500174 v->visit("Frame", fFrame, gParticleFrameMapping, SK_ARRAY_COUNT(gParticleFrameMapping));
Brian Osman0c486812019-02-26 10:02:15 -0500175 v->visit("Angle", fAngle);
Brian Osman1b20cd82019-02-25 14:15:02 -0500176 }
Brian Osman0c486812019-02-26 10:02:15 -0500177
178private:
179 SkCurve fAngle;
180 int fFrame;
Brian Osman7c979f52019-02-12 13:27:51 -0500181};
182
Brian Osman8b6283f2019-02-14 16:55:21 -0500183class SkSizeAffector : public SkParticleAffector {
Brian Osman7c979f52019-02-12 13:27:51 -0500184public:
Brian Osman8b6283f2019-02-14 16:55:21 -0500185 SkSizeAffector(const SkCurve& curve = 1.0f) : fCurve(curve) {}
Brian Osman7c979f52019-02-12 13:27:51 -0500186
Brian Osman8b6283f2019-02-14 16:55:21 -0500187 REFLECTED(SkSizeAffector, SkParticleAffector)
Brian Osman7c979f52019-02-12 13:27:51 -0500188
Brian Osman14a67a32019-02-25 14:30:44 -0500189 void onApply(SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
190 for (int i = 0; i < count; ++i) {
Brian Osmane5d532e2019-02-26 14:58:40 -0500191 ps[i].fPose.fScale = fCurve.eval(ps[i].fAge, ps[i].fRandom);
Brian Osman14a67a32019-02-25 14:30:44 -0500192 }
Brian Osman7c979f52019-02-12 13:27:51 -0500193 }
194
195 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500196 SkParticleAffector::visitFields(v);
Brian Osman8b6283f2019-02-14 16:55:21 -0500197 v->visit("Curve", fCurve);
Brian Osman7c979f52019-02-12 13:27:51 -0500198 }
199
200private:
Brian Osman8b6283f2019-02-14 16:55:21 -0500201 SkCurve fCurve;
Brian Osman7c979f52019-02-12 13:27:51 -0500202};
203
Brian Osman125daa42019-02-20 12:25:20 -0500204class SkFrameAffector : public SkParticleAffector {
205public:
206 SkFrameAffector(const SkCurve& curve = 1.0f) : fCurve(curve) {}
207
208 REFLECTED(SkFrameAffector, SkParticleAffector)
209
Brian Osman14a67a32019-02-25 14:30:44 -0500210 void onApply(SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
211 for (int i = 0; i < count; ++i) {
Brian Osmane5d532e2019-02-26 14:58:40 -0500212 ps[i].fFrame = fCurve.eval(ps[i].fAge, ps[i].fRandom);
Brian Osman14a67a32019-02-25 14:30:44 -0500213 }
Brian Osman125daa42019-02-20 12:25:20 -0500214 }
215
216 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500217 SkParticleAffector::visitFields(v);
Brian Osman125daa42019-02-20 12:25:20 -0500218 v->visit("Curve", fCurve);
219 }
220
221private:
222 SkCurve fCurve;
223};
224
225class SkColorAffector : public SkParticleAffector {
226public:
227 SkColorAffector(const SkColorCurve& curve = SkColor4f{ 1.0f, 1.0f, 1.0f, 1.0f })
228 : fCurve(curve) {}
229
230 REFLECTED(SkColorAffector, SkParticleAffector)
231
Brian Osman14a67a32019-02-25 14:30:44 -0500232 void onApply(SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
233 for (int i = 0; i < count; ++i) {
Brian Osmane5d532e2019-02-26 14:58:40 -0500234 ps[i].fColor = fCurve.eval(ps[i].fAge, ps[i].fRandom);
Brian Osman14a67a32019-02-25 14:30:44 -0500235 }
Brian Osman125daa42019-02-20 12:25:20 -0500236 }
237
238 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500239 SkParticleAffector::visitFields(v);
Brian Osman125daa42019-02-20 12:25:20 -0500240 v->visit("Curve", fCurve);
241 }
242
243private:
244 SkColorCurve fCurve;
245};
246
Brian Osman7c979f52019-02-12 13:27:51 -0500247void SkParticleAffector::RegisterAffectorTypes() {
248 REGISTER_REFLECTED(SkParticleAffector);
Brian Osman8b6283f2019-02-14 16:55:21 -0500249 REGISTER_REFLECTED(SkLinearVelocityAffector);
Brian Osman0c486812019-02-26 10:02:15 -0500250 REGISTER_REFLECTED(SkAngularVelocityAffector);
Brian Osman7c979f52019-02-12 13:27:51 -0500251 REGISTER_REFLECTED(SkPointForceAffector);
Brian Osman0c486812019-02-26 10:02:15 -0500252 REGISTER_REFLECTED(SkOrientationAffector);
Brian Osman8b6283f2019-02-14 16:55:21 -0500253 REGISTER_REFLECTED(SkSizeAffector);
Brian Osman125daa42019-02-20 12:25:20 -0500254 REGISTER_REFLECTED(SkFrameAffector);
255 REGISTER_REFLECTED(SkColorAffector);
Brian Osman7c979f52019-02-12 13:27:51 -0500256}
257
Brian Osman8b6283f2019-02-14 16:55:21 -0500258sk_sp<SkParticleAffector> SkParticleAffector::MakeLinearVelocity(const SkCurve& angle,
259 const SkCurve& strength,
Brian Osmand5c57fe2019-02-22 11:48:18 -0500260 bool force,
Brian Osman0c486812019-02-26 10:02:15 -0500261 SkParticleFrame frame) {
262 return sk_sp<SkParticleAffector>(new SkLinearVelocityAffector(angle, strength, force, frame));
263}
264
265sk_sp<SkParticleAffector> SkParticleAffector::MakeAngularVelocity(const SkCurve& strength,
266 bool force) {
267 return sk_sp<SkParticleAffector>(new SkAngularVelocityAffector(strength, force));
Brian Osman7c979f52019-02-12 13:27:51 -0500268}
269
Brian Osman8b6283f2019-02-14 16:55:21 -0500270sk_sp<SkParticleAffector> SkParticleAffector::MakePointForce(SkPoint point, SkScalar constant,
271 SkScalar invSquare) {
Brian Osman7c979f52019-02-12 13:27:51 -0500272 return sk_sp<SkParticleAffector>(new SkPointForceAffector(point, constant, invSquare));
273}
274
Brian Osman0c486812019-02-26 10:02:15 -0500275sk_sp<SkParticleAffector> SkParticleAffector::MakeOrientation(const SkCurve& angle,
276 SkParticleFrame frame) {
277 return sk_sp<SkParticleAffector>(new SkOrientationAffector(angle, frame));
Brian Osman7c979f52019-02-12 13:27:51 -0500278}
Brian Osman8b6283f2019-02-14 16:55:21 -0500279
Brian Osman125daa42019-02-20 12:25:20 -0500280sk_sp<SkParticleAffector> SkParticleAffector::MakeSize(const SkCurve& curve) {
Brian Osman8b6283f2019-02-14 16:55:21 -0500281 return sk_sp<SkParticleAffector>(new SkSizeAffector(curve));
282}
Brian Osman125daa42019-02-20 12:25:20 -0500283
284sk_sp<SkParticleAffector> SkParticleAffector::MakeFrame(const SkCurve& curve) {
285 return sk_sp<SkParticleAffector>(new SkFrameAffector(curve));
286}
287
288sk_sp<SkParticleAffector> SkParticleAffector::MakeColor(const SkColorCurve& curve) {
289 return sk_sp<SkParticleAffector>(new SkColorAffector(curve));
290}