1#include <glm/gtc/random.hpp>
2#include <zen/particles/ZEN_ParticleSystem.h>
6 ParticleSystem::ParticleSystem(
size_t maxParticles) : m_max(maxParticles) {
9 m_cpuQuad.resize(m_max * 4);
12 m_vao.reset(VertexArray::Create());
15 m_vbo.reset(VertexBuffer::Create(
nullptr,
16 static_cast<uint32_t
>(m_cpuQuad.size() *
sizeof(QuadVertex))));
18 {ShaderDataType::Float2,
"a_Position"},
19 {ShaderDataType::Float4,
"a_Color" }
22 m_vao->addVertexBuffer(m_vbo);
24 std::vector<uint32_t> indices;
25 indices.reserve(m_max * 6);
26 for (uint32_t i = 0; i < m_max; ++i) {
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);
35 m_ibo.reset(IndexBuffer::Create(indices.data(),
static_cast<uint32_t
>(indices.size())));
36 m_vao->setIndexBuffer(m_ibo);
38 m_shader = std::make_shared<Shader>(
"data/particle.vert",
"data/particle.frag");
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};
48 m_vbo->setData(m_cpuQuad.data(),
static_cast<uint32_t
>(m_cpuQuad.size() *
sizeof(QuadVertex)));
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;
63 m_poolIndex = (m_poolIndex + 1) % m_pool.size();
66 void ParticleSystem::update(DeltaTime deltaTime) {
67 float deltaTimef = deltaTime.seconds();
70 for (
auto &p : m_pool) {
75 p.lifeRemaining -= deltaTimef;
76 if (p.lifeRemaining <= 0.f) {
81 p.pos += p.vel * deltaTimef;
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);
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};
98 void ParticleSystem::upload() {
99 const uint32_t bytes = m_alive * 4 *
sizeof(QuadVertex);
101 m_vbo->setData(m_cpuQuad.data(), bytes);
102 m_ibo->setCount(m_alive * 6);
105 void ParticleSystem::clear() {
106 for (
auto &p : m_pool)
112 void ParticleSystem::updateEmitter(ParticleEmitter &emitter, DeltaTime deltaTime) {
113 float rate = emitter.spawnRate;
114 float period = 1.0f / glm::max(rate, 0.001f);
116 emitter.emitAccumulator += deltaTime.seconds();
117 while (emitter.emitAccumulator > period) {
120 p.position = emitter.pos;
121 glm::vec2 v = sampleVelocityFromBase(emitter.props.velocity, emitter.vRand);
124 emitter.emitAccumulator -= period;
128 void ParticleSystem::updateEmitters(std::vector<ParticleEmitter> &emitters, DeltaTime deltaTime) {
129 for (
auto &e : emitters) {
130 updateEmitter(e, deltaTime);