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