Add accessors to get/set SkParticleEffect fields
Simplify burst handling. Scripts should just add to burst (if they want to handle programmatic bursting, as well). Update most effects to handle dynamic updates to position better, and add a sample effect meant to be used with mouse tracking. Change-Id: Ia302e1d04e62e2b07974807c44067786cc10a8ad Bug: skia:9513 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/248798 Commit-Queue: Brian Osman <brianosman@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
parent
f22c57ddcc
commit
df18296f98
@ -156,6 +156,28 @@ public:
|
||||
}
|
||||
int getCount() const { return fCount; }
|
||||
|
||||
float getRate() const { return fState.fRate; }
|
||||
int getBurst() const { return fState.fBurst; }
|
||||
SkPoint getPosition() const { return fState.fPosition; }
|
||||
SkVector getHeading() const { return fState.fHeading; }
|
||||
float getScale() const { return fState.fScale; }
|
||||
SkVector getVelocity() const { return fState.fVelocity; }
|
||||
float getSpin() const { return fState.fSpin; }
|
||||
SkColor4f getColor() const { return fState.fColor; }
|
||||
float getFrame() const { return fState.fFrame; }
|
||||
uint32_t getFlags() const { return fState.fFlags; }
|
||||
|
||||
void setRate (float r) { fState.fRate = r; }
|
||||
void setBurst (int b) { fState.fBurst = b; }
|
||||
void setPosition(SkPoint p) { fState.fPosition = p; }
|
||||
void setHeading (SkVector h) { fState.fHeading = h; }
|
||||
void setScale (float s) { fState.fScale = s; }
|
||||
void setVelocity(SkVector v) { fState.fVelocity = v; }
|
||||
void setSpin (float s) { fState.fSpin = s; }
|
||||
void setColor (SkColor4f c) { fState.fColor = c; }
|
||||
void setFrame (float f) { fState.fFrame = f; }
|
||||
void setFlags (uint32_t f) { fState.fFlags = f; }
|
||||
|
||||
static void RegisterParticleTypes();
|
||||
|
||||
private:
|
||||
@ -165,7 +187,7 @@ private:
|
||||
void advanceTime(double now);
|
||||
|
||||
void processEffectSpawnRequests(double now);
|
||||
int runEffectScript(double now, const char* entry);
|
||||
void runEffectScript(double now, const char* entry);
|
||||
|
||||
void processParticleSpawnRequests(double now, int start);
|
||||
void runParticleScript(double now, const char* entry, int start, int count);
|
||||
|
@ -226,8 +226,7 @@ void SkParticleEffect::processEffectSpawnRequests(double now) {
|
||||
fSpawnRequests.reset();
|
||||
}
|
||||
|
||||
int SkParticleEffect::runEffectScript(double now, const char* entry) {
|
||||
fState.fBurst = 0;
|
||||
void SkParticleEffect::runEffectScript(double now, const char* entry) {
|
||||
if (const auto& byteCode = fParams->fEffectProgram.fByteCode) {
|
||||
if (auto fun = byteCode->getFunction(entry)) {
|
||||
for (const auto& value : fParams->fEffectProgram.fExternalValues) {
|
||||
@ -241,7 +240,6 @@ int SkParticleEffect::runEffectScript(double now, const char* entry) {
|
||||
this->processEffectSpawnRequests(now);
|
||||
}
|
||||
}
|
||||
return fState.fBurst;
|
||||
}
|
||||
|
||||
void SkParticleEffect::processParticleSpawnRequests(double now, int start) {
|
||||
@ -304,24 +302,22 @@ void SkParticleEffect::advanceTime(double now) {
|
||||
this->setCapacity(fParams->fMaxCount);
|
||||
}
|
||||
|
||||
int burstCount = 0;
|
||||
|
||||
// Is this the first update after calling start()?
|
||||
// Run 'effectSpawn' to set initial emitter properties.
|
||||
if (fState.fAge == 0.0f && fState.fLoopCount == 0) {
|
||||
burstCount += this->runEffectScript(now, "effectSpawn");
|
||||
this->runEffectScript(now, "effectSpawn");
|
||||
}
|
||||
|
||||
fState.fAge += fState.fDeltaTime / fState.fLifetime;
|
||||
if (fState.fAge > 1) {
|
||||
// We always run effectDeath when age crosses 1, whether we're looping or actually dying
|
||||
burstCount += this->runEffectScript(now, "effectDeath");
|
||||
this->runEffectScript(now, "effectDeath");
|
||||
|
||||
if (fLooping) {
|
||||
// If we looped, then run effectSpawn again (with the updated loop count)
|
||||
fState.fLoopCount += sk_float_floor2int(fState.fAge);
|
||||
fState.fAge = fmodf(fState.fAge, 1.0f);
|
||||
burstCount += this->runEffectScript(now, "effectSpawn");
|
||||
this->runEffectScript(now, "effectSpawn");
|
||||
} else {
|
||||
// Effect is dead if we've reached the end (and are not looping)
|
||||
return;
|
||||
@ -349,7 +345,7 @@ void SkParticleEffect::advanceTime(double now) {
|
||||
this->runParticleScript(now, "death", fCount, numDyingParticles);
|
||||
|
||||
// Run 'effectUpdate' to adjust emitter properties
|
||||
burstCount += this->runEffectScript(now, "effectUpdate");
|
||||
this->runEffectScript(now, "effectUpdate");
|
||||
|
||||
// Do integration of effect position and orientation
|
||||
{
|
||||
@ -362,10 +358,11 @@ void SkParticleEffect::advanceTime(double now) {
|
||||
}
|
||||
|
||||
// Spawn new particles
|
||||
float desired = fState.fRate * fState.fDeltaTime + fSpawnRemainder;
|
||||
float desired = fState.fRate * fState.fDeltaTime + fSpawnRemainder + fState.fBurst;
|
||||
fState.fBurst = 0;
|
||||
int numToSpawn = sk_float_round2int(desired);
|
||||
fSpawnRemainder = desired - numToSpawn;
|
||||
numToSpawn = SkTPin(numToSpawn + burstCount, 0, fParams->fMaxCount - fCount);
|
||||
numToSpawn = SkTPin(numToSpawn, 0, fParams->fMaxCount - fCount);
|
||||
if (numToSpawn) {
|
||||
const int spawnBase = fCount;
|
||||
|
||||
|
28
resources/particles/mouse_trail.json
Normal file
28
resources/particles/mouse_trail.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"MaxCount": 2000,
|
||||
"Drawable": {
|
||||
"Type": "SkCircleDrawable",
|
||||
"Radius": 4
|
||||
},
|
||||
"EffectCode": [
|
||||
"void effectSpawn(inout Effect effect) {",
|
||||
" effect.rate = 800;",
|
||||
"}",
|
||||
""
|
||||
],
|
||||
"Code": [
|
||||
"void spawn(inout Particle p) {",
|
||||
" p.lifetime = 2 + rand;",
|
||||
" float a = radians(rand * 360);",
|
||||
" p.vel = float2(cos(a), sin(a)) * mix(5, 15, rand);",
|
||||
" p.scale = mix(0.25, 0.75, rand);",
|
||||
"}",
|
||||
"",
|
||||
"void update(inout Particle p) {",
|
||||
" p.color.r = p.age;",
|
||||
" p.color.g = 1 - p.age;",
|
||||
"}",
|
||||
""
|
||||
],
|
||||
"Bindings": []
|
||||
}
|
@ -10,12 +10,12 @@
|
||||
"}",
|
||||
"",
|
||||
"void effectUpdate(inout Effect effect) {",
|
||||
" effect.pos.y = sin(effect.age * 6.28) * 40;",
|
||||
"}",
|
||||
""
|
||||
],
|
||||
"Code": [
|
||||
"void spawn(inout Particle p) {",
|
||||
" p.pos.y += sin(effect.age * 6.28) * 40;",
|
||||
" p.lifetime = 2 + (rand * 2);",
|
||||
" p.vel.x = (30 * rand) + 50;",
|
||||
" p.vel.y = (20 * rand) - 10;",
|
||||
|
@ -25,8 +25,9 @@
|
||||
"",
|
||||
"void spawn(inout Particle p) {",
|
||||
" p.lifetime = 1.0 + rand * 2.0;",
|
||||
" p.pos = circle() * 60;",
|
||||
" p.vel = p.pos / 3;",
|
||||
" float2 ofs = circle() * 60;",
|
||||
" p.pos += ofs;",
|
||||
" p.vel = ofs / 3;",
|
||||
"}",
|
||||
"",
|
||||
"void update(inout Particle p) {",
|
||||
|
@ -17,7 +17,7 @@
|
||||
" float s = mix(10, 30, rand);",
|
||||
" p.vel.x = cos(a) * s;",
|
||||
" p.vel.y = sin(a) * s;",
|
||||
" p.pos = text(rand).xy;",
|
||||
" p.pos += text(rand).xy;",
|
||||
"}",
|
||||
"",
|
||||
"void update(inout Particle p) {",
|
||||
|
@ -14,8 +14,9 @@
|
||||
"void spawn(inout Particle p) {",
|
||||
" p.lifetime = 6;",
|
||||
" float a = radians(rand * 360);",
|
||||
" p.pos = float2(cos(a), sin(a)) * 40;",
|
||||
" p.vel = p.pos;",
|
||||
" float2 ofs = float2(cos(a), sin(a)) * 40;",
|
||||
" p.pos += ofs;",
|
||||
" p.vel = ofs;",
|
||||
" p.scale = 0.5;",
|
||||
"}",
|
||||
""
|
||||
|
@ -23,11 +23,11 @@
|
||||
"",
|
||||
"void spawn(inout Particle p) {",
|
||||
" p.lifetime = 30;",
|
||||
" p.pos = circle() * 40;",
|
||||
" p.pos += circle() * 40;",
|
||||
"}",
|
||||
"",
|
||||
"void update(inout Particle p) {",
|
||||
" p.vel += normalize(p.pos) * dt * 10;",
|
||||
" p.vel += normalize(p.pos - effect.pos) * dt * 10;",
|
||||
" p.scale = mix(0.25, 3, p.age);",
|
||||
"}",
|
||||
""
|
||||
|
@ -281,7 +281,7 @@ void ParticlesSlide::draw(SkCanvas* canvas) {
|
||||
if (fAnimated && ImGui::Button("Play")) {
|
||||
sk_sp<SkParticleEffect> effect(new SkParticleEffect(fLoaded[i].fParams, fRandom));
|
||||
effect->start(fAnimationTime, looped);
|
||||
fRunning.push_back({ fPlayPosition, fLoaded[i].fName, effect });
|
||||
fRunning.push_back({ fPlayPosition, fLoaded[i].fName, effect, false });
|
||||
fRandom.nextU();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
@ -302,10 +302,17 @@ void ParticlesSlide::draw(SkCanvas* canvas) {
|
||||
if (ImGui::Begin("Running")) {
|
||||
for (int i = 0; i < fRunning.count(); ++i) {
|
||||
ImGui::PushID(i);
|
||||
ImGui::Checkbox("##Track", &fRunning[i].fTrackMouse);
|
||||
ImGui::SameLine();
|
||||
bool remove = ImGui::Button("X") || !fRunning[i].fEffect->isAlive();
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("%4g, %4g %5d %s", fRunning[i].fPosition.fX, fRunning[i].fPosition.fY,
|
||||
fRunning[i].fEffect->getCount(), fRunning[i].fName.c_str());
|
||||
if (fRunning[i].fTrackMouse) {
|
||||
fRunning[i].fEffect->setPosition({ ImGui::GetMousePos().x,
|
||||
ImGui::GetMousePos().y });
|
||||
fRunning[i].fPosition.set(0, 0);
|
||||
}
|
||||
if (remove) {
|
||||
fRunning.removeShuffle(i);
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ private:
|
||||
SkPoint fPosition;
|
||||
SkString fName;
|
||||
sk_sp<SkParticleEffect> fEffect;
|
||||
bool fTrackMouse;
|
||||
};
|
||||
SkTArray<RunningEffect> fRunning;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user