blob: 82ab3fcda06827b6981e4201c0d2fbd110956868 [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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "include/utils/SkRandom.h"
Brian Osmanfe491632019-07-25 15:14:50 -040018#include "modules/particles/include/SkParticleData.h"
Brian Osmanfe491632019-07-25 15:14:50 -040019
20#include <memory>
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 Osmanfe491632019-07-25 15:14:50 -040026class SkParticleExternalValue;
27
28namespace SkSL {
29 struct ByteCode;
Brian Osmanfe491632019-07-25 15:14:50 -040030}
31
Brian Osman7c979f52019-02-12 13:27:51 -050032class SkParticleEffectParams : public SkRefCnt {
33public:
Brian Osmanfe491632019-07-25 15:14:50 -040034 SkParticleEffectParams();
35
Brian Osmand46cb972019-09-12 16:25:52 -040036 // Maximum number of particles per instance of the effect
37 int fMaxCount;
Brian Osman7c979f52019-02-12 13:27:51 -050038
Brian Osman3da607e2019-07-26 15:11:46 -040039 // What is drawn for each particle? (Image, shape, sprite sheet, etc.)
40 // See SkParticleDrawable::Make*
Brian Osman543d2e22019-02-15 14:29:38 -050041 sk_sp<SkParticleDrawable> fDrawable;
Brian Osman7c979f52019-02-12 13:27:51 -050042
Brian Osmand46cb972019-09-12 16:25:52 -040043 // Particle behavior is driven by two chunks of SkSL code. Effect functions are defined in
44 // fEffectCode, and get a mutable Effect struct:
Brian Osman3da607e2019-07-26 15:11:46 -040045 //
Brian Osmand46cb972019-09-12 16:25:52 -040046 // struct Effect {
Brian Osmand1846d82019-09-17 13:32:32 -040047 // float age; // Normalized age of the effect
48 // float lifetime; // Effect's duration, in seconds - script should set this in effectSpawn
49 // int loop; // Number of loops that have elapsed (0 on initial spawn)
50 // float rate; // Rate to generate new particles (particles / second)
51 // int burst; // Number of particles to emit in a single update
52 // // Set during spawn to emit that many at once on each loop
Brian Osmand46cb972019-09-12 16:25:52 -040053 //
54 // // Everything below this line controls the state of the effect, which is also the
55 // // default values for new particles.
56 // float2 pos = { 0, 0 }; // Local position
Brian Osman3da607e2019-07-26 15:11:46 -040057 // float2 dir = { 0, -1 }; // Heading. Should be a normalized vector.
58 // float scale = 1; // Size, normalized relative to the drawable's native size
59 // float2 vel = { 0, 0 }; // Linear velocity, in (units / second)
60 // float spin = 0; // Angular velocity, in (radians / second)
61 // float4 color = { 1, 1, 1, 1 }; // RGBA color
62 // float frame = 0; // Normalized sprite index for multi-frame drawables
63 // };
64 //
Brian Osmand46cb972019-09-12 16:25:52 -040065 // Particle functions are defined in fParticleCode, and get a mutable Particle struct, as well
66 // as a uniform copy of the current Effect, named 'effect'.
Brian Osman3da607e2019-07-26 15:11:46 -040067 //
Brian Osmand46cb972019-09-12 16:25:52 -040068 // struct Particle {
69 // float age;
70 // float lifetime;
71 // float2 pos;
72 // float2 dir;
73 // float scale;
74 // float2 vel;
75 // float spin;
76 // float4 color;
77 // float frame;
78 // };
79 //
80 // All functions have access to a global variable named 'rand'. Every read of 'rand' returns a
81 // random floating point value in [0, 1). For particle functions, the state is rewound after
82 // each update, so calls to 'rand' will return consistent values from one update to the next.
83 //
84 // Finally, there is one global uniform values available, 'dt'. This is a floating point
85 // number of seconds that have elapsed since the last update.
86 //
87 // Effect code should define two functions:
88 //
89 // 'void effectSpawn(inout Effect e)' is called when an instance of the effect is first
90 // created, and again at every loop point (if the effect is played with the looping flag).
91 //
92 // 'void effectUpdate(inout Effect e)' is called once per update to adjust properties of the
93 // effect (ie emitter).
94 //
95 // Particle code should also define two functions:
Brian Osman3da607e2019-07-26 15:11:46 -040096 //
97 // 'void spawn(inout Particle p)' is called once for each particle when it is first created,
98 // to set initial values. At a minimum, this should set 'lifetime' to the number of seconds
Brian Osmand1846d82019-09-17 13:32:32 -040099 // that the particle will exist. Other parameters will get default values from the effect.
Brian Osman3da607e2019-07-26 15:11:46 -0400100 //
101 // 'void update(inout Particle p)' is called for each particle on every call to the running
102 // SkParticleEffect's update() method. It can animate any of the particle's values. Note that
103 // the 'lifetime' field has a different meaning in 'update', and should not be used or changed.
Brian Osmand46cb972019-09-12 16:25:52 -0400104
105 SkString fEffectCode;
106 SkString fParticleCode;
Brian Osmanfe491632019-07-25 15:14:50 -0400107
Brian Osman3da607e2019-07-26 15:11:46 -0400108 // External objects accessible by the effect's SkSL code. Each binding is a name and particular
109 // kind of object. See SkParticleBinding::Make* for details.
Brian Osmanfe491632019-07-25 15:14:50 -0400110 SkTArray<sk_sp<SkParticleBinding>> fBindings;
Brian Osman7c979f52019-02-12 13:27:51 -0500111
112 void visitFields(SkFieldVisitor* v);
Brian Osmanfe491632019-07-25 15:14:50 -0400113
114private:
115 friend class SkParticleEffect;
116
117 // Cached
Brian Osmand46cb972019-09-12 16:25:52 -0400118 struct Program {
119 std::unique_ptr<SkSL::ByteCode> fByteCode;
120 SkTArray<std::unique_ptr<SkParticleExternalValue>> fExternalValues;
121 };
122
123 Program fEffectProgram;
124 Program fParticleProgram;
Brian Osmanfe491632019-07-25 15:14:50 -0400125
126 void rebuild();
Brian Osman7c979f52019-02-12 13:27:51 -0500127};
128
129class SkParticleEffect : public SkRefCnt {
130public:
Brian Osman5c1f8eb2019-02-14 14:49:55 -0500131 SkParticleEffect(sk_sp<SkParticleEffectParams> params, const SkRandom& random);
Brian Osman7c979f52019-02-12 13:27:51 -0500132
Kevin Lubick269fe892019-03-06 09:32:55 -0500133 void start(double now, bool looping = false);
Kevin Lubick269fe892019-03-06 09:32:55 -0500134 void update(double now);
Brian Osman7c979f52019-02-12 13:27:51 -0500135 void draw(SkCanvas* canvas);
136
Brian Osmand46cb972019-09-12 16:25:52 -0400137 bool isAlive() const { return fState.fAge >= 0 && fState.fAge <= 1; }
Brian Osmanb77d5022019-03-06 11:08:48 -0500138 int getCount() const { return fCount; }
Brian Osman7c979f52019-02-12 13:27:51 -0500139
Brian Osman2aa85df2019-08-30 10:59:47 -0400140 static void RegisterParticleTypes();
141
Brian Osman7c979f52019-02-12 13:27:51 -0500142private:
143 void setCapacity(int capacity);
144
Brian Osman7c979f52019-02-12 13:27:51 -0500145 sk_sp<SkParticleEffectParams> fParams;
Brian Osman7c979f52019-02-12 13:27:51 -0500146
Brian Osman5c1f8eb2019-02-14 14:49:55 -0500147 SkRandom fRandom;
148
149 bool fLooping;
Brian Osman7c979f52019-02-12 13:27:51 -0500150 int fCount;
151 double fLastTime;
152 float fSpawnRemainder;
153
Brian Osmand46cb972019-09-12 16:25:52 -0400154 // Effect-associated values exposed to script. They are some mix of uniform and inout,
155 // depending on whether we're executing per-feffect or per-particle scripts.
156 struct EffectState {
157 float fDeltaTime;
158
159 // Above this line is always uniform. Below is uniform for particles, inout for effect.
160
161 float fAge;
162 float fLifetime;
163 int fLoopCount;
164 float fRate;
165 int fBurst;
166
167 // Properties that determine default values for new particles
168 SkPoint fPosition;
169 SkVector fHeading;
170 float fScale;
171 SkVector fVelocity;
172 float fSpin;
173 SkColor4f fColor;
174 float fFrame;
175 };
176 EffectState fState;
177
Brian Osmanfe491632019-07-25 15:14:50 -0400178 SkParticles fParticles;
179 SkAutoTMalloc<SkRandom> fStableRandoms;
Brian Osman7c979f52019-02-12 13:27:51 -0500180
181 // Cached
182 int fCapacity;
183};
184
185#endif // SkParticleEffect_DEFINED