Skip to content

Instantly share code, notes, and snippets.

@fenbf
Created April 27, 2014 05:47
Show Gist options
  • Save fenbf/11338457 to your computer and use it in GitHub Desktop.
Save fenbf/11338457 to your computer and use it in GitHub Desktop.
Basic Particle classes design. Used as a starting point for my particle system. More details http://www.bfilipek.com
#include "particles.h"
#include <assert.h>
#include <algorithm>
namespace particles
{
void ParticleData::generate(size_t maxSize)
{
m_count = maxSize;
m_countAlive = 0;
m_pos.reset(new glm::vec4[maxSize]);
m_col.reset(new glm::vec4[maxSize]);
m_startCol.reset(new glm::vec4[maxSize]);
m_endCol.reset(new glm::vec4[maxSize]);
m_vel.reset(new glm::vec4[maxSize]);
m_acc.reset(new glm::vec4[maxSize]);
m_time.reset(new glm::vec4[maxSize]);
m_alive.reset(new bool[maxSize]);
}
void ParticleData::kill(size_t id)
{
if (m_countAlive > 0) // maybe this if can be removed?
{
m_alive[id] = false;
swapData(id, m_countAlive - 1);
m_countAlive--;
}
}
void ParticleData::wake(size_t id)
{
if (m_countAlive < m_count) // maybe this if can be removed?
{
m_alive[id] = true;
swapData(id, m_countAlive);
m_countAlive++;
}
}
void ParticleData::swapData(size_t a, size_t b)
{
std::swap(m_pos[a], m_pos[b]);
std::swap(m_col[a], m_col[b]);
std::swap(m_startCol[a], m_startCol[b]);
std::swap(m_endCol[a], m_endCol[b]);
std::swap(m_vel[a], m_vel[b]);
std::swap(m_acc[a], m_acc[b]);
std::swap(m_time[a], m_time[b]);
std::swap(m_alive[a], m_alive[b]);
}
////////////////////////////////////////////////////////////////////////////////
// ParticleEmitter class
void ParticleEmitter::emit(double dt, ParticleData *p)
{
const size_t maxNewParticles = static_cast<size_t>(dt*m_emitRate);
const size_t startId = p->m_countAlive;
const size_t endId = std::min(startId + maxNewParticles, p->m_count-1);
for (auto &gen : m_generators)
gen->generate(dt, p, startId, endId);
for (size_t i = startId; i < endId; ++i)
{
p->wake(i);
}
}
////////////////////////////////////////////////////////////////////////////////
// ParticleSystem class
////////////////////////////////////////////////////////////////////////////////
ParticleSystem::ParticleSystem(size_t maxCount)
{
m_count = maxCount;
m_particles.generate(maxCount);
m_aliveParticles.generate(maxCount);
for (size_t i = 0; i < maxCount; ++i)
m_particles.m_alive[i] = false;
}
void ParticleSystem::update(double dt)
{
for (auto & em : m_emitters)
{
em->emit(dt, &m_particles);
}
for (size_t i = 0; i < m_count; ++i)
{
m_particles.m_acc[i] = glm::vec4(0.0f);
}
for (auto & up : m_updaters)
{
up->update(dt, &m_particles);
}
//ParticleData::copyOnlyAlive(&m_particles, &m_aliveParticles);
}
void ParticleSystem::reset()
{
m_particles.m_countAlive = 0;
}
size_t ParticleSystem::computeMemoryUsage(const ParticleSystem &p)
{
return 2 * ParticleData::computeMemoryUsage(p.m_particles);
}
}
#pragma once
#include <vector>
#include <memory>
#include <glm/vec4.hpp>
namespace particles
{
class ParticleData
{
public:
std::unique_ptr<glm::vec4[]> m_pos;
std::unique_ptr<glm::vec4[]> m_col;
std::unique_ptr<glm::vec4[]> m_startCol;
std::unique_ptr<glm::vec4[]> m_endCol;
std::unique_ptr<glm::vec4[]> m_vel;
std::unique_ptr<glm::vec4[]> m_acc;
std::unique_ptr<glm::vec4[]> m_time;
std::unique_ptr<bool[]> m_alive;
size_t m_count{ 0 };
size_t m_countAlive{ 0 };
public:
ParticleData() { }
explicit ParticleData(size_t maxCount) { generate(maxCount); }
~ParticleData() { }
ParticleData(const ParticleData &) = delete;
ParticleData &operator=(const ParticleData &) = delete;
void generate(size_t maxSize);
void kill(size_t id);
void wake(size_t id);
void swapData(size_t a, size_t b);
};
class ParticleGenerator
{
public:
ParticleGenerator() { }
virtual ~ParticleGenerator() { }
virtual void generate(double dt, ParticleData *p, size_t startId, size_t endId) = 0;
};
class ParticleEmitter
{
protected:
std::vector<std::shared_ptr<ParticleGenerator>> m_generators;
public:
float m_emitRate{ 0.0 };
public:
ParticleEmitter() { }
virtual ~ParticleEmitter() { }
// calls all the generators and at the end it activates (wakes) particle
virtual void emit(double dt, ParticleData *p);
void addGenerator(std::shared_ptr<ParticleGenerator> gen) { m_generators.push_back(gen); }
};
class ParticleUpdater
{
public:
ParticleUpdater() { }
virtual ~ParticleUpdater() { }
virtual void update(double dt, ParticleData *p) = 0;
};
class ParticleSystem
{
protected:
ParticleData m_particles;
ParticleData m_aliveParticles;
size_t m_count;
std::vector<std::shared_ptr<ParticleEmitter>> m_emitters;
std::vector<std::shared_ptr<ParticleUpdater>> m_updaters;
public:
explicit ParticleSystem(size_t maxCount);
virtual ~ParticleSystem() { }
ParticleSystem(const ParticleSystem &) = delete;
ParticleSystem &operator=(const ParticleSystem &) = delete;
virtual void update(double dt);
virtual void reset();
virtual size_t numAllParticles() const { return m_particles.m_count; }
virtual size_t numAliveParticles() const { return m_particles.m_countAlive; }
void addEmitter(std::shared_ptr<ParticleEmitter> em) { m_emitters.push_back(em); }
void addUpdater(std::shared_ptr<ParticleUpdater> up) { m_updaters.push_back(up); }
ParticleData *finalData() { return &m_particles; }
static size_t computeMemoryUsage(const ParticleSystem &p);
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment