diff options
Diffstat (limited to 'src/libjin/graphics/particles')
-rw-r--r-- | src/libjin/graphics/particles/je_particle.cpp | 72 | ||||
-rw-r--r-- | src/libjin/graphics/particles/je_particle.h | 166 | ||||
-rw-r--r-- | src/libjin/graphics/particles/je_particle_emitter.cpp | 105 | ||||
-rw-r--r-- | src/libjin/graphics/particles/je_particle_emitter.h | 136 | ||||
-rw-r--r-- | src/libjin/graphics/particles/je_particle_pool.h | 24 | ||||
-rw-r--r-- | src/libjin/graphics/particles/je_particle_system.cpp | 67 | ||||
-rw-r--r-- | src/libjin/graphics/particles/je_particle_system.h | 115 |
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 |