Zen 0.3.0
Loading...
Searching...
No Matches
ZEN_ParticleSystem.cpp
1#include <glm/gtc/random.hpp>
2#include <zen/particles/ZEN_ParticleSystem.h>
3
4namespace Zen {
5
6 ParticleSystem::ParticleSystem(size_t maxParticles) : m_max(maxParticles) {
7
8 m_pool.resize(m_max);
9 m_cpuQuad.resize(m_max * 4);
10
11 // geometry setup
12 m_vao.reset(VertexArray::Create());
13
14 // dynamic vertex buffer (positions + colors), sized for the full pool
15 m_vbo.reset(VertexBuffer::Create(nullptr,
16 static_cast<uint32_t>(m_cpuQuad.size() * sizeof(QuadVertex))));
17 m_vbo->setLayout({
18 {ShaderDataType::Float2, "a_Position"},
19 {ShaderDataType::Float4, "a_Color" }
20 });
21
22 m_vao->addVertexBuffer(m_vbo);
23
24 std::vector<uint32_t> indices;
25 indices.reserve(m_max * 6);
26 for (uint32_t i = 0; i < m_max; ++i) {
27 uint32_t b = i * 4;
28 indices.push_back(b + 0);
29 indices.push_back(b + 1);
30 indices.push_back(b + 2);
31 indices.push_back(b + 2);
32 indices.push_back(b + 3);
33 indices.push_back(b + 0);
34 }
35 m_ibo.reset(IndexBuffer::Create(indices.data(), static_cast<uint32_t>(indices.size())));
36 m_vao->setIndexBuffer(m_ibo);
37
38 m_shader = std::make_shared<Shader>("data/particle.vert", "data/particle.frag");
39
40 const glm::vec2 deadPos(0.0f);
41 const glm::vec4 deadCol(0.0f);
42 for (uint32_t i = 0; i < m_max; ++i) {
43 QuadVertex *v = &m_cpuQuad[i * 4];
44 v[0] = v[1] = v[2] = v[3] = {deadPos, deadCol};
45 }
46
47 m_vbo->bind();
48 m_vbo->setData(m_cpuQuad.data(), static_cast<uint32_t>(m_cpuQuad.size() * sizeof(QuadVertex)));
49 }
50
51 void ParticleSystem::emit(const ParticleProps &p) {
52 Particle &particle = m_pool[m_poolIndex];
53 particle.active = true;
54 particle.pos = p.position;
55 particle.vel = p.velocity;
56 particle.lifeTime = p.lifeTime;
57 particle.lifeRemaining = p.lifeTime;
58 particle.sizeBegin = p.sizeBegin;
59 particle.sizeEnd = p.sizeEnd;
60 particle.colourBegin = p.colourBegin;
61 particle.colourEnd = p.colourEnd;
62
63 m_poolIndex = (m_poolIndex + 1) % m_pool.size();
64 }
65
66 void ParticleSystem::update(DeltaTime deltaTime) {
67 float deltaTimef = deltaTime.seconds();
68 m_alive = 0;
69
70 for (auto &p : m_pool) {
71 if (!p.active) {
72 continue;
73 }
74
75 p.lifeRemaining -= deltaTimef;
76 if (p.lifeRemaining <= 0.f) {
77 p.active = false;
78 continue;
79 }
80
81 p.pos += p.vel * deltaTimef;
82
83 float t = 1.0f - (p.lifeRemaining / p.lifeTime);
84 float size = glm::mix(p.sizeBegin, p.sizeEnd, t);
85 glm::vec4 c = glm::mix(p.colourBegin, p.colourEnd, t);
86
87 glm::vec2 h(size * 0.5f);
88 QuadVertex *v = &m_cpuQuad[m_alive * 4];
89 v[0] = {p.pos + glm::vec2(-h.x, -h.y), c};
90 v[1] = {p.pos + glm::vec2(+h.x, -h.y), c};
91 v[2] = {p.pos + glm::vec2(+h.x, +h.y), c};
92 v[3] = {p.pos + glm::vec2(-h.x, +h.y), c};
93
94 ++m_alive;
95 }
96 }
97
98 void ParticleSystem::upload() {
99 const uint32_t bytes = m_alive * 4 * sizeof(QuadVertex);
100 m_vbo->bind();
101 m_vbo->setData(m_cpuQuad.data(), bytes);
102 m_ibo->setCount(m_alive * 6); // key line
103 }
104
105 void ParticleSystem::clear() {
106 for (auto &p : m_pool)
107 p.active = false;
108
109 m_alive = 0;
110 }
111
112 void ParticleSystem::updateEmitter(ParticleEmitter &emitter, DeltaTime deltaTime) {
113 float rate = emitter.spawnRate;
114 float period = 1.0f / glm::max(rate, 0.001f);
115
116 emitter.emitAccumulator += deltaTime.seconds();
117 while (emitter.emitAccumulator > period) {
118 Zen::ParticleProps p = emitter.props;
119
120 p.position = emitter.pos;
121 glm::vec2 v = sampleVelocityFromBase(emitter.props.velocity, emitter.vRand);
122 p.velocity = v;
123 emit(p);
124 emitter.emitAccumulator -= period;
125 }
126 }
127
128 void ParticleSystem::updateEmitters(std::vector<ParticleEmitter> &emitters, DeltaTime deltaTime) {
129 for (auto &e : emitters) {
130 updateEmitter(e, deltaTime);
131 }
132 }
133} // namespace Zen