1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "BsCorePrerequisites.h"
6#include "Image/BsPixelData.h"
7#include "Utility/BsModule.h"
8#include "Math/BsAABox.h"
9#include "CoreThread/BsCoreThread.h"
10#include "BsParticleSystem.h"
11
12namespace bs
13{
14 class ParticleSet;
15 struct EvaluatedAnimationData;
16
17 /** @addtogroup Particles-Internal
18 * @{
19 */
20
21 /**
22 * Contains data resulting from a single frame of CPU particle simulation of a single particle system, used by all
23 * rendering modes.
24 */
25 struct BS_CORE_EXPORT ParticleRenderData
26 {
27 /** Contains mapping from unsorted to sorted particle indices. */
28 Vector<UINT32> indices;
29
30 /** Total number of particles in the particle system. */
31 UINT32 numParticles;
32
33 /** Bounds of the particle system, in the system's simulation space. */
34 AABox bounds;
35 };
36
37 /**
38 * Contains data used for rendering particles as billboards. Per-particle data is stored in a 2D square layout so it
39 * can be used for quickly initializing a texture.
40 */
41 struct BS_CORE_EXPORT ParticleBillboardRenderData : ParticleRenderData
42 {
43 /** Contains particle positions in .xyz and 2D rotation in .w */
44 PixelData positionAndRotation;
45
46 /** Contains particle color in .xyz and transparency in .a. */
47 PixelData color;
48
49 /** Contains 2D particle size in .xy, frame index (used for animation) in .z. */
50 PixelData sizeAndFrameIdx;
51 };
52
53 /**
54 * Contains data used for rendering particles as meshes. Per-particle data is stored in a 2D square layout so it
55 * can be used for quickly initializing a texture.
56 */
57 struct BS_CORE_EXPORT ParticleMeshRenderData : ParticleRenderData
58 {
59 /** Contains particle positions in .xyz with .w unused. */
60 PixelData position;
61
62 /** Contains particle color in .xyz and transparency in .a. */
63 PixelData color;
64
65 /** Contains particle size in .xyz with .w unused. */
66 PixelData size;
67
68 /** Contains particle rotation in radians in .xyz with .w unused. */
69 PixelData rotation;
70 };
71 /**
72 * Contains information about a single particle about to be inserted into the GPU simulation. Matches the structure
73 * of the vertex buffer element used for injecting shader data into the simulation.
74 */
75 struct GpuParticleVertex
76 {
77 Vector3 position;
78 float lifetime;
79 Vector3 velocity;
80 float invMaxLifetime;
81 Vector2 size;
82 float rotation;
83 Vector2 dataUV;
84 };
85
86 /** Extension of GpuParticle that contains data not required by the injection vertex buffer. */
87 struct GpuParticle : GpuParticleVertex
88 {
89 /** Gets a version of this object suitable for upload to the injection vertex buffer. */
90 GpuParticleVertex getVertex() const
91 {
92 GpuParticleVertex output;
93 output.position = position;
94 output.lifetime = (initialLifetime - lifetime) / initialLifetime;
95 output.velocity = velocity;
96 output.invMaxLifetime = 1.0f / initialLifetime;
97 output.size = size;
98 output.rotation = rotation;
99 output.dataUV = dataUV;
100
101 return output;
102 }
103
104 float initialLifetime;
105 };
106
107 /** Contains inputs to the GPU particle simulation as provided by the particle system manager. */
108 struct BS_CORE_EXPORT ParticleGPUSimulationData
109 {
110 /** A set of the particles to be inserted into the simulation. */
111 Vector<GpuParticle> particles;
112 };
113
114 /** Contains simulation data resulting from all particle systems, for a single frame. */
115 struct ParticlePerFrameData
116 {
117 UnorderedMap<UINT32, ParticleRenderData*> cpuData;
118 UnorderedMap<UINT32, ParticleGPUSimulationData*> gpuData;
119 };
120
121 /** Keeps track of all active ParticleSystem%s and performs per-frame updates. */
122 class BS_CORE_EXPORT ParticleManager final : public Module<ParticleManager>
123 {
124 struct Members;
125 public:
126 ParticleManager();
127 ~ParticleManager();
128
129 /**
130 * Advances the simulation for all particle systems using the current frame time delta. Outputs a set of data
131 * that can be used for rendering & updating every active particle system.
132 */
133 ParticlePerFrameData* update(const EvaluatedAnimationData& animData);
134
135 private:
136 friend class ParticleSystem;
137
138 /** Must be called by a ParticleSystem upon construction. */
139 UINT32 registerParticleSystem(ParticleSystem* system);
140
141 /** Must be called by a ParticleSystem before destruction. */
142 void unregisterParticleSystem(ParticleSystem* system);
143
144 /**
145 * Sorts the particles in the provided @p using the @p sortMode. Sorted particle indices are placed in the
146 * @p indices array which is expected to be pre-allocated with enough space to hold an index for each particle
147 * in a set. @p viewPoint is used as a reference point when using the Distance sort mode.
148 */
149 void sortParticles(const ParticleSet& set, ParticleSortMode sortMode, const Vector3& viewPoint, UINT32* indices);
150
151 Members* m;
152
153 UINT32 mNextId = 1;
154 UnorderedSet<ParticleSystem*> mSystems;
155
156 bool mPaused = false;
157
158 // Worker threads
159 ParticlePerFrameData mSimulationData[CoreThread::NUM_SYNC_BUFFERS];
160
161 UINT32 mReadBufferIdx = 1;
162 UINT32 mWriteBufferIdx = 0;
163
164 Signal mWorkerDoneSignal;
165 Mutex mMutex;
166
167 UINT32 mNumActiveWorkers = 0;
168 bool mSwapBuffers = false;
169 };
170
171 /** @} */
172}
173