1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci* Copyright 2019 Google LLC 3cb93a386Sopenharmony_ci* 4cb93a386Sopenharmony_ci* Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci* found in the LICENSE file. 6cb93a386Sopenharmony_ci*/ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#ifndef SkParticleEffect_DEFINED 9cb93a386Sopenharmony_ci#define SkParticleEffect_DEFINED 10cb93a386Sopenharmony_ci 11cb93a386Sopenharmony_ci#include "include/core/SkColor.h" 12cb93a386Sopenharmony_ci#include "include/core/SkPoint.h" 13cb93a386Sopenharmony_ci#include "include/core/SkRefCnt.h" 14cb93a386Sopenharmony_ci#include "include/core/SkString.h" 15cb93a386Sopenharmony_ci#include "include/private/SkTArray.h" 16cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h" 17cb93a386Sopenharmony_ci#include "modules/particles/include/SkParticleData.h" 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_ci#include <memory> 20cb93a386Sopenharmony_ci#include <vector> 21cb93a386Sopenharmony_ci 22cb93a386Sopenharmony_ciclass SkCanvas; 23cb93a386Sopenharmony_ciclass SkFieldVisitor; 24cb93a386Sopenharmony_ciclass SkParticleBinding; 25cb93a386Sopenharmony_ciclass SkParticleDrawable; 26cb93a386Sopenharmony_cistruct SkParticleProgram; 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_cinamespace skresources { 29cb93a386Sopenharmony_ci class ResourceProvider; 30cb93a386Sopenharmony_ci} // namespace skresources 31cb93a386Sopenharmony_ci 32cb93a386Sopenharmony_cinamespace SkSL { 33cb93a386Sopenharmony_ci class ExternalFunction; 34cb93a386Sopenharmony_ci struct UniformInfo; 35cb93a386Sopenharmony_ci} // namespace SkSL 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_ciclass SkParticleEffectParams : public SkRefCnt { 38cb93a386Sopenharmony_cipublic: 39cb93a386Sopenharmony_ci SkParticleEffectParams(); 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci // Maximum number of particles per instance of the effect 42cb93a386Sopenharmony_ci int fMaxCount; 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_ci // What is drawn for each particle? (Image, shape, sprite sheet, etc.) 45cb93a386Sopenharmony_ci // See SkParticleDrawable::Make* 46cb93a386Sopenharmony_ci sk_sp<SkParticleDrawable> fDrawable; 47cb93a386Sopenharmony_ci 48cb93a386Sopenharmony_ci // Particle behavior is driven by SkSL code. Effect functions get a mutable Effect struct: 49cb93a386Sopenharmony_ci // 50cb93a386Sopenharmony_ci // struct Effect { 51cb93a386Sopenharmony_ci // float age; // Normalized age of the effect 52cb93a386Sopenharmony_ci // float lifetime; // Effect's duration, in seconds - script should set this in effectSpawn 53cb93a386Sopenharmony_ci // int loop; // Number of loops that have elapsed (0 on initial spawn) 54cb93a386Sopenharmony_ci // float rate; // Rate to generate new particles (particles / second) 55cb93a386Sopenharmony_ci // int burst; // Number of particles to emit in a single update 56cb93a386Sopenharmony_ci // // Set during spawn to emit that many at once on each loop 57cb93a386Sopenharmony_ci // 58cb93a386Sopenharmony_ci // // Everything below this line controls the state of the effect, which is also the 59cb93a386Sopenharmony_ci // // default values for new particles. 60cb93a386Sopenharmony_ci // float2 pos = { 0, 0 }; // Local position 61cb93a386Sopenharmony_ci // float2 dir = { 0, -1 }; // Heading. Should be a normalized vector. 62cb93a386Sopenharmony_ci // float scale = 1; // Size, normalized relative to the drawable's native size 63cb93a386Sopenharmony_ci // float2 vel = { 0, 0 }; // Linear velocity, in (units / second) 64cb93a386Sopenharmony_ci // float spin = 0; // Angular velocity, in (radians / second) 65cb93a386Sopenharmony_ci // float4 color = { 1, 1, 1, 1 }; // RGBA color 66cb93a386Sopenharmony_ci // float frame = 0; // Normalized sprite index for multi-frame drawables 67cb93a386Sopenharmony_ci // float seed = 0; // Random value, used with rand() (see below) 68cb93a386Sopenharmony_ci // }; 69cb93a386Sopenharmony_ci // 70cb93a386Sopenharmony_ci // Particle functions get a mutable Particle struct, as well as a uniform copy of the current 71cb93a386Sopenharmony_ci // Effect, named 'effect'. 72cb93a386Sopenharmony_ci // 73cb93a386Sopenharmony_ci // struct Particle { 74cb93a386Sopenharmony_ci // float age; 75cb93a386Sopenharmony_ci // float lifetime; 76cb93a386Sopenharmony_ci // float2 pos; 77cb93a386Sopenharmony_ci // float2 dir; 78cb93a386Sopenharmony_ci // float scale; 79cb93a386Sopenharmony_ci // float2 vel; 80cb93a386Sopenharmony_ci // float spin; 81cb93a386Sopenharmony_ci // float4 color; 82cb93a386Sopenharmony_ci // float frame; 83cb93a386Sopenharmony_ci // float seed; 84cb93a386Sopenharmony_ci // }; 85cb93a386Sopenharmony_ci // 86cb93a386Sopenharmony_ci // All functions have access to a global function named 'rand'. It takes a float seed value, 87cb93a386Sopenharmony_ci // which it uses and updates (using a PRNG). It returns a random floating point value in [0, 1]. 88cb93a386Sopenharmony_ci // Typical usage is to pass the particle or effect's seed value to rand. 89cb93a386Sopenharmony_ci // For particle functions, the seed is rewound after each update, so calls to 'rand(p.seed)' 90cb93a386Sopenharmony_ci // will return consistent values from one update to the next. 91cb93a386Sopenharmony_ci // 92cb93a386Sopenharmony_ci // Finally, there is one global uniform values available, 'dt'. This is a floating point 93cb93a386Sopenharmony_ci // number of seconds that have elapsed since the last update. 94cb93a386Sopenharmony_ci // 95cb93a386Sopenharmony_ci // There are four functions that can be defined in fCode: 96cb93a386Sopenharmony_ci // 97cb93a386Sopenharmony_ci // 'void effectSpawn(inout Effect e)' is called when an instance of the effect is first 98cb93a386Sopenharmony_ci // created, and again at every loop point (if the effect is played with the looping flag). 99cb93a386Sopenharmony_ci // 100cb93a386Sopenharmony_ci // 'void effectUpdate(inout Effect e)' is called once per update to adjust properties of the 101cb93a386Sopenharmony_ci // effect (ie emitter). 102cb93a386Sopenharmony_ci // 103cb93a386Sopenharmony_ci // 'void spawn(inout Particle p)' is called once for each particle when it is first created, 104cb93a386Sopenharmony_ci // to set initial values. At a minimum, this should set 'lifetime' to the number of seconds 105cb93a386Sopenharmony_ci // that the particle will exist. Other parameters will get default values from the effect. 106cb93a386Sopenharmony_ci // 107cb93a386Sopenharmony_ci // 'void update(inout Particle p)' is called for each particle on every call to the running 108cb93a386Sopenharmony_ci // SkParticleEffect's update() method. It can animate any of the particle's values. Note that 109cb93a386Sopenharmony_ci // the 'lifetime' field has a different meaning in 'update', and should not be used or changed. 110cb93a386Sopenharmony_ci 111cb93a386Sopenharmony_ci SkString fCode; 112cb93a386Sopenharmony_ci 113cb93a386Sopenharmony_ci // External objects accessible by the effect's SkSL code. Each binding is a name and particular 114cb93a386Sopenharmony_ci // kind of object. See SkParticleBinding::Make* for details. 115cb93a386Sopenharmony_ci SkTArray<sk_sp<SkParticleBinding>> fBindings; 116cb93a386Sopenharmony_ci 117cb93a386Sopenharmony_ci void visitFields(SkFieldVisitor* v); 118cb93a386Sopenharmony_ci 119cb93a386Sopenharmony_ci // Load/compute cached resources 120cb93a386Sopenharmony_ci void prepare(const skresources::ResourceProvider*); 121cb93a386Sopenharmony_ci 122cb93a386Sopenharmony_ciprivate: 123cb93a386Sopenharmony_ci friend class SkParticleEffect; 124cb93a386Sopenharmony_ci 125cb93a386Sopenharmony_ci std::unique_ptr<SkParticleProgram> fProgram; 126cb93a386Sopenharmony_ci}; 127cb93a386Sopenharmony_ci 128cb93a386Sopenharmony_ciclass SkParticleEffect : public SkRefCnt { 129cb93a386Sopenharmony_cipublic: 130cb93a386Sopenharmony_ci SkParticleEffect(sk_sp<SkParticleEffectParams> params); 131cb93a386Sopenharmony_ci 132cb93a386Sopenharmony_ci // Start playing this effect, specifying initial values for the emitter's properties 133cb93a386Sopenharmony_ci void start(double now, bool looping, SkPoint position, SkVector heading, float scale, 134cb93a386Sopenharmony_ci SkVector velocity, float spin, SkColor4f color, float frame, float seed); 135cb93a386Sopenharmony_ci 136cb93a386Sopenharmony_ci // Start playing this effect, with default values for the emitter's properties 137cb93a386Sopenharmony_ci void start(double now, bool looping) { 138cb93a386Sopenharmony_ci this->start(now, looping, 139cb93a386Sopenharmony_ci { 0.0f, 0.0f }, // position 140cb93a386Sopenharmony_ci { 0.0f, -1.0f }, // heading 141cb93a386Sopenharmony_ci 1.0f, // scale 142cb93a386Sopenharmony_ci { 0.0f, 0.0f }, // velocity 143cb93a386Sopenharmony_ci 0.0f, // spin 144cb93a386Sopenharmony_ci { 1.0f, 1.0f, 1.0f, 1.0f }, // color 145cb93a386Sopenharmony_ci 0.0f, // sprite frame 146cb93a386Sopenharmony_ci 0.0f); // seed 147cb93a386Sopenharmony_ci } 148cb93a386Sopenharmony_ci 149cb93a386Sopenharmony_ci void update(double now); 150cb93a386Sopenharmony_ci void draw(SkCanvas* canvas); 151cb93a386Sopenharmony_ci 152cb93a386Sopenharmony_ci bool isAlive() const { return (fState.fAge >= 0 && fState.fAge <= 1); } 153cb93a386Sopenharmony_ci int getCount() const { return fCount; } 154cb93a386Sopenharmony_ci 155cb93a386Sopenharmony_ci float getRate() const { return fState.fRate; } 156cb93a386Sopenharmony_ci int getBurst() const { return fState.fBurst; } 157cb93a386Sopenharmony_ci SkPoint getPosition() const { return fState.fPosition; } 158cb93a386Sopenharmony_ci SkVector getHeading() const { return fState.fHeading; } 159cb93a386Sopenharmony_ci float getScale() const { return fState.fScale; } 160cb93a386Sopenharmony_ci SkVector getVelocity() const { return fState.fVelocity; } 161cb93a386Sopenharmony_ci float getSpin() const { return fState.fSpin; } 162cb93a386Sopenharmony_ci SkColor4f getColor() const { return fState.fColor; } 163cb93a386Sopenharmony_ci float getFrame() const { return fState.fFrame; } 164cb93a386Sopenharmony_ci 165cb93a386Sopenharmony_ci void setRate (float r) { fState.fRate = r; } 166cb93a386Sopenharmony_ci void setBurst (int b) { fState.fBurst = b; } 167cb93a386Sopenharmony_ci void setPosition(SkPoint p) { fState.fPosition = p; } 168cb93a386Sopenharmony_ci void setHeading (SkVector h) { fState.fHeading = h; } 169cb93a386Sopenharmony_ci void setScale (float s) { fState.fScale = s; } 170cb93a386Sopenharmony_ci void setVelocity(SkVector v) { fState.fVelocity = v; } 171cb93a386Sopenharmony_ci void setSpin (float s) { fState.fSpin = s; } 172cb93a386Sopenharmony_ci void setColor (SkColor4f c) { fState.fColor = c; } 173cb93a386Sopenharmony_ci void setFrame (float f) { fState.fFrame = f; } 174cb93a386Sopenharmony_ci 175cb93a386Sopenharmony_ci const SkSL::UniformInfo* uniformInfo() const; 176cb93a386Sopenharmony_ci float* uniformData() { return fUniforms.data(); } 177cb93a386Sopenharmony_ci 178cb93a386Sopenharmony_ci // Sets named uniform to the data in 'val'. 'count' must be equal to the total number of floats 179cb93a386Sopenharmony_ci // in the uniform (eg, the number of elements in a vector). Returns false if the uniform isn't 180cb93a386Sopenharmony_ci // found, or if count is incorrect. Returns true if the value is changed successfully. 181cb93a386Sopenharmony_ci bool setUniform(const char* name, const float* val, int count); 182cb93a386Sopenharmony_ci 183cb93a386Sopenharmony_ci static void RegisterParticleTypes(); 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_ciprivate: 186cb93a386Sopenharmony_ci void setCapacity(int capacity); 187cb93a386Sopenharmony_ci void updateStorage(); 188cb93a386Sopenharmony_ci 189cb93a386Sopenharmony_ci // Helpers to break down update 190cb93a386Sopenharmony_ci void advanceTime(double now); 191cb93a386Sopenharmony_ci 192cb93a386Sopenharmony_ci enum class EntryPoint { 193cb93a386Sopenharmony_ci kSpawn, 194cb93a386Sopenharmony_ci kUpdate, 195cb93a386Sopenharmony_ci }; 196cb93a386Sopenharmony_ci 197cb93a386Sopenharmony_ci void runEffectScript(EntryPoint entryPoint); 198cb93a386Sopenharmony_ci void runParticleScript(EntryPoint entryPoint, int start, int count); 199cb93a386Sopenharmony_ci 200cb93a386Sopenharmony_ci sk_sp<SkParticleEffectParams> fParams; 201cb93a386Sopenharmony_ci 202cb93a386Sopenharmony_ci bool fLooping; 203cb93a386Sopenharmony_ci int fCount; 204cb93a386Sopenharmony_ci double fLastTime; 205cb93a386Sopenharmony_ci float fSpawnRemainder; 206cb93a386Sopenharmony_ci 207cb93a386Sopenharmony_ci // C++ version of the SkSL Effect struct. This is the inout parameter to per-effect scripts, 208cb93a386Sopenharmony_ci // and provided as a uniform (named 'effect') to all scripts. 209cb93a386Sopenharmony_ci struct EffectState { 210cb93a386Sopenharmony_ci float fAge; 211cb93a386Sopenharmony_ci float fLifetime; 212cb93a386Sopenharmony_ci int fLoopCount; 213cb93a386Sopenharmony_ci float fRate; 214cb93a386Sopenharmony_ci int fBurst; 215cb93a386Sopenharmony_ci 216cb93a386Sopenharmony_ci // Properties that determine default values for new particles 217cb93a386Sopenharmony_ci SkPoint fPosition; 218cb93a386Sopenharmony_ci SkVector fHeading; 219cb93a386Sopenharmony_ci float fScale; 220cb93a386Sopenharmony_ci SkVector fVelocity; 221cb93a386Sopenharmony_ci float fSpin; 222cb93a386Sopenharmony_ci SkColor4f fColor; 223cb93a386Sopenharmony_ci float fFrame; 224cb93a386Sopenharmony_ci float fRandom; 225cb93a386Sopenharmony_ci }; 226cb93a386Sopenharmony_ci EffectState fState; 227cb93a386Sopenharmony_ci 228cb93a386Sopenharmony_ci SkParticles fParticles; 229cb93a386Sopenharmony_ci SkAutoTMalloc<float> fStableRandoms; 230cb93a386Sopenharmony_ci 231cb93a386Sopenharmony_ci // Cached 232cb93a386Sopenharmony_ci int fCapacity = 0; 233cb93a386Sopenharmony_ci SkTArray<float, true> fUniforms; 234cb93a386Sopenharmony_ci 235cb93a386Sopenharmony_ci friend struct SkParticleProgram; 236cb93a386Sopenharmony_ci}; 237cb93a386Sopenharmony_ci 238cb93a386Sopenharmony_ci#endif // SkParticleEffect_DEFINED 239