blob: 7cecc5c5f5803d1b53e07a7c1e92cce2c63c1dd5 [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 Osmand46cb972019-09-12 16:25:52 -040048 // Particle behavior is driven by two chunks of SkSL code. Effect functions are defined in
49 // fEffectCode, and get a mutable Effect struct:
Brian Osman3da607e2019-07-26 15:11:46 -040050 //
Brian Osmand46cb972019-09-12 16:25:52 -040051 // struct Effect {
Brian Osmand1846d82019-09-17 13:32:32 -040052 // float age; // Normalized age of the effect
53 // float lifetime; // Effect's duration, in seconds - script should set this in effectSpawn
54 // int loop; // Number of loops that have elapsed (0 on initial spawn)
55 // float rate; // Rate to generate new particles (particles / second)
56 // int burst; // Number of particles to emit in a single update
57 // // Set during spawn to emit that many at once on each loop
Brian Osmand46cb972019-09-12 16:25:52 -040058 //
59 // // Everything below this line controls the state of the effect, which is also the
60 // // default values for new particles.
61 // float2 pos = { 0, 0 }; // Local position
Brian Osman3da607e2019-07-26 15:11:46 -040062 // float2 dir = { 0, -1 }; // Heading. Should be a normalized vector.
63 // float scale = 1; // Size, normalized relative to the drawable's native size
64 // float2 vel = { 0, 0 }; // Linear velocity, in (units / second)
65 // float spin = 0; // Angular velocity, in (radians / second)
66 // float4 color = { 1, 1, 1, 1 }; // RGBA color
67 // float frame = 0; // Normalized sprite index for multi-frame drawables
Brian Osmane11c4382020-12-22 16:15:28 -050068 // float seed = 0; // Random value, used with rand() (see below)
Brian Osman3da607e2019-07-26 15:11:46 -040069 // };
70 //
Brian Osmand46cb972019-09-12 16:25:52 -040071 // Particle functions are defined in fParticleCode, and get a mutable Particle struct, as well
72 // as a uniform copy of the current Effect, named 'effect'.
Brian Osman3da607e2019-07-26 15:11:46 -040073 //
Brian Osmand46cb972019-09-12 16:25:52 -040074 // struct Particle {
75 // float age;
76 // float lifetime;
77 // float2 pos;
78 // float2 dir;
79 // float scale;
80 // float2 vel;
81 // float spin;
82 // float4 color;
83 // float frame;
Brian Osmane11c4382020-12-22 16:15:28 -050084 // float seed;
Brian Osmand46cb972019-09-12 16:25:52 -040085 // };
86 //
Brian Osmane11c4382020-12-22 16:15:28 -050087 // All functions have access to a global function named 'rand'. It takes a float seed value,
88 // which it uses and updates (using a PRNG). It returns a random floating point value in [0, 1].
89 // Typical usage is to pass the particle or effect's seed value to rand.
Brian Osman95c26ef2020-02-10 13:45:22 -050090 // For particle functions, the seed is rewound after each update, so calls to 'rand(p.seed)'
91 // will return consistent values from one update to the next.
Brian Osmand46cb972019-09-12 16:25:52 -040092 //
93 // Finally, there is one global uniform values available, 'dt'. This is a floating point
94 // number of seconds that have elapsed since the last update.
95 //
96 // Effect code should define two functions:
97 //
98 // 'void effectSpawn(inout Effect e)' is called when an instance of the effect is first
99 // created, and again at every loop point (if the effect is played with the looping flag).
100 //
101 // 'void effectUpdate(inout Effect e)' is called once per update to adjust properties of the
102 // effect (ie emitter).
103 //
104 // Particle code should also define two functions:
Brian Osman3da607e2019-07-26 15:11:46 -0400105 //
106 // 'void spawn(inout Particle p)' is called once for each particle when it is first created,
107 // to set initial values. At a minimum, this should set 'lifetime' to the number of seconds
Brian Osmand1846d82019-09-17 13:32:32 -0400108 // that the particle will exist. Other parameters will get default values from the effect.
Brian Osman3da607e2019-07-26 15:11:46 -0400109 //
110 // 'void update(inout Particle p)' is called for each particle on every call to the running
111 // SkParticleEffect's update() method. It can animate any of the particle's values. Note that
112 // the 'lifetime' field has a different meaning in 'update', and should not be used or changed.
Brian Osmand46cb972019-09-12 16:25:52 -0400113
114 SkString fEffectCode;
115 SkString fParticleCode;
Brian Osmanfe491632019-07-25 15:14:50 -0400116
Brian Osman3da607e2019-07-26 15:11:46 -0400117 // External objects accessible by the effect's SkSL code. Each binding is a name and particular
118 // kind of object. See SkParticleBinding::Make* for details.
Brian Osmanfe491632019-07-25 15:14:50 -0400119 SkTArray<sk_sp<SkParticleBinding>> fBindings;
Brian Osman7c979f52019-02-12 13:27:51 -0500120
121 void visitFields(SkFieldVisitor* v);
Brian Osmanfe491632019-07-25 15:14:50 -0400122
Brian Osman9dac0d82019-12-02 16:52:51 -0500123 // Load/compute cached resources
124 void prepare(const skresources::ResourceProvider*);
125
Brian Osmanfe491632019-07-25 15:14:50 -0400126private:
127 friend class SkParticleEffect;
128
Brian Osmane89d8ea2021-01-20 14:01:30 -0500129 std::unique_ptr<SkParticleProgram> fEffectProgram;
130 std::unique_ptr<SkParticleProgram> fParticleProgram;
Brian Osman7c979f52019-02-12 13:27:51 -0500131};
132
133class SkParticleEffect : public SkRefCnt {
134public:
Brian Osman95c26ef2020-02-10 13:45:22 -0500135 SkParticleEffect(sk_sp<SkParticleEffectParams> params);
Brian Osman7c979f52019-02-12 13:27:51 -0500136
Brian Osman9a8b8462019-09-19 10:06:36 -0400137 // Start playing this effect, specifying initial values for the emitter's properties
138 void start(double now, bool looping, SkPoint position, SkVector heading, float scale,
Brian Osmane11c4382020-12-22 16:15:28 -0500139 SkVector velocity, float spin, SkColor4f color, float frame, float seed);
Brian Osman9a8b8462019-09-19 10:06:36 -0400140
141 // Start playing this effect, with default values for the emitter's properties
142 void start(double now, bool looping) {
143 this->start(now, looping,
144 { 0.0f, 0.0f }, // position
145 { 0.0f, -1.0f }, // heading
146 1.0f, // scale
147 { 0.0f, 0.0f }, // velocity
148 0.0f, // spin
149 { 1.0f, 1.0f, 1.0f, 1.0f }, // color
Brian Osman559ffe42019-09-25 11:24:50 -0400150 0.0f, // sprite frame
Brian Osmane11c4382020-12-22 16:15:28 -0500151 0.0f); // seed
Brian Osman9a8b8462019-09-19 10:06:36 -0400152 }
153
Kevin Lubick269fe892019-03-06 09:32:55 -0500154 void update(double now);
Brian Osman7c979f52019-02-12 13:27:51 -0500155 void draw(SkCanvas* canvas);
156
Brian Osmanace3f292021-01-12 13:18:52 -0500157 bool isAlive() const { return (fState.fAge >= 0 && fState.fAge <= 1); }
Brian Osmanb77d5022019-03-06 11:08:48 -0500158 int getCount() const { return fCount; }
Brian Osman7c979f52019-02-12 13:27:51 -0500159
Brian Osmandf182962019-10-15 10:27:59 -0400160 float getRate() const { return fState.fRate; }
161 int getBurst() const { return fState.fBurst; }
162 SkPoint getPosition() const { return fState.fPosition; }
163 SkVector getHeading() const { return fState.fHeading; }
164 float getScale() const { return fState.fScale; }
165 SkVector getVelocity() const { return fState.fVelocity; }
166 float getSpin() const { return fState.fSpin; }
167 SkColor4f getColor() const { return fState.fColor; }
168 float getFrame() const { return fState.fFrame; }
Brian Osmandf182962019-10-15 10:27:59 -0400169
170 void setRate (float r) { fState.fRate = r; }
171 void setBurst (int b) { fState.fBurst = b; }
172 void setPosition(SkPoint p) { fState.fPosition = p; }
173 void setHeading (SkVector h) { fState.fHeading = h; }
174 void setScale (float s) { fState.fScale = s; }
175 void setVelocity(SkVector v) { fState.fVelocity = v; }
176 void setSpin (float s) { fState.fSpin = s; }
177 void setColor (SkColor4f c) { fState.fColor = c; }
178 void setFrame (float f) { fState.fFrame = f; }
Brian Osmandf182962019-10-15 10:27:59 -0400179
Brian Osmane89d8ea2021-01-20 14:01:30 -0500180 const SkSL::UniformInfo* effectUniformInfo() const;
181 const SkSL::UniformInfo* particleUniformInfo() const;
Brian Osman5b431132019-10-15 16:41:18 -0400182
183 float* effectUniforms() { return fEffectUniforms.data(); }
184 float* particleUniforms() { return fParticleUniforms.data(); }
185
Brian Osman2aa85df2019-08-30 10:59:47 -0400186 static void RegisterParticleTypes();
187
Brian Osman7c979f52019-02-12 13:27:51 -0500188private:
189 void setCapacity(int capacity);
190
Brian Osman9a8b8462019-09-19 10:06:36 -0400191 // Helpers to break down update
192 void advanceTime(double now);
193
Brian Osmane89d8ea2021-01-20 14:01:30 -0500194 enum class EntryPoint {
195 kSpawn,
196 kUpdate,
197 };
198
199 void runEffectScript(EntryPoint entryPoint);
200 void runParticleScript(EntryPoint entryPoint, int start, int count);
Brian Osman9a8b8462019-09-19 10:06:36 -0400201
Brian Osmand12f2782019-11-27 10:34:18 -0500202 sk_sp<SkParticleEffectParams> fParams;
Brian Osman7c979f52019-02-12 13:27:51 -0500203
Brian Osman5c1f8eb2019-02-14 14:49:55 -0500204 bool fLooping;
Brian Osman7c979f52019-02-12 13:27:51 -0500205 int fCount;
206 double fLastTime;
207 float fSpawnRemainder;
208
Brian Osman5b431132019-10-15 16:41:18 -0400209 // C++ version of the SkSL Effect struct. This is the inout parameter to per-effect scripts,
210 // and provided as a uniform (named 'effect') to the per-particle scripts.
Brian Osmand46cb972019-09-12 16:25:52 -0400211 struct EffectState {
Brian Osmand46cb972019-09-12 16:25:52 -0400212 float fAge;
213 float fLifetime;
214 int fLoopCount;
215 float fRate;
216 int fBurst;
217
218 // Properties that determine default values for new particles
219 SkPoint fPosition;
220 SkVector fHeading;
221 float fScale;
222 SkVector fVelocity;
223 float fSpin;
224 SkColor4f fColor;
225 float fFrame;
Brian Osmane11c4382020-12-22 16:15:28 -0500226 float fRandom;
Brian Osmand46cb972019-09-12 16:25:52 -0400227 };
228 EffectState fState;
229
Brian Osman95c26ef2020-02-10 13:45:22 -0500230 SkParticles fParticles;
231 SkAutoTMalloc<float> fStableRandoms;
Brian Osman7c979f52019-02-12 13:27:51 -0500232
233 // Cached
234 int fCapacity;
Brian Osman5b431132019-10-15 16:41:18 -0400235 SkTArray<float, true> fEffectUniforms;
236 SkTArray<float, true> fParticleUniforms;
Brian Osman7c979f52019-02-12 13:27:51 -0500237};
238
239#endif // SkParticleEffect_DEFINED