Particles: remove non-stable random, add better enum reflection

The other generator was never used (or useful). String-based serialization
of enums is quite helpful, though.

Bug: skia:
Change-Id: Ic9d58f8d20cfe7aba47722bd74f1e6f8f0f219e5
Reviewed-on: https://skia-review.googlesource.com/c/195368
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Osman 2019-02-26 14:58:40 -05:00 committed by Skia Commit-Bot
parent f12d675179
commit e5d532edae
11 changed files with 74 additions and 22 deletions

View File

@ -43,11 +43,10 @@ struct SkParticleState {
SkParticleVelocity fVelocity;
SkColor4f fColor;
SkScalar fFrame; // Parameter to drawable for animated sprites, etc.
SkRandom fStableRandom;
SkRandom fRandom;
};
struct SkParticleUpdateParams {
SkRandom* fRandom;
float fDeltaTime;
};

View File

@ -31,6 +31,9 @@ public:
void visit(const char* name, SkString& s) override {
fWriter.appendString(name, s.c_str());
}
void visit(const char* name, int& i, const EnumStringMapping* map, int count) override {
fWriter.appendString(name, EnumToString(i, map, count));
}
// Compound types
void visit(const char* name, SkPoint& p) override {
@ -87,6 +90,12 @@ public:
void visit(const char* name, SkString& s) override {
TryParse(get(name), s);
}
void visit(const char* name, int& i, const EnumStringMapping* map, int count) override {
SkString str;
if (TryParse(get(name), str)) {
i = StringToEnum(str.c_str(), map, count);
}
}
void visit(const char* name, SkPoint& p) override {
if (const skjson::ObjectValue* obj = get(name)) {

View File

@ -14,6 +14,8 @@
#include "SkString.h"
#include "SkTArray.h"
#include <string.h>
class SkFieldVisitor;
class SkRandom;
@ -148,6 +150,13 @@ public:
virtual void visit(const char*, SkPoint&) = 0;
virtual void visit(const char*, SkColor4f&) = 0;
// Accommodation for enums, where caller can supply a value <-> string map
struct EnumStringMapping {
int fValue;
const char* fName;
};
virtual void visit(const char*, int&, const EnumStringMapping*, int count) = 0;
// Specific virtual signature for SkCurve, to allow for heavily customized UI in SkGuiVisitor.
virtual void visit(const char* name, SkCurve& c) {
this->enterObject(name);
@ -233,6 +242,23 @@ protected:
}
};
static const char* EnumToString(int value, const EnumStringMapping* map, int count) {
for (int i = 0; i < count; ++i) {
if (map[i].fValue == value) {
return map[i].fName;
}
}
return nullptr;
}
static int StringToEnum(const char* str, const EnumStringMapping* map, int count) {
for (int i = 0; i < count; ++i) {
if (0 == strcmp(str, map[i].fName)) {
return map[i].fValue;
}
}
return -1;
}
virtual void enterObject(const char* name) = 0;
virtual void exitObject() = 0;

View File

@ -11,6 +11,12 @@
#include "SkParticleData.h"
#include "SkRandom.h"
constexpr SkFieldVisitor::EnumStringMapping gParticleFrameMapping[] = {
{ kWorld_ParticleFrame, "World" },
{ kLocal_ParticleFrame, "Local" },
{ kVelocity_ParticleFrame, "Velocity" },
};
void SkParticleAffector::apply(SkParticleUpdateParams& params, SkParticleState ps[], int count) {
if (fEnabled) {
this->onApply(params, ps, count);
@ -53,12 +59,12 @@ public:
void onApply(SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
for (int i = 0; i < count; ++i) {
float angle = fAngle.eval(ps[i].fAge, ps[i].fStableRandom);
float angle = fAngle.eval(ps[i].fAge, ps[i].fRandom);
SkScalar c_local, s_local = SkScalarSinCos(SkDegreesToRadians(angle), &c_local);
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);
float strength = fStrength.eval(ps[i].fAge, ps[i].fRandom);
SkVector force = { c * strength, s * strength };
if (fForce) {
ps[i].fVelocity.fLinear += force * params.fDeltaTime;
@ -71,7 +77,7 @@ public:
void visitFields(SkFieldVisitor* v) override {
SkParticleAffector::visitFields(v);
v->visit("Force", fForce);
v->visit("Frame", fFrame);
v->visit("Frame", fFrame, gParticleFrameMapping, SK_ARRAY_COUNT(gParticleFrameMapping));
v->visit("Angle", fAngle);
v->visit("Strength", fStrength);
}
@ -93,7 +99,7 @@ public:
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);
float strength = fStrength.eval(ps[i].fAge, ps[i].fRandom);
if (fForce) {
ps[i].fVelocity.fAngular += strength * params.fDeltaTime;
} else {
@ -155,7 +161,7 @@ public:
void onApply(SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
for (int i = 0; i < count; ++i) {
float angle = fAngle.eval(ps[i].fAge, ps[i].fStableRandom);
float angle = fAngle.eval(ps[i].fAge, ps[i].fRandom);
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,
@ -165,7 +171,7 @@ public:
void visitFields(SkFieldVisitor *v) override {
SkParticleAffector::visitFields(v);
v->visit("Frame", fFrame);
v->visit("Frame", fFrame, gParticleFrameMapping, SK_ARRAY_COUNT(gParticleFrameMapping));
v->visit("Angle", fAngle);
}
@ -182,7 +188,7 @@ public:
void onApply(SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
for (int i = 0; i < count; ++i) {
ps[i].fPose.fScale = fCurve.eval(ps[i].fAge, ps[i].fStableRandom);
ps[i].fPose.fScale = fCurve.eval(ps[i].fAge, ps[i].fRandom);
}
}
@ -203,7 +209,7 @@ public:
void onApply(SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
for (int i = 0; i < count; ++i) {
ps[i].fFrame = fCurve.eval(ps[i].fAge, ps[i].fStableRandom);
ps[i].fFrame = fCurve.eval(ps[i].fAge, ps[i].fRandom);
}
}
@ -225,7 +231,7 @@ public:
void onApply(SkParticleUpdateParams& params, SkParticleState ps[], int count) override {
for (int i = 0; i < count; ++i) {
ps[i].fColor = fCurve.eval(ps[i].fAge, ps[i].fStableRandom);
ps[i].fColor = fCurve.eval(ps[i].fAge, ps[i].fRandom);
}
}

View File

@ -68,7 +68,6 @@ void SkParticleEffect::update(const SkAnimTimer& timer) {
SkParticleUpdateParams updateParams;
updateParams.fDeltaTime = deltaTime;
updateParams.fRandom = &fRandom;
// Advance age for existing particles, and remove any that have reached their end of life
for (int i = 0; i < fCount; ++i) {
@ -106,7 +105,7 @@ void SkParticleEffect::update(const SkAnimTimer& timer) {
fParticles[fCount].fColor = { 1.0f, 1.0f, 1.0f, 1.0f };
fParticles[fCount].fFrame = 0.0f;
fParticles[fCount].fStableRandom = fStableRandoms[fCount] = fRandom;
fParticles[fCount].fRandom = fStableRandoms[fCount] = fRandom;
fCount++;
}
@ -123,7 +122,7 @@ void SkParticleEffect::update(const SkAnimTimer& timer) {
// Restore all stable random generators so update affectors get consistent behavior each frame
for (int i = 0; i < fCount; ++i) {
fParticles[i].fStableRandom = fStableRandoms[i];
fParticles[i].fRandom = fStableRandoms[i];
}
// Apply update rules

View File

@ -34,7 +34,7 @@
"Type": "SkLinearVelocityAffector",
"Enabled": true,
"Force": false,
"Frame": 0,
"Frame": "World",
"Angle": {
"XValues": [],
"Segments": [

View File

@ -36,7 +36,7 @@
"Type": "SkLinearVelocityAffector",
"Enabled": true,
"Force": false,
"Frame": 0,
"Frame": "World",
"Angle": {
"XValues": [],
"Segments": [
@ -80,7 +80,7 @@
"Type": "SkLinearVelocityAffector",
"Enabled": true,
"Force": true,
"Frame": 0,
"Frame": "World",
"Angle": {
"XValues": [],
"Segments": [
@ -121,7 +121,7 @@
{
"Type": "SkOrientationAffector",
"Enabled": true,
"Frame": 2,
"Frame": "Velocity",
"Angle": {
"XValues": [],
"Segments": [

View File

@ -34,7 +34,7 @@
"Type": "SkLinearVelocityAffector",
"Enabled": true,
"Force": false,
"Frame": 0,
"Frame": "World",
"Angle": {
"XValues": [],
"Segments": [

View File

@ -34,7 +34,7 @@
"Type": "SkLinearVelocityAffector",
"Enabled": true,
"Force": false,
"Frame": 0,
"Frame": "World",
"Angle": {
"XValues": [],
"Segments": [

View File

@ -34,7 +34,7 @@
"Type": "SkLinearVelocityAffector",
"Enabled": true,
"Force": false,
"Frame": 0,
"Frame": "World",
"Angle": {
"XValues": [],
"Segments": [
@ -78,7 +78,7 @@
"Type": "SkLinearVelocityAffector",
"Enabled": true,
"Force": true,
"Frame": 0,
"Frame": "World",
"Angle": {
"XValues": [],
"Segments": [

View File

@ -64,6 +64,19 @@ public:
&s);
}
}
void visit(const char* name, int& i, const EnumStringMapping* map, int count) override {
if (fTreeStack.back()) {
const char* curStr = EnumToString(i, map, count);
if (ImGui::BeginCombo(item(name), curStr ? curStr : "Unknown")) {
for (int j = 0; j < count; ++j) {
if (ImGui::Selectable(map[j].fName, i == map[j].fValue)) {
i = map[j].fValue;
}
}
ImGui::EndCombo();
}
}
}
void visit(const char* name, SkPoint& p) override {
if (fTreeStack.back()) {