blob: 8ff80a0806f599d88711a7aff77812d11a713baa [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 Osman14a67a32019-02-25 14:30:44 -050014void SkParticleAffector::apply(SkParticleUpdateParams& params, SkParticleState ps[], int count) {
Brian Osman1b20cd82019-02-25 14:15:02 -050015 if (fEnabled) {
Brian Osman14a67a32019-02-25 14:30:44 -050016 this->onApply(params, ps, count);
Brian Osman1b20cd82019-02-25 14:15:02 -050017 }
18}
19
20void SkParticleAffector::visitFields(SkFieldVisitor* v) {
21 v->visit("Enabled", fEnabled);
22}
23
Brian Osman0c486812019-02-26 10:02:15 -050024static inline SkVector get_heading(const SkParticleState& ps, SkParticleFrame frame) {
25 switch (frame) {
26 case kLocal_ParticleFrame:
27 return ps.fPose.fHeading;
28 case kVelocity_ParticleFrame: {
29 SkVector heading = ps.fVelocity.fLinear;
30 if (!heading.normalize()) {
31 heading.set(0, -1);
32 }
33 return heading;
34 }
35 case kWorld_ParticleFrame:
36 default:
37 return SkVector{ 0, -1 };
38 }
39}
40
Brian Osman8b6283f2019-02-14 16:55:21 -050041class SkLinearVelocityAffector : public SkParticleAffector {
Brian Osman7c979f52019-02-12 13:27:51 -050042public:
Brian Osman8b6283f2019-02-14 16:55:21 -050043 SkLinearVelocityAffector(const SkCurve& angle = 0.0f,
44 const SkCurve& strength = 0.0f,
Brian Osmand5c57fe2019-02-22 11:48:18 -050045 bool force = true,
Brian Osman0c486812019-02-26 10:02:15 -050046 SkParticleFrame frame = kWorld_ParticleFrame)
Brian Osman8b6283f2019-02-14 16:55:21 -050047 : fAngle(angle)
48 , fStrength(strength)
Brian Osmand5c57fe2019-02-22 11:48:18 -050049 , fForce(force)
Brian Osman0c486812019-02-26 10:02:15 -050050 , fFrame(frame) {}
Brian Osman7c979f52019-02-12 13:27:51 -050051
Brian Osman8b6283f2019-02-14 16:55:21 -050052 REFLECTED(SkLinearVelocityAffector, SkParticleAffector)
Brian Osman7c979f52019-02-12 13:27:51 -050053
Brian Osman14a67a32019-02-25 14:30:44 -050054 void onApply(SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
55 for (int i = 0; i < count; ++i) {
56 float angle = fAngle.eval(ps[i].fAge, ps[i].fStableRandom);
57 SkScalar c_local, s_local = SkScalarSinCos(SkDegreesToRadians(angle), &c_local);
Brian Osman0c486812019-02-26 10:02:15 -050058 SkVector heading = get_heading(ps[i], static_cast<SkParticleFrame>(fFrame));
Brian Osman14a67a32019-02-25 14:30:44 -050059 SkScalar c = heading.fX * c_local - heading.fY * s_local;
60 SkScalar s = heading.fX * s_local + heading.fY * c_local;
61 float strength = fStrength.eval(ps[i].fAge, ps[i].fStableRandom);
62 SkVector force = { c * strength, s * strength };
63 if (fForce) {
64 ps[i].fVelocity.fLinear += force * params.fDeltaTime;
65 } else {
66 ps[i].fVelocity.fLinear = force;
67 }
Brian Osman8b6283f2019-02-14 16:55:21 -050068 }
Brian Osman7c979f52019-02-12 13:27:51 -050069 }
70
71 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -050072 SkParticleAffector::visitFields(v);
Brian Osman7c979f52019-02-12 13:27:51 -050073 v->visit("Force", fForce);
Brian Osman0c486812019-02-26 10:02:15 -050074 v->visit("Frame", fFrame);
Brian Osman7c979f52019-02-12 13:27:51 -050075 v->visit("Angle", fAngle);
76 v->visit("Strength", fStrength);
Brian Osman7c979f52019-02-12 13:27:51 -050077 }
78
79private:
80 SkCurve fAngle;
81 SkCurve fStrength;
Brian Osman8b6283f2019-02-14 16:55:21 -050082 bool fForce;
Brian Osman0c486812019-02-26 10:02:15 -050083 int fFrame;
84};
85
86class SkAngularVelocityAffector : public SkParticleAffector {
87public:
88 SkAngularVelocityAffector(const SkCurve& strength = 0.0f, bool force = true)
89 : fStrength(strength)
90 , fForce(force) {}
91
92 REFLECTED(SkAngularVelocityAffector, SkParticleAffector)
93
94 void onApply(SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
95 for (int i = 0; i < count; ++i) {
96 float strength = fStrength.eval(ps[i].fAge, ps[i].fStableRandom);
97 if (fForce) {
98 ps[i].fVelocity.fAngular += strength * params.fDeltaTime;
99 } else {
100 ps[i].fVelocity.fAngular = strength;
101 }
102 }
103 }
104
105 void visitFields(SkFieldVisitor* v) override {
106 SkParticleAffector::visitFields(v);
107 v->visit("Force", fForce);
108 v->visit("Strength", fStrength);
109 }
110
111private:
112 SkCurve fStrength;
113 bool fForce;
Brian Osman7c979f52019-02-12 13:27:51 -0500114};
115
116class SkPointForceAffector : public SkParticleAffector {
117public:
118 SkPointForceAffector(SkPoint point = { 0.0f, 0.0f }, SkScalar constant = 0.0f,
119 SkScalar invSquare = 0.0f)
120 : fPoint(point), fConstant(constant), fInvSquare(invSquare) {}
121
122 REFLECTED(SkPointForceAffector, SkParticleAffector)
123
Brian Osman14a67a32019-02-25 14:30:44 -0500124 void onApply(SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
125 for (int i = 0; i < count; ++i) {
126 SkVector toPoint = fPoint - ps[i].fPose.fPosition;
127 SkScalar lenSquare = toPoint.dot(toPoint);
128 toPoint.normalize();
129 ps[i].fVelocity.fLinear +=
130 toPoint * (fConstant + (fInvSquare / lenSquare)) * params.fDeltaTime;
131 }
Brian Osman7c979f52019-02-12 13:27:51 -0500132 }
133
134 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500135 SkParticleAffector::visitFields(v);
Brian Osman7c979f52019-02-12 13:27:51 -0500136 v->visit("Point", fPoint);
137 v->visit("Constant", fConstant);
138 v->visit("InvSquare", fInvSquare);
139 }
140
141private:
142 SkPoint fPoint;
143 SkScalar fConstant;
144 SkScalar fInvSquare;
145};
146
Brian Osman0c486812019-02-26 10:02:15 -0500147class SkOrientationAffector : public SkParticleAffector {
Brian Osman7c979f52019-02-12 13:27:51 -0500148public:
Brian Osman0c486812019-02-26 10:02:15 -0500149 SkOrientationAffector(const SkCurve& angle = 0.0f,
150 SkParticleFrame frame = kLocal_ParticleFrame)
151 : fAngle(angle)
152 , fFrame(frame) {}
Brian Osman7c979f52019-02-12 13:27:51 -0500153
Brian Osman0c486812019-02-26 10:02:15 -0500154 REFLECTED(SkOrientationAffector, SkParticleAffector)
Brian Osman7c979f52019-02-12 13:27:51 -0500155
Brian Osman14a67a32019-02-25 14:30:44 -0500156 void onApply(SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
157 for (int i = 0; i < count; ++i) {
Brian Osman0c486812019-02-26 10:02:15 -0500158 float angle = fAngle.eval(ps[i].fAge, ps[i].fStableRandom);
159 SkScalar c_local, s_local = SkScalarSinCos(SkDegreesToRadians(angle), &c_local);
160 SkVector heading = get_heading(ps[i], static_cast<SkParticleFrame>(fFrame));
161 ps[i].fPose.fHeading.set(heading.fX * c_local - heading.fY * s_local,
162 heading.fX * s_local + heading.fY * c_local);
Brian Osman7c979f52019-02-12 13:27:51 -0500163 }
Brian Osman7c979f52019-02-12 13:27:51 -0500164 }
165
Brian Osman1b20cd82019-02-25 14:15:02 -0500166 void visitFields(SkFieldVisitor *v) override {
167 SkParticleAffector::visitFields(v);
Brian Osman0c486812019-02-26 10:02:15 -0500168 v->visit("Frame", fFrame);
169 v->visit("Angle", fAngle);
Brian Osman1b20cd82019-02-25 14:15:02 -0500170 }
Brian Osman0c486812019-02-26 10:02:15 -0500171
172private:
173 SkCurve fAngle;
174 int fFrame;
Brian Osman7c979f52019-02-12 13:27:51 -0500175};
176
Brian Osman8b6283f2019-02-14 16:55:21 -0500177class SkSizeAffector : public SkParticleAffector {
Brian Osman7c979f52019-02-12 13:27:51 -0500178public:
Brian Osman8b6283f2019-02-14 16:55:21 -0500179 SkSizeAffector(const SkCurve& curve = 1.0f) : fCurve(curve) {}
Brian Osman7c979f52019-02-12 13:27:51 -0500180
Brian Osman8b6283f2019-02-14 16:55:21 -0500181 REFLECTED(SkSizeAffector, SkParticleAffector)
Brian Osman7c979f52019-02-12 13:27:51 -0500182
Brian Osman14a67a32019-02-25 14:30:44 -0500183 void onApply(SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
184 for (int i = 0; i < count; ++i) {
185 ps[i].fPose.fScale = fCurve.eval(ps[i].fAge, ps[i].fStableRandom);
186 }
Brian Osman7c979f52019-02-12 13:27:51 -0500187 }
188
189 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500190 SkParticleAffector::visitFields(v);
Brian Osman8b6283f2019-02-14 16:55:21 -0500191 v->visit("Curve", fCurve);
Brian Osman7c979f52019-02-12 13:27:51 -0500192 }
193
194private:
Brian Osman8b6283f2019-02-14 16:55:21 -0500195 SkCurve fCurve;
Brian Osman7c979f52019-02-12 13:27:51 -0500196};
197
Brian Osman125daa42019-02-20 12:25:20 -0500198class SkFrameAffector : public SkParticleAffector {
199public:
200 SkFrameAffector(const SkCurve& curve = 1.0f) : fCurve(curve) {}
201
202 REFLECTED(SkFrameAffector, SkParticleAffector)
203
Brian Osman14a67a32019-02-25 14:30:44 -0500204 void onApply(SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
205 for (int i = 0; i < count; ++i) {
206 ps[i].fFrame = fCurve.eval(ps[i].fAge, ps[i].fStableRandom);
207 }
Brian Osman125daa42019-02-20 12:25:20 -0500208 }
209
210 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500211 SkParticleAffector::visitFields(v);
Brian Osman125daa42019-02-20 12:25:20 -0500212 v->visit("Curve", fCurve);
213 }
214
215private:
216 SkCurve fCurve;
217};
218
219class SkColorAffector : public SkParticleAffector {
220public:
221 SkColorAffector(const SkColorCurve& curve = SkColor4f{ 1.0f, 1.0f, 1.0f, 1.0f })
222 : fCurve(curve) {}
223
224 REFLECTED(SkColorAffector, SkParticleAffector)
225
Brian Osman14a67a32019-02-25 14:30:44 -0500226 void onApply(SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
227 for (int i = 0; i < count; ++i) {
228 ps[i].fColor = fCurve.eval(ps[i].fAge, ps[i].fStableRandom);
229 }
Brian Osman125daa42019-02-20 12:25:20 -0500230 }
231
232 void visitFields(SkFieldVisitor* v) override {
Brian Osman1b20cd82019-02-25 14:15:02 -0500233 SkParticleAffector::visitFields(v);
Brian Osman125daa42019-02-20 12:25:20 -0500234 v->visit("Curve", fCurve);
235 }
236
237private:
238 SkColorCurve fCurve;
239};
240
Brian Osman7c979f52019-02-12 13:27:51 -0500241void SkParticleAffector::RegisterAffectorTypes() {
242 REGISTER_REFLECTED(SkParticleAffector);
Brian Osman8b6283f2019-02-14 16:55:21 -0500243 REGISTER_REFLECTED(SkLinearVelocityAffector);
Brian Osman0c486812019-02-26 10:02:15 -0500244 REGISTER_REFLECTED(SkAngularVelocityAffector);
Brian Osman7c979f52019-02-12 13:27:51 -0500245 REGISTER_REFLECTED(SkPointForceAffector);
Brian Osman0c486812019-02-26 10:02:15 -0500246 REGISTER_REFLECTED(SkOrientationAffector);
Brian Osman8b6283f2019-02-14 16:55:21 -0500247 REGISTER_REFLECTED(SkSizeAffector);
Brian Osman125daa42019-02-20 12:25:20 -0500248 REGISTER_REFLECTED(SkFrameAffector);
249 REGISTER_REFLECTED(SkColorAffector);
Brian Osman7c979f52019-02-12 13:27:51 -0500250}
251
Brian Osman8b6283f2019-02-14 16:55:21 -0500252sk_sp<SkParticleAffector> SkParticleAffector::MakeLinearVelocity(const SkCurve& angle,
253 const SkCurve& strength,
Brian Osmand5c57fe2019-02-22 11:48:18 -0500254 bool force,
Brian Osman0c486812019-02-26 10:02:15 -0500255 SkParticleFrame frame) {
256 return sk_sp<SkParticleAffector>(new SkLinearVelocityAffector(angle, strength, force, frame));
257}
258
259sk_sp<SkParticleAffector> SkParticleAffector::MakeAngularVelocity(const SkCurve& strength,
260 bool force) {
261 return sk_sp<SkParticleAffector>(new SkAngularVelocityAffector(strength, force));
Brian Osman7c979f52019-02-12 13:27:51 -0500262}
263
Brian Osman8b6283f2019-02-14 16:55:21 -0500264sk_sp<SkParticleAffector> SkParticleAffector::MakePointForce(SkPoint point, SkScalar constant,
265 SkScalar invSquare) {
Brian Osman7c979f52019-02-12 13:27:51 -0500266 return sk_sp<SkParticleAffector>(new SkPointForceAffector(point, constant, invSquare));
267}
268
Brian Osman0c486812019-02-26 10:02:15 -0500269sk_sp<SkParticleAffector> SkParticleAffector::MakeOrientation(const SkCurve& angle,
270 SkParticleFrame frame) {
271 return sk_sp<SkParticleAffector>(new SkOrientationAffector(angle, frame));
Brian Osman7c979f52019-02-12 13:27:51 -0500272}
Brian Osman8b6283f2019-02-14 16:55:21 -0500273
Brian Osman125daa42019-02-20 12:25:20 -0500274sk_sp<SkParticleAffector> SkParticleAffector::MakeSize(const SkCurve& curve) {
Brian Osman8b6283f2019-02-14 16:55:21 -0500275 return sk_sp<SkParticleAffector>(new SkSizeAffector(curve));
276}
Brian Osman125daa42019-02-20 12:25:20 -0500277
278sk_sp<SkParticleAffector> SkParticleAffector::MakeFrame(const SkCurve& curve) {
279 return sk_sp<SkParticleAffector>(new SkFrameAffector(curve));
280}
281
282sk_sp<SkParticleAffector> SkParticleAffector::MakeColor(const SkColorCurve& curve) {
283 return sk_sp<SkParticleAffector>(new SkColorAffector(curve));
284}