aboutsummaryrefslogtreecommitdiff
path: root/src/libjin/graphics/particles
diff options
context:
space:
mode:
Diffstat (limited to 'src/libjin/graphics/particles')
-rw-r--r--src/libjin/graphics/particles/je_particle.cpp72
-rw-r--r--src/libjin/graphics/particles/je_particle.h166
-rw-r--r--src/libjin/graphics/particles/je_particle_emitter.cpp105
-rw-r--r--src/libjin/graphics/particles/je_particle_emitter.h136
-rw-r--r--src/libjin/graphics/particles/je_particle_pool.h24
-rw-r--r--src/libjin/graphics/particles/je_particle_system.cpp67
-rw-r--r--src/libjin/graphics/particles/je_particle_system.h115
7 files changed, 685 insertions, 0 deletions
diff --git a/src/libjin/graphics/particles/je_particle.cpp b/src/libjin/graphics/particles/je_particle.cpp
new file mode 100644
index 0000000..53f4570
--- /dev/null
+++ b/src/libjin/graphics/particles/je_particle.cpp
@@ -0,0 +1,72 @@
+#include "../../math/je_math.h"
+
+#include "je_particle.h"
+
+using namespace JinEngine::Math;
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+ namespace Particles
+ {
+
+ Particle::Particle(const Graphic* grc)
+ : graphic(grc)
+ {
+ reset();
+ }
+
+ void Particle::reset()
+ {
+ transform.set(0, 0, 1, 1, 0, 0, 0);
+ lifeTime = 1.0f;
+ life = 0.0f;
+ speed.set(0, 0);
+ linearAcceleration.set(0, 0);
+ radialAcceleration = 0.0f;
+ angularSpeed = 0;
+ scaleBegin = 1;
+ scaleEnd = 1;
+ color = Color::WHITE;
+ colorStart = Color::WHITE;
+ colorEnd = Color::WHITE;
+ alive = true;
+ }
+
+ void Particle::update(float dt)
+ {
+ float t = life / lifeTime;
+ // Lerp color
+ color.r = lerp<int>(colorStart.r, colorEnd.r, t);
+ color.g = lerp<int>(colorStart.g, colorEnd.g, t);
+ color.b = lerp<int>(colorStart.b, colorEnd.b, t);
+ color.a = lerp<int>(colorStart.a, colorEnd.a, t);
+ // Lerp scale.
+ Vector2<float> scale = transform.getScale();
+ scale.x = lerp<float>(scaleBegin, scaleEnd, t);
+ scale.y = scale.x;
+ transform.setScale(scale.x, scale.y);
+ // Calculate position.
+ speed += linearAcceleration * dt;
+ transform.move(speed * dt);
+ // Calculate rotation.
+ angularSpeed += radialAcceleration * dt;
+ transform.rotate(angularSpeed * dt);
+ // Update life time.
+ life += dt;
+ alive = life < lifeTime;
+ }
+
+ void Particle::render()
+ {
+ Color c = gl.getColor();
+ gl.setColor(color);
+ if (graphic != nullptr)
+ graphic->render(transform);
+ gl.getColor();
+ }
+
+ }
+ }
+} \ No newline at end of file
diff --git a/src/libjin/graphics/particles/je_particle.h b/src/libjin/graphics/particles/je_particle.h
new file mode 100644
index 0000000..70a2653
--- /dev/null
+++ b/src/libjin/graphics/particles/je_particle.h
@@ -0,0 +1,166 @@
+#ifndef __JE_PARTICLE_H__
+#define __JE_PARTICLE_H__
+
+#include "../../math/je_transform.h"
+#include "../../math/je_vector2.hpp"
+#include "../je_color.h"
+#include "../je_graphic.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+ namespace Particles
+ {
+
+ class ParticleEmitter;
+
+ ///
+ ///
+ ///
+ struct LifeTimeDef
+ {
+ bool enableRandom = false;
+ Struct(life,
+ struct
+ {
+ float floor, ceil;
+ } random;
+ float life = 1.0f;
+ );
+ };
+
+ struct ScaleOverTimeDef
+ {
+ bool enable = false;
+ float start = 1;
+ float end = 1;
+ };
+
+ struct ColorOverTimeDef
+ {
+ bool enable = false;
+ Color colorStart = Color::WHITE;
+ Color colorEnd = Color::WHITE;
+ };
+
+ struct linearAccelarationDef
+ {
+ Math::Vector2<float> linearAccelaration;
+ };
+
+ struct RadialAccelarationDef
+ {
+ float radialAccelaration = 0.f;
+ };
+
+ struct AngularSpeedDef
+ {
+ bool enableRandom = false;
+ Struct(angularSpeed,
+ struct
+ {
+ float floor = 0;
+ float ceil = 0;
+ } random;
+ float angularSpeed = 0;
+ );
+ };
+
+ ///
+ ///
+ ///
+ struct ParticleDef
+ {
+ private:
+ friend class ParticleEmitter;
+
+ public:
+ // Basic definitions.
+ LifeTimeDef lifeTimeDef; ///<
+ linearAccelarationDef linearAccelarationDef; ///<
+ RadialAccelarationDef radialAccelarationDef; ///<
+ AngularSpeedDef angularSpeedDef; ///<
+ // Optional definitions.
+ ScaleOverTimeDef sizeOverTimeDef; ///<
+ ColorOverTimeDef colorOverTimeDef; ///<
+ };
+
+ ///
+ /// A single particle contains various properties of particle, such as position, accelaration, color
+ /// and other attributes changed over time.
+ ///
+ struct Particle
+ {
+ ///
+ /// Default constructor.
+ ///
+ Particle(const Graphic* graphic);
+
+ ///
+ /// Reset to default.
+ ///
+ void reset();
+
+ ///
+ ///
+ ///
+ void update(float dt);
+
+ ///
+ ///
+ ///
+ void render();
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////
+
+ ///
+ /// Whole life time.
+ ///
+ float lifeTime = 1.0f;
+
+ ///
+ /// Current life time.
+ ///
+ float life = 0.0f;
+
+ const Graphic* graphic;
+
+ ///
+ /// Color over lifetime.
+ ///
+ Color color = Color::WHITE;
+ Color colorStart = Color::WHITE;
+ Color colorEnd = Color::WHITE;
+
+ ///
+ /// Position scale rotation origin.
+ ///
+ Math::Transform transform;
+
+ ///
+ /// Speeds.
+ ///
+ Math::Vector2<float> speed;
+ Math::Vector2<float> linearAcceleration;
+ float angularSpeed;
+ float radialAcceleration = 0;
+
+ ///
+ /// Size over lifetime.
+ ///
+ float scaleBegin = 1;
+ float scaleEnd = 1;
+
+ ///
+ /// Is particle still alive? Alive is equivalent to NOT available in particle pool.
+ ///
+ bool alive = true;
+
+ };
+
+ } // namespace Particles
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif \ No newline at end of file
diff --git a/src/libjin/graphics/particles/je_particle_emitter.cpp b/src/libjin/graphics/particles/je_particle_emitter.cpp
new file mode 100644
index 0000000..d8fb78d
--- /dev/null
+++ b/src/libjin/graphics/particles/je_particle_emitter.cpp
@@ -0,0 +1,105 @@
+#include <time.h>
+
+#include "../../math/je_random.h"
+
+#include "je_particle_emitter.h"
+#include "je_particle_system.h"
+
+using namespace JinEngine::Math;
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+ namespace Particles
+ {
+
+ static const uint8 ACCURACY_4 = 4;
+ static const uint8 ACCURACY_5 = 5;
+ static const uint8 ACCURACY_6 = 6;
+
+ // Particle emitter
+ static RandomGenerator rng(0xEA44944);
+
+ ParticleEmitter::ParticleEmitter(ParticleSystem& ps)
+ : mPS(ps)
+ , mDef(ps.mDef.emitterDef)
+ , mPDef(ps.mDef.particleDef)
+ , mTime(0)
+ {
+ }
+
+ void ParticleEmitter::update(float dt)
+ {
+ mTime += dt;
+ for (;mTime >= mInterval; mTime -= mInterval)
+ {
+ emit();
+ // Random rate.
+ if (mDef.emitRateDef.enableRandom)
+ mInterval = rng.randf(mDef.emitRateDef.rate.random.floor, mDef.emitRateDef.rate.random.ceil, ACCURACY_5);
+ else
+ mInterval = mDef.emitRateDef.rate.rate;
+ }
+ }
+
+ void ParticleEmitter::emit()
+ {
+ Particle* p = mPS.claim();
+ if (p == nullptr)
+ return;
+ p->reset();
+ // Init position.
+ if (mDef.positionDef.enableRandom)
+ {
+ float x = rng.randf(mDef.positionDef.position.random.floor.x, mDef.positionDef.position.random.ceil.x, ACCURACY_4);
+ float y = rng.randf(mDef.positionDef.position.random.floor.y, mDef.positionDef.position.random.ceil.y, ACCURACY_4);
+ p->transform.setPosition(x, y);
+ }
+ else
+ {
+ p->transform.setPosition(mDef.positionDef.position.position);
+ }
+ // Init speed.
+ float r = 0;
+ if (mDef.directionDef.enableRandom)
+ r = rng.randf(mDef.directionDef.direction.random.floor, mDef.directionDef.direction.random.ceil, ACCURACY_4);
+ else
+ r = mDef.directionDef.direction.direction;
+ float f = 0;
+ if (mDef.forceDef.enableRandom)
+ f = rng.randf(mDef.forceDef.force.random.floor, mDef.forceDef.force.random.ceil, ACCURACY_4);
+ else
+ f = mDef.forceDef.force.force;
+ p->speed.set(f*cos(r), f*sin(r));
+ // Init life time
+ if (mPDef.lifeTimeDef.enableRandom)
+ p->lifeTime = rng.randf(mPDef.lifeTimeDef.life.random.floor, mPDef.lifeTimeDef.life.random.floor, ACCURACY_4);
+ else
+ p->lifeTime = mPDef.lifeTimeDef.life.life;
+ // Init linear accelaration
+ p->linearAcceleration = mPDef.linearAccelarationDef.linearAccelaration;
+ // Init angular accelaration
+ p->radialAcceleration = mPDef.radialAccelarationDef.radialAccelaration;
+ // Init Angular speed.
+ if (mPDef.angularSpeedDef.enableRandom)
+ p->angularSpeed = rng.randf(mPDef.angularSpeedDef.angularSpeed.random.floor, mPDef.angularSpeedDef.angularSpeed.random.ceil, ACCURACY_4);
+ else
+ p->angularSpeed = mPDef.angularSpeedDef.angularSpeed.angularSpeed;
+ // Scale over time
+ if (mPDef.sizeOverTimeDef.enable)
+ {
+ p->scaleBegin = mPDef.sizeOverTimeDef.start;
+ p->scaleEnd = mPDef.sizeOverTimeDef.end;
+ }
+ // Color over time
+ if (mPDef.colorOverTimeDef.enable)
+ {
+ p->colorStart = mPDef.colorOverTimeDef.colorStart;
+ p->colorEnd = mPDef.colorOverTimeDef.colorEnd;
+ }
+ }
+
+ }
+ }
+} \ No newline at end of file
diff --git a/src/libjin/graphics/particles/je_particle_emitter.h b/src/libjin/graphics/particles/je_particle_emitter.h
new file mode 100644
index 0000000..44bd1fb
--- /dev/null
+++ b/src/libjin/graphics/particles/je_particle_emitter.h
@@ -0,0 +1,136 @@
+#ifndef __JE_PARTICLE_EMITTER_H__
+#define __JE_PARTICLE_EMITTER_H__
+
+#include "../../common/je_temporary.h"
+#include "../../math/je_vector2.hpp"
+
+#include "je_particle.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+ namespace Particles
+ {
+
+ struct PositionDef
+ {
+ bool enableRandom = false;
+ Struct(position,
+ struct
+ {
+ Math::Vector2<float> floor;
+ Math::Vector2<float> ceil;
+ } random;
+ Math::Vector2<float> position;
+ );
+ };
+
+ struct DirectionDef
+ {
+ bool enableRandom = false;
+ Struct(direction,
+ struct
+ {
+ float floor = 0;
+ float ceil = 0;
+ } random;
+ float direction = 0;
+ );
+ };
+
+ ///
+ /// How many particles emitted per second.
+ ///
+ struct EmitRateDef
+ {
+ bool enableRandom = false;
+ Struct(rate,
+ struct
+ {
+ float floor = 1;
+ float ceil = 1;
+ } random;
+ float rate = 1;
+ );
+ };
+
+ ///
+ /// Initial speed of particle.
+ ///
+ struct ForceDef
+ {
+ bool enableRandom = false;
+ Struct(force,
+ struct
+ {
+ float floor = 1;
+ float ceil = 1;
+ } random;
+ float force = 1;
+ );
+ };
+
+ ///
+ /// Definition of particle emitter.
+ ///
+ struct ParticleEmitterDef
+ {
+ EmitRateDef emitRateDef; ///< Emit rate.
+
+ PositionDef positionDef; ///< Emit position(relativily to the particle system center).
+ DirectionDef directionDef; ///< Emit direction.
+ ForceDef forceDef; ///< Emit force.
+ };
+
+ class ParticleSystem;
+
+ ///
+ /// Emit a single particle.
+ ///
+ class ParticleEmitter
+ {
+ public:
+ ///
+ ///
+ ///
+ ParticleEmitter(ParticleSystem& ps);
+
+ ///
+ ///
+ ///
+ void update(float dt);
+
+ private:
+ ///
+ ///
+ ///
+ ParticleSystem& mPS;
+
+ const ParticleEmitterDef& mDef;
+
+ const ParticleDef& mPDef;
+
+ ///
+ /// Emit particle according to emitter definition and particle definition, particle system should
+ /// assign particle value to the particle in particle pool, but not use this return particle.
+ ///
+ void emit();
+
+ ///
+ ///
+ ///
+ float mTime;
+
+ ///
+ ///
+ ///
+ float mInterval;
+
+ };
+
+ } // namespace Particles
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif \ No newline at end of file
diff --git a/src/libjin/graphics/particles/je_particle_pool.h b/src/libjin/graphics/particles/je_particle_pool.h
new file mode 100644
index 0000000..46cd73a
--- /dev/null
+++ b/src/libjin/graphics/particles/je_particle_pool.h
@@ -0,0 +1,24 @@
+#ifndef __JE_PARTICLE_BATCH_H__
+#define __JE_PARTICLE_BATCH_H__
+
+#include "../../common/je_pool.hpp"
+
+#include "je_particle.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+ namespace Particles
+ {
+
+ ///
+ /// Particle pool for reducing memory fragmentation.
+ ///
+ typedef Pool<Particle> ParticlePool;
+
+ } // namespace Particles
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif \ No newline at end of file
diff --git a/src/libjin/graphics/particles/je_particle_system.cpp b/src/libjin/graphics/particles/je_particle_system.cpp
new file mode 100644
index 0000000..a81a3c9
--- /dev/null
+++ b/src/libjin/graphics/particles/je_particle_system.cpp
@@ -0,0 +1,67 @@
+#include "je_particle_system.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+ namespace Particles
+ {
+
+ ParticleSystem::ParticleSystem(const ParticleSystemDef& def)
+ : mDef(def)
+ , mEmitter(*this)
+ , mParticlePool(def.maxParticleCount, sizeof(Particle))
+ {
+ }
+
+ ParticleSystem::~ParticleSystem()
+ {
+ }
+
+ void ParticleSystem::update(float dt)
+ {
+ mEmitter.update(dt);
+ for (int i = 0; i < mAliveParticles.size(); ++i)
+ {
+ Particle* p = mAliveParticles[i];
+ if (p->alive == false)
+ {
+ recycle(i, p);
+ --i;
+ }
+ else
+ {
+ p->update(dt);
+ }
+ }
+ }
+
+ void ParticleSystem::render(float x, float y, float sx /* = 1 */, float sy /* = 1 */, float r /* = 0 */, float ax /* = 0 */, float ay /* = 0 */)
+ {
+ for (Particle* p : mAliveParticles)
+ p->render();
+ }
+
+ void ParticleSystem::setGraphic(const Graphic* graphic)
+ {
+ mGraphic = graphic;
+ }
+
+ Particle* ParticleSystem::claim()
+ {
+ Particle* p = new (mParticlePool.GetNextWithoutInitializing()) Particle(mGraphic);
+ mAliveParticles.push_back(p);
+ return p;
+ }
+
+ void ParticleSystem::recycle(int i, Particle* p)
+ {
+ if (i >= mAliveParticles.size())
+ return;
+ mAliveParticles.erase(mAliveParticles.begin() + i);
+ mParticlePool.Delete(p);
+ }
+
+ }
+ }
+} \ No newline at end of file
diff --git a/src/libjin/graphics/particles/je_particle_system.h b/src/libjin/graphics/particles/je_particle_system.h
new file mode 100644
index 0000000..8ee79ec
--- /dev/null
+++ b/src/libjin/graphics/particles/je_particle_system.h
@@ -0,0 +1,115 @@
+#ifndef __JE_PARTICLE_EMMITTER_H__
+#define __JE_PARTICLE_EMMITTER_H__
+
+#include <vector>
+
+#include "../../common/je_temporary.h"
+#include "../../game/je_gameobject.h"
+
+#include "../je_sprite.h"
+
+#include "je_particle_emitter.h"
+#include "je_particle_pool.h"
+#include "je_particle.h"
+
+namespace JinEngine
+{
+ namespace Graphics
+ {
+ namespace Particles
+ {
+
+ ///
+ /// Definition of particle system.
+ ///
+ struct ParticleSystemDef
+ {
+ ParticleSystemDef() {}
+ uint maxParticleCount = 1; ///< Max count of particles in pool. 1 by default.
+ ParticleEmitterDef emitterDef; ///< Particle emitter definition.
+ ParticleDef particleDef; ///< Particle definition.
+ };
+
+ ///
+ /// Particle emitter, handle all particles it emitts.
+ ///
+ class ParticleSystem/* : public Game::GameObject*/
+ {
+ public:
+ ///
+ /// Particle system constructor
+ ///
+ /// @param def Definition of particle system.
+ ///
+ ParticleSystem(const ParticleSystemDef& def);
+
+ ///
+ /// Particle system destructor.
+ ///
+ ~ParticleSystem();
+
+ ///
+ /// Update particle system and all alive particles.
+ ///
+ void update(float dt);
+
+ ///
+ /// Render particle system.
+ ///
+ void render(float x, float y, float sx = 1, float sy = 1, float r = 0, float ax = 0, float ay = 0);
+
+ ///
+ /// Set sprite to render.
+ ///
+ /// @param sprite Sprite to render.
+ ///
+ void setGraphic(const Graphic* graphic);
+
+ private:
+
+ friend class ParticleEmitter;
+
+ ParticleSystem();
+
+ ///
+ ///
+ ///
+ Particle* claim();
+
+ ///
+ ///
+ ///
+ void recycle(int i, Particle* p);
+
+ ///
+ /// Particle system definition.
+ ///
+ ParticleSystemDef mDef;
+
+ ///
+ /// Sprite to be drawn.
+ ///
+ const Graphic* mGraphic;
+
+ ///
+ /// Particle emitter.
+ ///
+ ParticleEmitter mEmitter;
+
+ ///
+ /// Particle pool.
+ ///
+ ParticlePool mParticlePool;
+
+ ///
+ /// Alive particles, that means these particles could join to the life cycle loop.
+ ///
+ std::vector<Particle*> mAliveParticles;
+
+ };
+
+ } // namespace Particles
+ } // namespace Graphics
+} // namespace JinEngine
+
+#endif \ No newline at end of file