summaryrefslogtreecommitdiff
path: root/Runtime/Graphics/ParticleSystem/ParticleSystem.h
blob: 10c8f2a35d0ef289c40008045f25b4e8a723dc0e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
#ifndef SHURIKEN_H
#define SHURIKEN_H

#include "Runtime/BaseClasses/GameObject.h"
#include "ParticleSystemParticle.h"
#include "Runtime/Utilities/LinkedList.h"
#include "Modules/InitialModule.h"
#include "Modules/ShapeModule.h"
#include "Modules/EmissionModule.h"

struct ParticleSystemEmitReplay;
struct ParticleSystemState;
class ParticleSystemModule;
class SizeModule;
class RotationModule;
class ColorModule;
class UVModule;
class VelocityModule;
class ForceModule;
class ExternalForcesModule;
class ClampVelocityModule;
class SizeBySpeedModule;
class RotationBySpeedModule;
class ColorBySpeedModule;
class CollisionModule;
class SubModule;

enum ParticleSystemSimulationSpace {
	kSimLocal = 0,
	kSimWorld = 1,
};

// TODO: rename
struct ParticleSystemThreadScratchPad
{
	ParticleSystemThreadScratchPad ()
	: deltaTime (1.0f)
	{}
	
	float deltaTime;
};

enum { kGoodQualityDelay = 0, kMediumQualityDelay = 0, kLowQualityDelay = 4 }; 
struct RayBudgetState
{
	void SetQuality(int quality)
	{
		if ( m_Quality != quality )
		{
			switch (quality)
			{
			case 0:
				m_QualityFrameDelay = kGoodQualityDelay;
				break;
			case 1:
				m_QualityFrameDelay = kMediumQualityDelay;
				break;
			case 2:
				m_QualityFrameDelay = kLowQualityDelay;
				break;
			default:
				m_QualityFrameDelay = kGoodQualityDelay;
			}
			m_FramesRemaining = m_QualityFrameDelay;
			m_Quality = quality;
		};
	}
	RayBudgetState() { m_Quality=m_QualityFrameDelay=m_FramesRemaining=0; }
	bool ReceiveRays() const { return m_FramesRemaining==0; }
	void Update() { m_FramesRemaining = ( m_FramesRemaining ? m_FramesRemaining-1 : m_QualityFrameDelay ); }
	int m_Quality;
	int m_QualityFrameDelay;
	int m_FramesRemaining;
};

class ParticleSystem : public Unity::Component
{
public:
	REGISTER_DERIVED_CLASS (ParticleSystem, Unity::Component)
	DECLARE_OBJECT_SERIALIZE (ParticleSystem)

	enum
	{
		kParticleBuffer0,
#if UNITY_EDITOR // Double buffered + interpolation
		kParticleBuffer1,
#endif
		kNumParticleBuffers,
	};
	
	ParticleSystem (MemLabelId label, ObjectCreationMode mode);

	// ParticleSystem (); declared-by-macro

	void SmartReset ();
	void AddParticleSystemRenderer ();

	void Deactivate (DeactivateOperation operation);
	void AwakeFromLoad (AwakeFromLoadMode awakeMode);
	
	#if UNITY_EDITOR
	// ParticleSystemRenderer always goes with ParticleSystem
	virtual int GetCoupledComponentClassID() const { return ClassID(ParticleSystemRenderer); }
	#endif
	
	
	static void* UpdateFunction (void* rawData);
	
	static void BeginUpdateAll();
	static void EndUpdateAll();
	static void Update(ParticleSystem& system, float deltaTime, bool fixedTimeStep, bool useProcedural, int rayBudget = 0);
	
	static bool SystemWannaRayCast(const ParticleSystem& system);
	static bool SystemWillRayCast(const ParticleSystem& system);
	static void AssignRayBudgets();

	static void SyncJobs();

	static void Emit(ParticleSystem& system, const SubEmitterEmitCommand& command, ParticleSystemEmitMode emitMode);
	
	// Client interface
	void Simulate (float t, bool restart);				// Fastforwards the particle system by simulating particles over given period of time, then pauses it.
	void Play (bool autoPrewarm = true);
	void Stop ();
	void Pause ();
	void Emit (int count);
	void EmitParticleExternal(ParticleSystemParticle* particle);
	void Clear (bool updateBounds = true);
	void AutoPrewarm();
	
	bool IsAlive () const;
	bool IsPlaying () const;
	bool IsPaused () const;
	bool IsStopped () const;
	float GetStartDelay() const;	
	void SetStartDelay(float value);
	bool GetLoop () const;
	void SetLoop (bool loop);
	bool GetPlayOnAwake () const;
	void SetPlayOnAwake (bool playOnAwake);
	ParticleSystemSimulationSpace GetSimulationSpace () const;
	void SetSimulationSpace (ParticleSystemSimulationSpace simulationSpace);
	float GetSecPosition () const;
	void SetSecPosition (float pos);
	float GetLengthInSec () const;
	void SetPlaybackSpeed (float speed);
	float GetPlaybackSpeed () const;
	void SetRayBudget (int rayBudget);
	int GetRayBudget() const;

	bool GetEnableEmission() const;
	void SetEnableEmission(bool value);
	float GetEmissionRate() const;
	void SetEmissionRate(float value);
	float GetStartSpeed() const;
	void SetStartSpeed(float value);
	float GetStartSize() const;
	void SetStartSize(float value);
	ColorRGBAf GetStartColor() const;
	void SetStartColor(ColorRGBAf value);
	float GetStartRotation() const;
	void SetStartRotation(float value);
	float GetStartLifeTime() const;
	void SetStartLifeTime(float value);
	float GetGravityModifier() const;
	void SetGravityModifier(float value);
	UInt32 GetRandomSeed() const;
	void SetRandomSeed(UInt32 value);
	int GetMaxNumParticles() const;
	void SetMaxNumParticles(int value);

	ShapeModule& GetShapeModule () { return m_ShapeModule; }
	
	
	Matrix4x4f GetLocalToWorldMatrix() const;

	void GetNumTiles(int& uvTilesX, int& uvTilesY) const;
	
	void AllocateAllStructuresOfArrays();
	void SetParticlesExternal (ParticleSystemParticle* particles, int size);
	void GetParticlesExternal (ParticleSystemParticle* particles, int size);

	int GetSafeCollisionEventSize () const;
	int GetCollisionEventsExternal (int instanceID, MonoParticleCollisionEvent* collisionEvents, int size) const;

	ParticleSystemParticles& GetParticles (int index = -1);
	const ParticleSystemParticles& GetParticles (int index = -1) const;
	size_t GetParticleCount () const;

	ParticleSystemThreadScratchPad& GetThreadScratchPad () { return m_ThreadScratchpad; }

	static void InitializeClass ();
	static void CleanupClass () {};

	void DidModifyMesh ();
	void DidDeleteMesh ();

#if UNITY_EDITOR
	void TransformChanged();
#endif
	
	void RendererBecameVisible();
	void RendererBecameInvisible();

	static size_t EmitFromData (ParticleSystemEmissionState& emissionState, size_t& numContinuous, const ParticleSystemEmissionData& emissionData, const Vector3f velocity, float fromT, float toT, float dt, float length);
private:
	static void Update0 (ParticleSystem& system, const ParticleSystemReadOnlyState& roState, ParticleSystemState& state, float dt, bool fixedTimeStep);
	static void Update1 (ParticleSystem& system, ParticleSystemParticles& ps, float dt, bool fixedTimeStep, bool useProcedural, int rayBudget = 0);
	static void Update2 (ParticleSystem& system, const ParticleSystemReadOnlyState& roState, ParticleSystemState& state, bool fixedTimeStep);
	static void Update1Incremental(ParticleSystem& system, const ParticleSystemReadOnlyState& roState, ParticleSystemState& state, ParticleSystemParticles& ps, size_t fromIndex, float dt, bool useProcedural);

	static size_t EmitFromModules (const ParticleSystem& system, const ParticleSystemReadOnlyState& roState, ParticleSystemEmissionState& emissionState, size_t& numContinuous, const Vector3f velocity, float fromT, float toT, float dt);
	static void StartModules (ParticleSystem& system, const ParticleSystemReadOnlyState& roState, ParticleSystemState& state, const ParticleSystemEmissionState& emissionState, Vector3f initialVelocity, const Matrix4x4f& matrix, ParticleSystemParticles& ps, size_t fromIndex, float dt, float t, size_t numContinuous, float frameOffset);
	static void StartParticles(ParticleSystem& system, ParticleSystemParticles& ps, const float prevT, const float t, const float dt, const size_t numContinuous, size_t amountOfParticlesToEmit, float frameOffset);
	static void StartParticlesProcedural(ParticleSystem& system, ParticleSystemParticles& ps, const float prevT, const float t, const float dt, const size_t numContinuous, size_t amountOfParticlesToEmit, float frameOffset);
	static void UpdateProcedural(ParticleSystem& system, const ParticleSystemReadOnlyState& roState, ParticleSystemState& state, ParticleSystemParticles& ps);
	static void UpdateModulesPreSimulationIncremental (const ParticleSystem& system, const ParticleSystemReadOnlyState& roState, const ParticleSystemState& state, ParticleSystemParticles& ps, const size_t fromIndex, const size_t toIndex, float dt);
	static void UpdateModulesPostSimulationIncremental (const ParticleSystem& system, const ParticleSystemReadOnlyState& roState, ParticleSystemState& state, ParticleSystemParticles& ps, const size_t fromIndex, float dt);
	static void UpdateModulesIncremental (const ParticleSystem& system, const ParticleSystemReadOnlyState& roState, ParticleSystemState& state, ParticleSystemParticles& ps, size_t fromIndex, float dt);
	static void UpdateModulesNonIncremental (const ParticleSystem& system, const ParticleSystemParticles& ps, ParticleSystemParticlesTempData& psTemp, size_t fromIndex, size_t toIndex);
	static void SimulateParticles (const ParticleSystemReadOnlyState& roState, ParticleSystemState& state, ParticleSystemParticles& ps, const size_t fromIndex, float dt);
	static void PlaybackSubEmitterCommandBuffer(const ParticleSystem& shuriken, ParticleSystemState& state, bool fixedTimeStep);
	static void UpdateBounds(const ParticleSystem& system, const ParticleSystemParticles& ps, ParticleSystemState& state);

	static void AddStagingBuffer(ParticleSystem& system);
	static int CalculateMaximumSubEmitterEmitCount(ParticleSystem& shuriken, ParticleSystemState& state, float deltaTime, bool fixedTimeStep);
	static int SetupSubEmitters(ParticleSystem& shuriken, ParticleSystemState& state);
	
	static bool CheckSupportsProcedural(const ParticleSystem& system);
	static bool DetermineSupportsProcedural(const ParticleSystem& system);
	
	bool ComputePrewarmStartParameters(float& prewarmTime, float t);

	void SetUsesAxisOfRotation();
	void SetUsesEmitAccumulator(int numAccumulators);
	void SetUsesRotationalSpeed();
	void KeepUpdating();
	void Cull();

	size_t AddNewParticles(ParticleSystemParticles& particles, size_t newParticles) const;	
	size_t LimitParticleCount(size_t requestSize) const;
	float CalculateSubEmitterMaximumLifeTime(float parentLifeTime) const;

	bool GetIsDistanceEmitter() const;
	
	void AddToManager();
	void RemoveFromManager();
	
	ParticleSystemParticles			m_Particles[kNumParticleBuffers];
	ParticleSystemParticles			m_ParticlesStaging; // staging buffer for emitting into the emitter 
	ParticleSystemReadOnlyState*		m_ReadOnlyState;
	ParticleSystemState*				m_State;
	InitialModule				m_InitialModule;
	ShapeModule					m_ShapeModule;
	EmissionModule				m_EmissionModule;

	// Dependent on energy value
	SizeModule*					m_SizeModule;
	RotationModule*				m_RotationModule; // @TODO: Requires outputs angular velocity and thus requires integration (Inconsistent with other modules in this group)
	ColorModule*				m_ColorModule;
	UVModule*					m_UVModule;
	
	// Dependent on energy value
	VelocityModule*				m_VelocityModule;
	ForceModule*				m_ForceModule;
	ExternalForcesModule*		m_ExternalForcesModule;
	
	// Depends on velocity and modifies velocity
	ClampVelocityModule*		m_ClampVelocityModule;
	
	// Dependent on velocity value
	SizeBySpeedModule*		m_SizeBySpeedModule;
	RotationBySpeedModule*	m_RotationBySpeedModule;
	ColorBySpeedModule*		m_ColorBySpeedModule;
	
	// Dependent on a position and velocity
	CollisionModule*		m_CollisionModule;
	
	SubModule*					m_SubModule;

	ParticleSystemThreadScratchPad    m_ThreadScratchpad;
	
	RayBudgetState			m_RayBudgetState;
	int						m_RayBudget;

private:
	int m_EmittersIndex;

#if UNITY_EDITOR
public:
	int m_EditorRandomSeedIndex;
	ListNode<ParticleSystem>	m_EditorListNode;
	friend class ParticleSystemEditor;
#endif
	friend class ParticleSystemRenderer;
};

#endif // SHURIKEN_H