blob: 877a802db62e59c6b6b2e2b6be578ad18f446992 [file] [log] [blame]
Brian Osman7c979f52019-02-12 13:27:51 -05001/*
2* Copyright 2019 Google LLC
3*
4* Use of this source code is governed by a BSD-style license that can be
5* found in the LICENSE file.
6*/
7
8#ifndef SkParticleEffect_DEFINED
9#define SkParticleEffect_DEFINED
10
Brian Osmand46cb972019-09-12 16:25:52 -040011#include "include/core/SkColor.h"
12#include "include/core/SkPoint.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "include/core/SkRefCnt.h"
Brian Osmanfe491632019-07-25 15:14:50 -040014#include "include/core/SkString.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "include/private/SkTArray.h"
Brian Osmanfe491632019-07-25 15:14:50 -040016#include "include/private/SkTemplates.h"
Brian Osmanfe491632019-07-25 15:14:50 -040017#include "modules/particles/include/SkParticleData.h"
Brian Osmanfe491632019-07-25 15:14:50 -040018
19#include <memory>
Brian Osman32d53552020-09-23 13:55:20 -040020#include <vector>
Brian Osman7c979f52019-02-12 13:27:51 -050021
Brian Osman7c979f52019-02-12 13:27:51 -050022class SkCanvas;
Brian Osman2aa85df2019-08-30 10:59:47 -040023class SkFieldVisitor;
24class SkParticleBinding;
Brian Osman543d2e22019-02-15 14:29:38 -050025class SkParticleDrawable;
Brian Osmane89d8ea2021-01-20 14:01:30 -050026struct SkParticleProgram;
Brian Osmanfe491632019-07-25 15:14:50 -040027
Brian Osmand12f2782019-11-27 10:34:18 -050028namespace skresources {
29 class ResourceProvider;
John Stilesa6841be2020-08-06 14:11:56 -040030} // namespace skresources
Brian Osmand12f2782019-11-27 10:34:18 -050031
Brian Osmanfe491632019-07-25 15:14:50 -040032namespace SkSL {
Brian Osmanbe0b3b72021-01-06 14:27:35 -050033 class ExternalFunction;
Brian Osmane89d8ea2021-01-20 14:01:30 -050034 struct UniformInfo;
John Stilesa6841be2020-08-06 14:11:56 -040035} // namespace SkSL
Brian Osmanfe491632019-07-25 15:14:50 -040036
Brian Osman7c979f52019-02-12 13:27:51 -050037class SkParticleEffectParams : public SkRefCnt {
38public:
Brian Osmanfe491632019-07-25 15:14:50 -040039 SkParticleEffectParams();
40
Brian Osmand46cb972019-09-12 16:25:52 -040041 // Maximum number of particles per instance of the effect
42 int fMaxCount;
Brian Osman7c979f52019-02-12 13:27:51 -050043
Brian Osman3da607e2019-07-26 15:11:46 -040044 // What is drawn for each particle? (Image, shape, sprite sheet, etc.)
45 // See SkParticleDrawable::Make*
Brian Osman543d2e22019-02-15 14:29:38 -050046 sk_sp<SkParticleDrawable> fDrawable;
Brian Osman7c979f52019-02-12 13:27:51 -050047
Brian Osman360035c2021-02-03 10:52:05 -050048 // Particle behavior is driven by SkSL code. Effect functions get a mutable Effect struct:
Brian Osman3da607e2019-07-26 15:11:46 -040049 //
Brian Osmand46cb972019-09-12 16:25:52 -040050 // struct Effect {
Brian Osmand1846d82019-09-17 13:32:32 -040051 // float age; // Normalized age of the effect
52 // float lifetime; // Effect's duration, in seconds - script should set this in effectSpawn
53 // int loop; // Number of loops that have elapsed (0 on initial spawn)
54 // float rate; // Rate to generate new particles (particles / second)
55 // int burst; // Number of particles to emit in a single update
56 // // Set during spawn to emit that many at once on each loop
Brian Osmand46cb972019-09-12 16:25:52 -040057 //
58 // // Everything below this line controls the state of the effect, which is also the
59 // // default values for new particles.
60 // float2 pos = { 0, 0 }; // Local position
Brian Osman3da607e2019-07-26 15:11:46 -040061 // float2 dir = { 0, -1 }; // Heading. Should be a normalized vector.
62 // float scale = 1; // Size, normalized relative to the drawable's native size
63 // float2 vel = { 0, 0 }; // Linear velocity, in (units / second)
64 // float spin = 0; // Angular velocity, in (radians / second)
65 // float4 color = { 1, 1, 1, 1 }; // RGBA color
66 // float frame = 0; // Normalized sprite index for multi-frame drawables
Brian Osmane11c4382020-12-22 16:15:28 -050067 // float seed = 0; // Random value, used with rand() (see below)
Brian Osman3da607e2019-07-26 15:11:46 -040068 // };
69 //
Brian Osman360035c2021-02-03 10:52:05 -050070 // Particle functions get a mutable Particle struct, as well as a uniform copy of the current
71 // Effect, named 'effect'.
Brian Osman3da607e2019-07-26 15:11:46 -040072 //
Brian Osmand46cb972019-09-12 16:25:52 -040073 // struct Particle {
74 // float age;
75 // float lifetime;
76 // float2 pos;
77 // float2 dir;
78 // float scale;
79 // float2 vel;
80 // float spin;
81 // float4 color;
82 // float frame;
Brian Osmane11c4382020-12-22 16:15:28 -050083 // float seed;
Brian Osmand46cb972019-09-12 16:25:52 -040084 // };
85 //
Brian Osmane11c4382020-12-22 16:15:28 -050086 // All functions have access to a global function named 'rand'. It takes a float seed value,
87 // which it uses and updates (using a PRNG). It returns a random floating point value in [0, 1].
88 // Typical usage is to pass the particle or effect's seed value to rand.
Brian Osman95c26ef2020-02-10 13:45:22 -050089 // For particle functions, the seed is rewound after each update, so calls to 'rand(p.seed)'
90 // will return consistent values from one update to the next.
Brian Osmand46cb972019-09-12 16:25:52 -040091 //
92 // Finally, there is one global uniform values available, 'dt'. This is a floating point
93 // number of seconds that have elapsed since the last update.
94 //
Brian Osman360035c2021-02-03 10:52:05 -050095 // There are four functions that can be defined in fCode:
Brian Osmand46cb972019-09-12 16:25:52 -040096 //
97 // 'void effectSpawn(inout Effect e)' is called when an instance of the effect is first
98 // created, and again at every loop point (if the effect is played with the looping flag).
99 //
100 // 'void effectUpdate(inout Effect e)' is called once per update to adjust properties of the
101 // effect (ie emitter).
102 //
Brian Osman3da607e2019-07-26 15:11:46 -0400103 // 'void spawn(inout Particle p)' is called once for each particle when it is first created,
104 // to set initial values. At a minimum, this should set 'lifetime' to the number of seconds
Brian Osmand1846d82019-09-17 13:32:32 -0400105 // that the particle will exist. Other parameters will get default values from the effect.
Brian Osman3da607e2019-07-26 15:11:46 -0400106 //
107 // 'void update(inout Particle p)' is called for each particle on every call to the running
108 // SkParticleEffect's update() method. It can animate any of the particle's values. Note that
109 // the 'lifetime' field has a different meaning in 'update', and should not be used or changed.
Brian Osmand46cb972019-09-12 16:25:52 -0400110
Brian Osman360035c2021-02-03 10:52:05 -0500111 SkString fCode;
Brian Osmanfe491632019-07-25 15:14:50 -0400112
Brian Osman3da607e2019-07-26 15:11:46 -0400113 // External objects accessible by the effect's SkSL code. Each binding is a name and particular
114 // kind of object. See SkParticleBinding::Make* for details.
Brian Osmanfe491632019-07-25 15:14:50 -0400115 SkTArray<sk_sp<SkParticleBinding>> fBindings;
Brian Osman7c979f52019-02-12 13:27:51 -0500116
117 void visitFields(SkFieldVisitor* v);
Brian Osmanfe491632019-07-25 15:14:50 -0400118
Brian Osman9dac0d82019-12-02 16:52:51 -0500119 // Load/compute cached resources
120 void prepare(const skresources::ResourceProvider*);
121
Brian Osmanfe491632019-07-25 15:14:50 -0400122private:
123 friend class SkParticleEffect;
124
Brian Osman38316892021-01-29 14:32:09 -0500125 std::unique_ptr<SkParticleProgram> fProgram;
Brian Osman7c979f52019-02-12 13:27:51 -0500126};
127
128class SkParticleEffect : public SkRefCnt {
129public:
Brian Osman95c26ef2020-02-10 13:45:22 -0500130 SkParticleEffect(sk_sp<SkParticleEffectParams> params);
Brian Osman7c979f52019-02-12 13:27:51 -0500131
Brian Osman9a8b8462019-09-19 10:06:36 -0400132 // Start playing this effect, specifying initial values for the emitter's properties
133 void start(double now, bool looping, SkPoint position, SkVector heading, float scale,
Brian Osmane11c4382020-12-22 16:15:28 -0500134 SkVector velocity, float spin, SkColor4f color, float frame, float seed);
Brian Osman9a8b8462019-09-19 10:06:36 -0400135
136 // Start playing this effect, with default values for the emitter's properties
137 void start(double now, bool looping) {
138 this->start(now, looping,
139 { 0.0f, 0.0f }, // position
140 { 0.0f, -1.0f }, // heading
141 1.0f, // scale
142 { 0.0f, 0.0f }, // velocity
143 0.0f, // spin
144 { 1.0f, 1.0f, 1.0f, 1.0f }, // color
Brian Osman559ffe42019-09-25 11:24:50 -0400145 0.0f, // sprite frame
Brian Osmane11c4382020-12-22 16:15:28 -0500146 0.0f); // seed
Brian Osman9a8b8462019-09-19 10:06:36 -0400147 }
148
Kevin Lubick269fe892019-03-06 09:32:55 -0500149 void update(double now);
Brian Osman7c979f52019-02-12 13:27:51 -0500150 void draw(SkCanvas* canvas);
151
Brian Osmanace3f292021-01-12 13:18:52 -0500152 bool isAlive() const { return (fState.fAge >= 0 && fState.fAge <= 1); }
Brian Osmanb77d5022019-03-06 11:08:48 -0500153 int getCount() const { return fCount; }
Brian Osman7c979f52019-02-12 13:27:51 -0500154
Brian Osmandf182962019-10-15 10:27:59 -0400155 float getRate() const { return fState.fRate; }
156 int getBurst() const { return fState.fBurst; }
157 SkPoint getPosition() const { return fState.fPosition; }
158 SkVector getHeading() const { return fState.fHeading; }
159 float getScale() const { return fState.fScale; }
160 SkVector getVelocity() const { return fState.fVelocity; }
161 float getSpin() const { return fState.fSpin; }
162 SkColor4f getColor() const { return fState.fColor; }
163 float getFrame() const { return fState.fFrame; }
Brian Osmandf182962019-10-15 10:27:59 -0400164
165 void setRate (float r) { fState.fRate = r; }
166 void setBurst (int b) { fState.fBurst = b; }
167 void setPosition(SkPoint p) { fState.fPosition = p; }
168 void setHeading (SkVector h) { fState.fHeading = h; }
169 void setScale (float s) { fState.fScale = s; }
170 void setVelocity(SkVector v) { fState.fVelocity = v; }
171 void setSpin (float s) { fState.fSpin = s; }
172 void setColor (SkColor4f c) { fState.fColor = c; }
173 void setFrame (float f) { fState.fFrame = f; }
Brian Osmandf182962019-10-15 10:27:59 -0400174
Brian Osman38316892021-01-29 14:32:09 -0500175 const SkSL::UniformInfo* uniformInfo() const;
176 float* uniformData() { return fUniforms.data(); }
Brian Osman5b431132019-10-15 16:41:18 -0400177
Brian Osman4d76f632021-01-21 11:47:12 -0500178 // Sets named uniform to the data in 'val'. 'count' must be equal to the total number of floats
179 // in the uniform (eg, the number of elements in a vector). Returns false if the uniform isn't
180 // found, or if count is incorrect. Returns true if the value is changed successfully.
181 bool setUniform(const char* name, const float* val, int count);
182
Brian Osman2aa85df2019-08-30 10:59:47 -0400183 static void RegisterParticleTypes();
184
Brian Osman7c979f52019-02-12 13:27:51 -0500185private:
186 void setCapacity(int capacity);
Brian Osman4d76f632021-01-21 11:47:12 -0500187 void updateStorage();
Brian Osman7c979f52019-02-12 13:27:51 -0500188
Brian Osman9a8b8462019-09-19 10:06:36 -0400189 // Helpers to break down update
190 void advanceTime(double now);
191
Brian Osmane89d8ea2021-01-20 14:01:30 -0500192 enum class EntryPoint {
193 kSpawn,
194 kUpdate,
195 };
196
197 void runEffectScript(EntryPoint entryPoint);
198 void runParticleScript(EntryPoint entryPoint, int start, int count);
Brian Osman9a8b8462019-09-19 10:06:36 -0400199
Brian Osman360035c2021-02-03 10:52:05 -0500200 sk_sp<SkParticleEffectParams> fParams;
Brian Osman7c979f52019-02-12 13:27:51 -0500201
Brian Osman5c1f8eb2019-02-14 14:49:55 -0500202 bool fLooping;
Brian Osman7c979f52019-02-12 13:27:51 -0500203 int fCount;
204 double fLastTime;
205 float fSpawnRemainder;
206
Brian Osman5b431132019-10-15 16:41:18 -0400207 // C++ version of the SkSL Effect struct. This is the inout parameter to per-effect scripts,
Brian Osman360035c2021-02-03 10:52:05 -0500208 // and provided as a uniform (named 'effect') to all scripts.
Brian Osmand46cb972019-09-12 16:25:52 -0400209 struct EffectState {
Brian Osmand46cb972019-09-12 16:25:52 -0400210 float fAge;
211 float fLifetime;
212 int fLoopCount;
213 float fRate;
214 int fBurst;
215
216 // Properties that determine default values for new particles
217 SkPoint fPosition;
218 SkVector fHeading;
219 float fScale;
220 SkVector fVelocity;
221 float fSpin;
222 SkColor4f fColor;
223 float fFrame;
Brian Osmane11c4382020-12-22 16:15:28 -0500224 float fRandom;
Brian Osmand46cb972019-09-12 16:25:52 -0400225 };
226 EffectState fState;
227
Brian Osman95c26ef2020-02-10 13:45:22 -0500228 SkParticles fParticles;
229 SkAutoTMalloc<float> fStableRandoms;
Brian Osman7c979f52019-02-12 13:27:51 -0500230
231 // Cached
Brian Osman4d76f632021-01-21 11:47:12 -0500232 int fCapacity = 0;
Brian Osman38316892021-01-29 14:32:09 -0500233 SkTArray<float, true> fUniforms;
234
235 friend struct SkParticleProgram;
Brian Osman7c979f52019-02-12 13:27:51 -0500236};
237
238#endif // SkParticleEffect_DEFINED