Fix a couple minor bugs in particle code

- Copy effect state to particle uniforms before each script, so changes
  from spawn or update are visible.
- Guard path binding against out of range access
- New effect that actually stresses both of these conditions

Change-Id: Ice6112793099e515438af8bb863e9e1bf03d08b1
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/249125
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Osman 2019-10-17 10:28:46 -04:00 committed by Skia Commit-Bot
parent 93e853bf2b
commit e8bcc56951
3 changed files with 47 additions and 3 deletions

View File

@ -100,11 +100,12 @@ public:
void call(int index, float* arguments, float* outReturn) override { void call(int index, float* arguments, float* outReturn) override {
SkScalar len = fPath->fTotalLength * arguments[0]; SkScalar len = fPath->fTotalLength * arguments[0];
int idx = 0; int idx = 0;
while (idx < fPath->fContours.count() && len > fPath->fContours[idx]->length()) { while (idx < fPath->fContours.count() - 1 && len > fPath->fContours[idx]->length()) {
len -= fPath->fContours[idx++]->length(); len -= fPath->fContours[idx++]->length();
} }
SkVector localXAxis; SkVector localXAxis;
if (!fPath->fContours[idx]->getPosTan(len, (SkPoint*)outReturn, &localXAxis)) { if (idx >= fPath->fContours.count() ||
!fPath->fContours[idx]->getPosTan(len, (SkPoint*)outReturn, &localXAxis)) {
outReturn[0] = outReturn[1] = 0.0f; outReturn[0] = outReturn[1] = 0.0f;
localXAxis = { 1, 0 }; localXAxis = { 1, 0 };
} }

View File

@ -278,6 +278,7 @@ void SkParticleEffect::runParticleScript(double now, const char* entry, int star
value->setRandom(randomBase); value->setRandom(randomBase);
value->setEffect(this); value->setEffect(this);
} }
memcpy(&fParticleUniforms[1], &fState.fAge, sizeof(EffectState));
SkAssertResult(byteCode->runStriped(fun, count, args, SkParticles::kNumChannels, SkAssertResult(byteCode->runStriped(fun, count, args, SkParticles::kNumChannels,
nullptr, 0, nullptr, 0,
fParticleUniforms.data(), fParticleUniforms.data(),
@ -321,7 +322,6 @@ void SkParticleEffect::advanceTime(double now) {
SkASSERT(!this->particleCode() || this->particleCode()->getUniformLocation("effect.age") == 1); SkASSERT(!this->particleCode() || this->particleCode()->getUniformLocation("effect.age") == 1);
fEffectUniforms[0] = deltaTime; fEffectUniforms[0] = deltaTime;
fParticleUniforms[0] = deltaTime; fParticleUniforms[0] = deltaTime;
memcpy(&fParticleUniforms[1], &fState.fAge, sizeof(EffectState));
// Is this the first update after calling start()? // Is this the first update after calling start()?
// Run 'effectSpawn' to set initial emitter properties. // Run 'effectSpawn' to set initial emitter properties.

View File

@ -0,0 +1,43 @@
{
"MaxCount": 4000,
"Drawable": {
"Type": "SkCircleDrawable",
"Radius": 2
},
"EffectCode": [
"void effectSpawn(inout Effect effect) {",
" effect.lifetime = 4;",
"}",
"",
"void effectUpdate(inout Effect effect) {",
" effect.color.r = 0;",
" effect.color.g = 1 - effect.age;",
" effect.color.b = effect.age;",
"",
" effect.rate = effect.age < 0.75 ? 800 : 0;",
"}",
""
],
"Code": [
"uniform float2 mouse_pos;",
"",
"void spawn(inout Particle p) {",
" p.lifetime = 4;",
" p.pos = mouse_pos;",
" p.frame = effect.age / 0.75 + mix(-0.05, 0.05, rand);",
"}",
"",
"void update(inout Particle p) {",
" p.pos = mix(p.pos, text(p.frame).xy, 0.05);",
"}",
""
],
"Bindings": [
{
"Type": "SkTextBinding",
"Name": "text",
"Text": "HELLO WORLD",
"FontSize": 96
}
]
}