Few more particle features and some generalization work
Add particle "frame" enum, to allow effects relative to local, world,
or velocity. Remove the "orient along velocity" and replace with a much
more general orientation affector (angle curve + frame). Add an angular
velocity affector to mirror the behavior of the linear velocity affector.
Bug: skia:
Change-Id: Ibbaaeb352c9547d00d81c7916d00148dd65ed2b9
Reviewed-on: https://skia-review.googlesource.com/c/195361
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/modules/particles/src/SkParticleAffector.cpp b/modules/particles/src/SkParticleAffector.cpp
index de1a66c..8ff80a0 100644
--- a/modules/particles/src/SkParticleAffector.cpp
+++ b/modules/particles/src/SkParticleAffector.cpp
@@ -21,16 +21,33 @@
v->visit("Enabled", fEnabled);
}
+static inline SkVector get_heading(const SkParticleState& ps, SkParticleFrame frame) {
+ switch (frame) {
+ case kLocal_ParticleFrame:
+ return ps.fPose.fHeading;
+ case kVelocity_ParticleFrame: {
+ SkVector heading = ps.fVelocity.fLinear;
+ if (!heading.normalize()) {
+ heading.set(0, -1);
+ }
+ return heading;
+ }
+ case kWorld_ParticleFrame:
+ default:
+ return SkVector{ 0, -1 };
+ }
+}
+
class SkLinearVelocityAffector : public SkParticleAffector {
public:
SkLinearVelocityAffector(const SkCurve& angle = 0.0f,
const SkCurve& strength = 0.0f,
bool force = true,
- bool local = false)
+ SkParticleFrame frame = kWorld_ParticleFrame)
: fAngle(angle)
, fStrength(strength)
, fForce(force)
- , fLocal(local) {}
+ , fFrame(frame) {}
REFLECTED(SkLinearVelocityAffector, SkParticleAffector)
@@ -38,7 +55,7 @@
for (int i = 0; i < count; ++i) {
float angle = fAngle.eval(ps[i].fAge, ps[i].fStableRandom);
SkScalar c_local, s_local = SkScalarSinCos(SkDegreesToRadians(angle), &c_local);
- SkVector heading = fLocal ? ps[i].fPose.fHeading : SkVector{ 0, -1 };
+ SkVector heading = get_heading(ps[i], static_cast<SkParticleFrame>(fFrame));
SkScalar c = heading.fX * c_local - heading.fY * s_local;
SkScalar s = heading.fX * s_local + heading.fY * c_local;
float strength = fStrength.eval(ps[i].fAge, ps[i].fStableRandom);
@@ -54,7 +71,7 @@
void visitFields(SkFieldVisitor* v) override {
SkParticleAffector::visitFields(v);
v->visit("Force", fForce);
- v->visit("Local", fLocal);
+ v->visit("Frame", fFrame);
v->visit("Angle", fAngle);
v->visit("Strength", fStrength);
}
@@ -63,7 +80,37 @@
SkCurve fAngle;
SkCurve fStrength;
bool fForce;
- bool fLocal;
+ int fFrame;
+};
+
+class SkAngularVelocityAffector : public SkParticleAffector {
+public:
+ SkAngularVelocityAffector(const SkCurve& strength = 0.0f, bool force = true)
+ : fStrength(strength)
+ , fForce(force) {}
+
+ REFLECTED(SkAngularVelocityAffector, SkParticleAffector)
+
+ void onApply(SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
+ for (int i = 0; i < count; ++i) {
+ float strength = fStrength.eval(ps[i].fAge, ps[i].fStableRandom);
+ if (fForce) {
+ ps[i].fVelocity.fAngular += strength * params.fDeltaTime;
+ } else {
+ ps[i].fVelocity.fAngular = strength;
+ }
+ }
+ }
+
+ void visitFields(SkFieldVisitor* v) override {
+ SkParticleAffector::visitFields(v);
+ v->visit("Force", fForce);
+ v->visit("Strength", fStrength);
+ }
+
+private:
+ SkCurve fStrength;
+ bool fForce;
};
class SkPointForceAffector : public SkParticleAffector {
@@ -97,25 +144,34 @@
SkScalar fInvSquare;
};
-class SkOrientAlongVelocityAffector : public SkParticleAffector {
+class SkOrientationAffector : public SkParticleAffector {
public:
- SkOrientAlongVelocityAffector() {}
+ SkOrientationAffector(const SkCurve& angle = 0.0f,
+ SkParticleFrame frame = kLocal_ParticleFrame)
+ : fAngle(angle)
+ , fFrame(frame) {}
- REFLECTED(SkOrientAlongVelocityAffector, SkParticleAffector)
+ REFLECTED(SkOrientationAffector, SkParticleAffector)
void onApply(SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
for (int i = 0; i < count; ++i) {
- SkVector heading = ps[i].fVelocity.fLinear;
- if (!heading.normalize()) {
- heading.set(0, -1);
- }
- ps[i].fPose.fHeading = heading;
+ float angle = fAngle.eval(ps[i].fAge, ps[i].fStableRandom);
+ SkScalar c_local, s_local = SkScalarSinCos(SkDegreesToRadians(angle), &c_local);
+ SkVector heading = get_heading(ps[i], static_cast<SkParticleFrame>(fFrame));
+ ps[i].fPose.fHeading.set(heading.fX * c_local - heading.fY * s_local,
+ heading.fX * s_local + heading.fY * c_local);
}
}
void visitFields(SkFieldVisitor *v) override {
SkParticleAffector::visitFields(v);
+ v->visit("Frame", fFrame);
+ v->visit("Angle", fAngle);
}
+
+private:
+ SkCurve fAngle;
+ int fFrame;
};
class SkSizeAffector : public SkParticleAffector {
@@ -185,8 +241,9 @@
void SkParticleAffector::RegisterAffectorTypes() {
REGISTER_REFLECTED(SkParticleAffector);
REGISTER_REFLECTED(SkLinearVelocityAffector);
+ REGISTER_REFLECTED(SkAngularVelocityAffector);
REGISTER_REFLECTED(SkPointForceAffector);
- REGISTER_REFLECTED(SkOrientAlongVelocityAffector);
+ REGISTER_REFLECTED(SkOrientationAffector);
REGISTER_REFLECTED(SkSizeAffector);
REGISTER_REFLECTED(SkFrameAffector);
REGISTER_REFLECTED(SkColorAffector);
@@ -195,8 +252,13 @@
sk_sp<SkParticleAffector> SkParticleAffector::MakeLinearVelocity(const SkCurve& angle,
const SkCurve& strength,
bool force,
- bool local) {
- return sk_sp<SkParticleAffector>(new SkLinearVelocityAffector(angle, strength, force, local));
+ SkParticleFrame frame) {
+ return sk_sp<SkParticleAffector>(new SkLinearVelocityAffector(angle, strength, force, frame));
+}
+
+sk_sp<SkParticleAffector> SkParticleAffector::MakeAngularVelocity(const SkCurve& strength,
+ bool force) {
+ return sk_sp<SkParticleAffector>(new SkAngularVelocityAffector(strength, force));
}
sk_sp<SkParticleAffector> SkParticleAffector::MakePointForce(SkPoint point, SkScalar constant,
@@ -204,8 +266,9 @@
return sk_sp<SkParticleAffector>(new SkPointForceAffector(point, constant, invSquare));
}
-sk_sp<SkParticleAffector> SkParticleAffector::MakeOrientAlongVelocity() {
- return sk_sp<SkParticleAffector>(new SkOrientAlongVelocityAffector());
+sk_sp<SkParticleAffector> SkParticleAffector::MakeOrientation(const SkCurve& angle,
+ SkParticleFrame frame) {
+ return sk_sp<SkParticleAffector>(new SkOrientationAffector(angle, frame));
}
sk_sp<SkParticleAffector> SkParticleAffector::MakeSize(const SkCurve& curve) {