summaryrefslogtreecommitdiff
path: root/Runtime/Graphics/ParticleSystem/Modules/ParticleSystemModule.h
blob: b4746de14c3e67c3aaa9ee7415f5dfa83c4d3253 (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
#ifndef SHURIKENMODULE_H
#define SHURIKENMODULE_H

#include "../ParticleSystemCommon.h"
#include "../ParticleSystemCurves.h"
#include "Runtime/Math/Matrix4x4.h"
#include "Runtime/Geometry/AABB.h"
#include "Runtime/Utilities/dynamic_array.h"

#define ENABLE_MULTITHREADED_PARTICLES ENABLE_MULTITHREADED_CODE

#define DECLARE_MODULE(name) const char* GetName () { return #name; } DEFINE_GET_TYPESTRING(name)

class ParticleSystem;
class Plane;

struct ParticleSystemEmissionState
{
	ParticleSystemEmissionState() { Clear(); }
	inline void Clear()
	{
		m_ToEmitAccumulator = 0.0f;
		m_ParticleSpacing = 0.0f;
	}
	float m_ParticleSpacing;
	float m_ToEmitAccumulator;
};

struct ParticleSystemEmissionData
{
	enum { kMaxNumBursts = 4 };

	int type;
	MinMaxCurve rate;
	float burstTime[kMaxNumBursts];
	UInt16 burstParticleCount[kMaxNumBursts];
	UInt8 burstCount;
};


struct ParticleSystemSubEmitterData
{
	ParticleSystemSubEmitterData()
	:maxLifetime(0.0f)
	,startDelayInSec(0.0f)
	,lengthInSec(0.0f)
	{}

	ParticleSystemEmissionData emissionData;
	float maxLifetime;
	float startDelayInSec;
	float lengthInSec;
	ParticleSystem* emitter;
};

// @TODO: Find "pretty" place for shared structs and enums?
struct ParticleSystemEmitReplay
{
	float  t;
	float  aliveTime;
	float emissionOffset;
	float emissionGap;
	int    particlesToEmit;
	size_t numContinuous;
	UInt32 randomSeed;
	
	ParticleSystemEmitReplay (float inT, int inParticlesToEmit, float inEmissionOffset, float inEmissionGap, size_t inNumContinuous, UInt32 inRandomSeed)
		: t (inT), particlesToEmit (inParticlesToEmit), aliveTime(0.0F), emissionOffset(inEmissionOffset), emissionGap(inEmissionGap), numContinuous(inNumContinuous), randomSeed(inRandomSeed)
	{}
};

struct SubEmitterEmitCommand
{
	SubEmitterEmitCommand(ParticleSystemEmissionState inEmissionState, Vector3f inPosition, Vector3f inVelocity, ParticleSystemSubType inSubEmitterType, int inSubEmitterIndex, int inParticlesToEmit, int inParticlesToEmitContinuous, float inParentT, float inDeltaTime)
	:emissionState(inEmissionState)
	,position(inPosition)
	,velocity(inVelocity)
	,subEmitterType(inSubEmitterType)
	,subEmitterIndex(inSubEmitterIndex)
	,particlesToEmit(inParticlesToEmit)
	,particlesToEmitContinuous(inParticlesToEmitContinuous)
	,deltaTime(inDeltaTime)
	,parentT(inParentT)
	,timeAlive(0.0f)
	{
	}

	ParticleSystemEmissionState emissionState;
	Vector3f position;
	Vector3f velocity;
	ParticleSystemSubType subEmitterType;
	int subEmitterIndex;
	int particlesToEmit;
	int particlesToEmitContinuous;
	float deltaTime;
	float parentT;		// Used for StartModules
	float timeAlive;
};

struct ParticleSystemSubEmitCmdBuffer
{
	ParticleSystemSubEmitCmdBuffer()
	:commands(0)
	,commandCount(0)
	,maxCommandCount(0)
	{}
	
	inline void AddCommand(const ParticleSystemEmissionState& emissionState, const Vector3f& initialPosition, const Vector3f& initialVelocity, const ParticleSystemSubType type, const int index, const int particlesToEmit, const int particlesToEmitContinuous, const float parentT, const float dt)
	{
		commands[commandCount++] = SubEmitterEmitCommand(emissionState, initialPosition, initialVelocity, type, index, particlesToEmit, particlesToEmitContinuous, parentT, dt);
	}
	inline bool IsFull() { return commandCount >= maxCommandCount; }
	
	SubEmitterEmitCommand* commands;
	int commandCount;
	int maxCommandCount; // Mostly to assert/test against trashing memory
};

struct ParticleSystemExternalCachedForce
{
	Vector3f position;
	Vector3f direction;
	int forceType;
	float radius;
	float forceMain;
	float forceTurbulence; // not yet implemented
};

// @TODO: Maybe there's a better name for this? ParticleSystemSerializedState? Some shit like that :)
struct ParticleSystemReadOnlyState
{
	ParticleSystemReadOnlyState();
	
	void CheckConsistency();

	float lengthInSec;
	float startDelay;
	float speed;
	UInt32 randomSeed;
	bool looping;
	bool prewarm;
	bool playOnAwake;
	bool useLocalSpace;

	template<class TransferFunction>
	void Transfer (TransferFunction& transfer);
};

// Some of these aren't actually state, but more like context. Separate it?
struct ParticleSystemState
{	
	// state
	float accumulatedDt;
	float delayT;
	bool playing;
	bool needRestart;
	bool stopEmitting;
	size_t rayBudget;
	size_t nextParticleToTrace;

	bool GetIsSubEmitter() const { return isSubEmitter; }
private:
	// When setting this we need to ensure some other things happen as well
	bool isSubEmitter;

public:
	
	bool recordSubEmits;

	// Procedural mode / culling
	bool supportsProcedural;	// With the current parameter set, does the emitter support procedural mode?
	bool invalidateProcedural;  // This is set if anything changes from script at some point when running a system
	bool culled;				// Is particle system currently culled?
	double cullTime;			// Absolute time, so we need as double in case it runs for ages
	int numLoops;				// Number of loops executed
	
	// per-frame
	Matrix4x4f localToWorld;
	Matrix4x4f worldToLocal;
	Vector3f emitterVelocity;
	Vector3f emitterScale;
	
	MinMaxAABB minMaxAABB;
	float maxSize; // Maximum size of particles due to setting from script
	float t;

	// Temp alloc stuff
	ParticleSystemSubEmitterData* cachedSubDataBirth;
	size_t numCachedSubDataBirth;
	ParticleSystemSubEmitterData* cachedSubDataCollision;
	size_t numCachedSubDataCollision;
	ParticleSystemSubEmitterData* cachedSubDataDeath;
	size_t numCachedSubDataDeath;
	ParticleSystemExternalCachedForce* cachedForces;
	size_t numCachedForces;
	Plane* cachedCollisionPlanes;
	size_t numCachedCollisionPlanes;
	ParticleSystemSubEmitCmdBuffer subEmitterCommandBuffer;

	dynamic_array<ParticleSystemEmitReplay> emitReplay;
	ParticleSystemEmissionState emissionState;
	
	ParticleSystemState ();

	void Tick (const ParticleSystemReadOnlyState& constState, float dt);
	void ClearSubEmitterCommandBuffer();

	void SetIsSubEmitter(bool inIsSubEmitter)
	{
		if(inIsSubEmitter)
		{
			stopEmitting = true;
			invalidateProcedural = true;
		}
		isSubEmitter = inIsSubEmitter;
	}

	template<class TransferFunction>
	void Transfer (TransferFunction& transfer);
};


class ParticleSystemModule
{
public:
	DECLARE_SERIALIZE (ParticleSystemModule)
	ParticleSystemModule (bool enabled) : m_Enabled (enabled) {}
	virtual ~ParticleSystemModule () {}
	
	inline bool GetEnabled() const { return m_Enabled; }
	inline void SetEnabled(bool enabled) { m_Enabled = enabled; }

private:
	// shared data
	bool m_Enabled;
};

#endif // SHURIKENMODULE_H