diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/libjin/graphics/particles/je_particle.cpp | 154 | ||||
-rw-r--r-- | src/libjin/graphics/particles/je_particle.h | 136 | ||||
-rw-r--r-- | src/libjin/graphics/particles/je_particle_emitter.cpp | 35 | ||||
-rw-r--r-- | src/libjin/graphics/particles/je_particle_emitter.h | 4 | ||||
-rw-r--r-- | src/libjin/graphics/particles/je_particle_system.cpp | 157 | ||||
-rw-r--r-- | src/libjin/graphics/particles/je_particle_system.h | 61 |
6 files changed, 443 insertions, 104 deletions
diff --git a/src/libjin/graphics/particles/je_particle.cpp b/src/libjin/graphics/particles/je_particle.cpp index 1fa8bc2..761f166 100644 --- a/src/libjin/graphics/particles/je_particle.cpp +++ b/src/libjin/graphics/particles/je_particle.cpp @@ -1,4 +1,6 @@ +#include "../../common/je_array.hpp" #include "../../math/je_math.h" +#include "../../math/je_random.h" #include "../je_sprite.h" @@ -13,57 +15,158 @@ namespace JinEngine namespace Particles { - Particle::Particle(const Sprite* spr) - : sprite(spr) + static RandomGenerator rng(0xEA44944); + + ////////////////////////////////////////////////////////////////////////////////////////////////////// + // ScaledRangedValue + ////////////////////////////////////////////////////////////////////////////////////////////////////// + + ScaledRangedValue::ScaledRangedValue(Percentage* points, uint n) + { + for (int i = 0; i < n; ++i) + { + float x = points[2 * i].value; + float y = points[2 * i + 1].value; + addPoint(x, y); + } + } + + void ScaledRangedValue::set(Math::Percentage* points, uint n) + { + clear(); + for (int i = 0; i < n; ++i) + { + float x = points[2 * i].value; + float y = points[2 * i + 1].value; + addPoint(x, y); + } + } + + ////////////////////////////////////////////////////////////////////////////////////////////////////// + // GradientColorValue + ////////////////////////////////////////////////////////////////////////////////////////////////////// + + GradientColorValue::GradientColorValue() + : mCount(0) + { + } + + void GradientColorValue::addColor(Color col, Percentage time) + { + mColors.push_back(col); + mTimeline.push_back(time); + ++mCount; + } + + Color GradientColorValue::getColor(Percentage time) + { + int endIndex = -1; + int n = mCount; + for (int i = 1; i < n; i++) { + Percentage t = mTimeline[i]; + if (t.value > time.value) { + endIndex = i; + break; + } + } + if (endIndex == -1) return mColors[n - 1]; + int startIndex = endIndex - 1; + Color& startValue = mColors[startIndex]; + Color& endValue = mColors[endIndex]; + float t = time.value; + float start = mTimeline[startIndex].value; + float end = mTimeline[endIndex].value; + Color c; + c.r = startValue.r + (endValue.r - startValue.r) * ((t - start) / (end - start)); + c.g = startValue.g + (endValue.g - startValue.g) * ((t - start) / (end - start)); + c.b = startValue.b + (endValue.b - startValue.b) * ((t - start) / (end - start)); + c.a = startValue.a + (endValue.a - startValue.a) * ((t - start) / (end - start)); + return c; + } + + void GradientColorValue::insertColor(uint i, Color col, Math::Percentage time) + { + mColors.insert(mColors.begin() + i, col); + mTimeline.insert(mTimeline.begin() + i, time); + ++mCount; + } + + void GradientColorValue::removeColor(uint i) + { + mColors.erase(mColors.begin() + i); + mTimeline.erase(mTimeline.begin() + i); + --mCount; + } + + ////////////////////////////////////////////////////////////////////////////////////////////////////// + // Particle + ////////////////////////////////////////////////////////////////////////////////////////////////////// + + Particle::Particle() { reset(); } void Particle::reset() { + updateFlags = ParticleUpdateMask::NONE; transform.set(0, 0, 1, 1, 0, 0, 0); lifeTime = 1.0f; life = 0.0f; - speed.set(0, 0); + velocity.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; + spriteIndex = 0; } 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. + if ((updateFlags & UPDATE_COLOR) != 0) + color = def->colorDef.overTime.value.getColor(t); + if ((updateFlags & UPDATE_SCALE) != 0) + { + // Lerp scale. + float scale = def->scaleDef.overTime.value.getValue(t); + transform.setScale(scale, scale); + } + if ((updateFlags & UPDATE_POSITION) != 0) + { + // Calculate position. + if((updateFlags & UPDATE_VELOCITY) != 0) + velocity += linearAcceleration * dt; + transform.move(velocity * dt); + } + if ((updateFlags & UPDATE_ROTATION) != 0) + { + // Calculate rotation. + angularSpeed += radialAcceleration * dt; + transform.rotate(angularSpeed * dt); + } + if ((updateFlags & UPDATE_SPRITE) != 0) + { + int n = def->spritesDef.sprites.size(); + if (def->spritesDef.mode == SpriteMode::ANIMATED) + spriteIndex = lerp<int>(0, n - 1, t); + else + spriteIndex = rng.rand(0, n); + } life += dt; alive = life < lifeTime; } void Particle::render() { + // Set blend. + OpenGL::BlendMode blend = gl.getBlendMode(); + if(def->blendDef.additive) + gl.setBlendMode(OpenGL::BlendMode::ADDITIVE); Color c = gl.getColor(); gl.setColor(color); + const Sprite* sprite = def->spritesDef.sprites[spriteIndex]; if (sprite != nullptr) { Vector2<float>& position = transform.getPosition(); @@ -71,7 +174,8 @@ namespace JinEngine float r = transform.getRotation(); sprite->render(position.x, position.y, scale.x, scale.y, r); } - gl.getColor(); + gl.setColor(c); + gl.setBlendMode(blend); } } diff --git a/src/libjin/graphics/particles/je_particle.h b/src/libjin/graphics/particles/je_particle.h index 8012024..1efdc11 100644 --- a/src/libjin/graphics/particles/je_particle.h +++ b/src/libjin/graphics/particles/je_particle.h @@ -1,8 +1,12 @@ #ifndef __JE_PARTICLE_H__ #define __JE_PARTICLE_H__ +#include "../../game/je_gameobject.h" +#include "../../math/je_ranged_value.h" #include "../../math/je_transform.h" #include "../../math/je_vector2.hpp" +#include "../../math/je_percentage.h" + #include "../je_color.h" #include "../je_sprite.h" @@ -15,8 +19,34 @@ namespace JinEngine class ParticleEmitter; + class ScaledRangedValue : public Math::RangedValue + { + public: + ScaledRangedValue() {}; + ScaledRangedValue(Math::Percentage* points, uint n); + void set(Math::Percentage* points, uint n); + + }; + + class GradientColorValue + { + public: + GradientColorValue(); + + void addColor(Color col, Math::Percentage time); + Color getColor(Math::Percentage time); + void insertColor(uint i, Color col, Math::Percentage time); + void removeColor(uint i); + + private: + std::vector<Color> mColors; + std::vector<Math::Percentage> mTimeline; + uint mCount; + + }; + /// - /// + /// /// struct LifeTimeDef { @@ -30,18 +60,22 @@ namespace JinEngine ); }; - struct ScaleOverTimeDef + struct ScaleDef { - bool enable = false; - float start = 1; - float end = 1; + float scale = 1; + Struct(overTime, + bool enable = false; + ScaledRangedValue value; + ); }; - struct ColorOverTimeDef + struct ColorDef { - bool enable = false; - Color colorStart = Color::WHITE; - Color colorEnd = Color::WHITE; + Color color = Color::WHITE; + Struct(overTime, + bool enable = false; + GradientColorValue value; + ); }; struct linearAccelarationDef @@ -67,35 +101,68 @@ namespace JinEngine ); }; + enum SpriteMode + { + SINGLE = 1, + RANDOM = 2, + ANIMATED = 3, + }; + + struct SpritesDef + { + SpriteMode mode = SpriteMode::SINGLE; + std::vector<const Sprite*> sprites; + }; + + struct BlendDef + { + bool additive = false; + }; + /// - /// + /// /// struct ParticleDef { - private: - friend class ParticleEmitter; - public: // Basic definitions. LifeTimeDef lifeTimeDef; ///< linearAccelarationDef linearAccelarationDef; ///< RadialAccelarationDef radialAccelarationDef; ///< AngularSpeedDef angularSpeedDef; ///< + SpritesDef spritesDef; ///< + BlendDef blendDef; ///< // Optional definitions. - ScaleOverTimeDef sizeOverTimeDef; ///< - ColorOverTimeDef colorOverTimeDef; ///< + ScaleDef scaleDef; ///< + ColorDef colorDef; ///< + + private: + friend class ParticleEmitter; + }; /// /// A single particle contains various properties of particle, such as position, accelaration, color /// and other attributes changed over time. /// - struct Particle : public IRenderable + class Particle : public IRenderable, public Game::GameObject { + public: + enum ParticleUpdateMask + { + NONE = 0, + UPDATE_COLOR = 1 << 0, + UPDATE_SCALE = 1 << 1, + UPDATE_POSITION = 1 << 2, + UPDATE_ROTATION = 1 << 3, + UPDATE_SPRITE = 1 << 4, + UPDATE_VELOCITY = 1 << 5, + }; + /// /// Default constructor. /// - Particle(const Sprite* sprite); + Particle(); /// /// Reset to default. @@ -114,47 +181,26 @@ namespace JinEngine ////////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// Whole life time. - /// + ParticleDef* def; + + uint updateFlags = ParticleUpdateMask::NONE; + float lifeTime = 1.0f; - /// - /// Current life time. - /// float life = 0.0f; - const Sprite* sprite; + int spriteIndex = 0; - /// - /// 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> velocity; 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; }; diff --git a/src/libjin/graphics/particles/je_particle_emitter.cpp b/src/libjin/graphics/particles/je_particle_emitter.cpp index de5ef5d..533bbf4 100644 --- a/src/libjin/graphics/particles/je_particle_emitter.cpp +++ b/src/libjin/graphics/particles/je_particle_emitter.cpp @@ -49,6 +49,7 @@ namespace JinEngine if (p == nullptr) return; p->reset(); + p->def = &mPDef; // Init position. if (mDef.positionDef.enableRandom) { @@ -66,19 +67,22 @@ namespace JinEngine r = rng.randf(mDef.directionDef.direction.random.floor, mDef.directionDef.direction.random.ceil, ACCURACY_4); else r = mDef.directionDef.direction.direction; - float f = 0; + 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)); + p->velocity.set(f*cos(r), f*sin(r)); + if (f != 0) p->updateFlags |= Particle::UPDATE_POSITION; // Init life time. if (mPDef.lifeTimeDef.enableRandom) - p->lifeTime = rng.randf(mPDef.lifeTimeDef.life.random.floor, mPDef.lifeTimeDef.life.random.floor, ACCURACY_4); + p->lifeTime = rng.randf(mPDef.lifeTimeDef.life.random.floor, mPDef.lifeTimeDef.life.random.ceil, ACCURACY_4); else p->lifeTime = mPDef.lifeTimeDef.life.life; // Init linear accelaration. p->linearAcceleration = mPDef.linearAccelarationDef.linearAccelaration; + if(!p->linearAcceleration.isZero()) + p->updateFlags |= (Particle::UPDATE_VELOCITY | Particle::UPDATE_POSITION); // Init angular accelaration. p->radialAcceleration = mPDef.radialAccelarationDef.radialAccelaration; // Init Angular speed. @@ -86,18 +90,21 @@ namespace JinEngine p->angularSpeed = rng.randf(mPDef.angularSpeedDef.angularSpeed.random.floor, mPDef.angularSpeedDef.angularSpeed.random.ceil, ACCURACY_4); else p->angularSpeed = mPDef.angularSpeedDef.angularSpeed.angularSpeed; + if (p->angularSpeed != 0) + p->updateFlags |= Particle::UPDATE_ROTATION; // 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; - } + if (mPDef.scaleDef.overTime.enable) + p->updateFlags |= Particle::UPDATE_SCALE; + else + p->transform.setScale(mPDef.scaleDef.scale, mPDef.scaleDef.scale); + // Color over time. + if (mPDef.colorDef.overTime.enable) + p->updateFlags |= Particle::UPDATE_COLOR; + else + p->color = mPDef.colorDef.color; + // Sprite + if (mPDef.spritesDef.mode != SpriteMode::SINGLE) + p->updateFlags |= Particle::UPDATE_SPRITE; } } diff --git a/src/libjin/graphics/particles/je_particle_emitter.h b/src/libjin/graphics/particles/je_particle_emitter.h index 44bd1fb..03f83be 100644 --- a/src/libjin/graphics/particles/je_particle_emitter.h +++ b/src/libjin/graphics/particles/je_particle_emitter.h @@ -107,9 +107,9 @@ namespace JinEngine /// ParticleSystem& mPS; - const ParticleEmitterDef& mDef; + ParticleEmitterDef& mDef; - const ParticleDef& mPDef; + ParticleDef& mPDef; /// /// Emit particle according to emitter definition and particle definition, particle system should diff --git a/src/libjin/graphics/particles/je_particle_system.cpp b/src/libjin/graphics/particles/je_particle_system.cpp index dcb84dd..d16b918 100644 --- a/src/libjin/graphics/particles/je_particle_system.cpp +++ b/src/libjin/graphics/particles/je_particle_system.cpp @@ -48,14 +48,9 @@ namespace JinEngine p->render(); } - void ParticleSystem::setSprite(const Sprite* sprite) - { - mSprite = sprite; - } - Particle* ParticleSystem::claim() { - Particle* p = new (mParticlePool.GetNextWithoutInitializing()) Particle(mSprite); + Particle* p = new (mParticlePool.GetNextWithoutInitializing()) Particle(); mAliveParticles.push_back(p); return p; } @@ -68,6 +63,156 @@ namespace JinEngine mParticlePool.Delete(p); } + ////////////////////////////////////////////////////////////////////////////////////////////////////// + // Particle Emitter modification. + ////////////////////////////////////////////////////////////////////////////////////////////////////// + + void ParticleSystem::setEmitRate(float floor, float ceil) + { + mDef.emitterDef.emitRateDef.enableRandom = true; + mDef.emitterDef.emitRateDef.rate.random.floor = floor; + mDef.emitterDef.emitRateDef.rate.random.ceil = ceil; + } + + void ParticleSystem::setEmitRate(float rate) + { + mDef.emitterDef.emitRateDef.enableRandom = false; + mDef.emitterDef.emitRateDef.rate.rate = rate; + } + + void ParticleSystem::setEmitForce(float floor, float ceil) + { + mDef.emitterDef.forceDef.enableRandom = true; + mDef.emitterDef.forceDef.force.random.floor = floor; + mDef.emitterDef.forceDef.force.random.ceil = ceil; + } + + void ParticleSystem::setEmitForce(float force) + { + mDef.emitterDef.forceDef.enableRandom = false; + mDef.emitterDef.forceDef.force.force = force; + } + + void ParticleSystem::setEmitDirection(float floor, float ceil) + { + mDef.emitterDef.directionDef.enableRandom = true; + mDef.emitterDef.directionDef.direction.random.floor = floor; + mDef.emitterDef.directionDef.direction.random.ceil = ceil; + } + + void ParticleSystem::setEmitDirection(float dir) + { + mDef.emitterDef.directionDef.enableRandom = false; + mDef.emitterDef.directionDef.direction.direction = dir; + } + + void ParticleSystem::setEmitPosition(const Math::Vector2<float>& floor, const Math::Vector2<float>& ceil) + { + mDef.emitterDef.positionDef.enableRandom = true; + mDef.emitterDef.positionDef.position.random.floor = floor; + mDef.emitterDef.positionDef.position.random.ceil = ceil; + } + + void ParticleSystem::setEmitPosition(const Math::Vector2<float>& position) + { + mDef.emitterDef.positionDef.enableRandom = false; + mDef.emitterDef.positionDef.position.position = position; + } + + ////////////////////////////////////////////////////////////////////////////////////////////////////// + // Particle Emitter modification. + ////////////////////////////////////////////////////////////////////////////////////////////////////// + + void ParticleSystem::setParticleLife(float floor, float ceil) + { + mDef.particleDef.lifeTimeDef.enableRandom = true; + mDef.particleDef.lifeTimeDef.life.random.floor = floor; + mDef.particleDef.lifeTimeDef.life.random.ceil = ceil; + } + + void ParticleSystem::setParticleLife(float time) + { + mDef.particleDef.lifeTimeDef.enableRandom = true; + mDef.particleDef.lifeTimeDef.life.life = time; + } + + void ParticleSystem::setParticleLinearAccelaration(Math::Vector2<float> ac) + { + mDef.particleDef.linearAccelarationDef.linearAccelaration = ac; + } + + void ParticleSystem::setParticleRadialAccelaration(float ra) + { + mDef.particleDef.radialAccelarationDef.radialAccelaration = ra; + } + + void ParticleSystem::setParticleAngularSpeed(float floor, float ceil) + { + mDef.particleDef.angularSpeedDef.enableRandom = true; + mDef.particleDef.angularSpeedDef.angularSpeed.random.floor = floor; + mDef.particleDef.angularSpeedDef.angularSpeed.random.ceil = ceil; + } + + void ParticleSystem::setParticleAngularSpeed(float speed) + { + mDef.particleDef.angularSpeedDef.enableRandom = false; + mDef.particleDef.angularSpeedDef.angularSpeed.angularSpeed = speed; + } + + void ParticleSystem::setParticleSpritesMode(SpriteMode mode) + { + mDef.particleDef.spritesDef.mode = mode; + } + + void ParticleSystem::addParticleSprites(const Sprite* sprite) + { + mDef.particleDef.spritesDef.sprites.push_back(sprite); + } + + void ParticleSystem::removeParticleSprite(uint i) + { + mDef.particleDef.spritesDef.sprites.erase(mDef.particleDef.spritesDef.sprites.begin() + i); + } + + void ParticleSystem::enableParticleBlendAdditive(bool enable) + { + mDef.particleDef.blendDef.additive = enable; + } + + void ParticleSystem::setParticleScale(float scale) + { + mDef.particleDef.scaleDef.overTime.enable = false; + mDef.particleDef.scaleDef.scale = scale; + } + + void ParticleSystem::addParticleScalePoint(float scale, float t) + { + mDef.particleDef.scaleDef.overTime.enable = true; + mDef.particleDef.scaleDef.overTime.value.addPoint(t, scale); + } + + void ParticleSystem::removeParticleScalePoint(uint i) + { + mDef.particleDef.scaleDef.overTime.value.removePoint(i); + } + + void ParticleSystem::setParticleColor(Color color) + { + mDef.particleDef.colorDef.overTime.enable = false; + mDef.particleDef.colorDef.color = color; + } + + void ParticleSystem::addParticleColorPoint(Color color, float t) + { + mDef.particleDef.colorDef.overTime.enable = true; + mDef.particleDef.colorDef.overTime.value.addColor(color, t); + } + + void ParticleSystem::removeParticleColorPoint(uint i) + { + mDef.particleDef.colorDef.overTime.value.removeColor(i); + } + } } }
\ 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 index 614ee7c..1a07588 100644 --- a/src/libjin/graphics/particles/je_particle_system.h +++ b/src/libjin/graphics/particles/je_particle_system.h @@ -33,7 +33,7 @@ namespace JinEngine /// /// Particle emitter, handle all particles it emitts. /// - class ParticleSystem : public IRenderable + class ParticleSystem : public IRenderable, public Game::GameObject { public: /// @@ -59,16 +59,14 @@ namespace JinEngine void render(); /// - /// Set sprite to render. - /// - /// @param sprite Sprite to render. + /// Set particle system position. /// - void setSprite(const Sprite* sprite); + void setPosition(float x, float y); /// - /// Set particle system position. + /// Set scale. /// - void setPosition(float x, float y); + void setScale(float sx, float sy); /// /// Pause particle spawn. @@ -80,6 +78,50 @@ namespace JinEngine /// void clear(); + ////////////////////////////////////////////////////////////////////////////////////////////////// + // Particle Emitter modification. + ////////////////////////////////////////////////////////////////////////////////////////////////// + + void setEmitRate(float floor, float ceil); + void setEmitRate(float rate); + + void setEmitForce(float floor, float ceil); + void setEmitForce(float force); + + void setEmitDirection(float floor, float ceil); + void setEmitDirection(float dir); + + void setEmitPosition(const Math::Vector2<float>& floor, const Math::Vector2<float>& ceil); + void setEmitPosition(const Math::Vector2<float>& position); + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // Particle Emitter modification. + ////////////////////////////////////////////////////////////////////////////////////////////////// + + void setParticleLife(float floor, float ceil); + void setParticleLife(float time); + + void setParticleLinearAccelaration(Math::Vector2<float> ac); + + void setParticleRadialAccelaration(float ra); + + void setParticleAngularSpeed(float floor, float ceil); + void setParticleAngularSpeed(float speed); + + void setParticleSpritesMode(SpriteMode mode); + void addParticleSprites(const Sprite* sprite); + void removeParticleSprite(uint i); + + void enableParticleBlendAdditive(bool enable); + + void setParticleScale(float scale); + void addParticleScalePoint(float scale, float t); + void removeParticleScalePoint(uint i); + + void setParticleColor(Color color); + void addParticleColorPoint(Color color, float t); + void removeParticleColorPoint(uint i); + private: friend class ParticleEmitter; @@ -107,11 +149,6 @@ namespace JinEngine ParticleSystemDef mDef; /// - /// Sprite to be drawn. - /// - const Sprite* mSprite; - - /// /// Particle emitter. /// ParticleEmitter mEmitter; |