diff --git a/src/framework/const.h b/src/framework/const.h index 05951fb6..1921afa5 100644 --- a/src/framework/const.h +++ b/src/framework/const.h @@ -180,7 +180,8 @@ namespace Fw enum BlendFunc { BlendDefault, - BlendColorzing + BlendColorzing, + BlendParticles }; enum AspectRatioMode { diff --git a/src/framework/graphics/graphics.cpp b/src/framework/graphics/graphics.cpp index d768b568..3033e4bb 100644 --- a/src/framework/graphics/graphics.cpp +++ b/src/framework/graphics/graphics.cpp @@ -317,6 +317,9 @@ void Graphics::bindBlendFunc(Fw::BlendFunc blendType) case Fw::BlendColorzing: glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); break; + case Fw::BlendParticles: + glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ONE); + break; } } diff --git a/src/framework/graphics/particlessystem.cpp b/src/framework/graphics/particlessystem.cpp index e5ca4ae9..9bce62c0 100644 --- a/src/framework/graphics/particlessystem.cpp +++ b/src/framework/graphics/particlessystem.cpp @@ -1,6 +1,8 @@ #include "particlessystem.h" #include "graphics.h" #include +#include +#include Particle::Particle(const Rect& rect, float vx, float vy, float ax, float ay, float duration, const Color& color, TexturePtr texture) { @@ -17,7 +19,7 @@ Particle::Particle(const Rect& rect, float vx, float vy, float ax, float ay, flo Particle::~Particle() { - //dump << "deleted"; + dump << "deleted"; } void Particle::render() @@ -26,8 +28,11 @@ void Particle::render() if(!m_texture) g_graphics.drawFilledRect(m_rect); - else + else { + g_graphics.bindBlendFunc(Fw::BlendParticles); g_graphics.drawTexturedRect(m_rect, m_texture); + g_graphics.bindBlendFunc(Fw::BlendDefault); + } } void Particle::update() @@ -35,17 +40,17 @@ void Particle::update() ticks_t t = g_clock.ticks() - m_startTicks; // check if finished - if(m_duration > 0 && t > m_duration * 1000) { + if(m_duration >= 0 && t > m_duration * 1000) { m_finished = true; return; } //update position - m_rect.moveTo(m_ix + (m_vx * t / 1000.0) + (m_ax * t*t / 2000.0), - m_iy + (m_vy * t / 1000.0) + (m_ay * t*t / 2000.0)); + m_rect.moveTo(m_ix + (m_vx * t / 1000.0) + (m_ax * t*t / (2.0 * 1000 * 1000)), + m_iy + (m_vy * t / 1000.0) + (m_ay * t*t / (2.0 * 1000 * 1000))); } -Emitter::Emitter(const Point& position, float duration, int particlesPerSecond) +ParticleEmitter::ParticleEmitter(const Point& position, float duration, int particlesPerSecond) { m_position = position; m_duration = duration; @@ -53,44 +58,67 @@ Emitter::Emitter(const Point& position, float duration, int particlesPerSecond) m_createdParticles = 0; m_startTicks = g_clock.ticks(); m_finished = false; + + // particles default configuration. (make them reasonable detect missing properties on scripts) + m_pPositionMinRadius = 0; m_pPositionMaxRadius = 3; + m_pPositionMinAngle = 0; m_pPositionMaxAngle = 90; + m_pMinSize = Size(32, 32); m_pMaxSize = Size(32, 32); + m_pMinDuration = 0; m_pMaxDuration = 10; } -void Emitter::render() +void ParticleEmitter::render() { + // testing + //g_graphics.bindColor(Color(255, 255, 255)); + //g_graphics.drawFilledRect(Rect(0, 0, 400, 400)); + for(auto it = m_particles.begin(), end = m_particles.end(); it != end; ++it) - (*it).render(); + (*it)->render(); } -void Emitter::update() +void ParticleEmitter::update() { ticks_t elapsedTicks = g_clock.ticks() - m_startTicks; // check if finished - if(m_duration > 0 && elapsedTicks > m_duration * 1000) { + if(m_duration >= 0 && elapsedTicks > m_duration * 1000) { m_finished = true; return; } // update particles for(auto it = m_particles.begin(), end = m_particles.end(); it != end;) { - if((*it).hasFinished()) { + const ParticlePtr& particle = *it; + if(particle->hasFinished()) { it = m_particles.erase(it); continue; } - (*it).update(); + particle->update(); ++it; } // create some particles + TexturePtr tex = g_textures.getTexture("circle2.png"); + int currentParticles = 1 + elapsedTicks / 1000.0 * m_particlesPerSecond; for(int i = m_createdParticles; i < currentParticles; ++i) { + + // \/ not working properly + float pRadius = Fw::randomRange(m_pPositionMinRadius, m_pPositionMaxRadius); + float pAngle = Fw::randomRange(m_pPositionMinAngle, m_pPositionMaxAngle) * 3.141592 / 180.0; + + Point pPosition = Point(cos(pAngle * pRadius), sin(pAngle * pRadius)); + + Size pSize = Size(Fw::randomRange(m_pMinSize.width(), m_pMaxSize.width()), Fw::randomRange(m_pMinSize.height(), m_pMaxSize.height())); + float pDuration = Fw::randomRange(m_pMinDuration, m_pMaxDuration); + // todo: add random data generation - m_particles.push_back(Particle(Rect(100, 100, 16, 16), 16, 8, 0, 0, 1.5)); + m_particles.push_back(ParticlePtr(new Particle(Rect(m_position + pPosition, pSize), 16, 8, 0, 0, pDuration, Color(255, 0, 0, 32), tex))); } m_createdParticles = currentParticles; } -void ParticlesSystem::add(Emitter emitter) +void ParticlesSystem::add(const ParticleEmitterPtr& emitter) { m_emitters.push_back(emitter); } @@ -98,17 +126,18 @@ void ParticlesSystem::add(Emitter emitter) void ParticlesSystem::render() { for(auto it = m_emitters.begin(), end = m_emitters.end(); it != end; ++it) - (*it).render(); + (*it)->render(); } void ParticlesSystem::update() { for(auto it = m_emitters.begin(), end = m_emitters.end(); it != end;) { - if((*it).hasFinished()) { + const ParticleEmitterPtr& emitter = *it; + if(emitter->hasFinished()) { it = m_emitters.erase(it); continue; } - (*it).update(); + emitter->update(); ++it; } } diff --git a/src/framework/graphics/particlessystem.h b/src/framework/graphics/particlessystem.h index f5a2ef1d..d9b99a63 100644 --- a/src/framework/graphics/particlessystem.h +++ b/src/framework/graphics/particlessystem.h @@ -1,7 +1,7 @@ #include #include -struct Particle { +class Particle { public: Particle(const Rect& rect, float vx, float vy, float ax, float ay, float duration, const Color& color = Color(255, 255, 255), TexturePtr texture = nullptr); @@ -14,23 +14,24 @@ public: private: Rect m_rect; - - int m_ix, m_iy; - float m_vx, m_vy; - float m_ax, m_ay; - Color m_color; TexturePtr m_texture; + int m_ix, m_iy; + PointF m_s0, m_v, m_a; + float m_vx, m_vy; + float m_ax, m_ay; + float m_duration; ticks_t m_startTicks; bool m_finished; }; +typedef std::shared_ptr ParticlePtr; -class Emitter { +class ParticleEmitter { public: - Emitter(const Point& position, float duration, int particlesPerSecond); + ParticleEmitter(const Point& position, float duration, int particlesPerSecond); void render(); void update(); @@ -44,11 +45,14 @@ private: ticks_t m_startTicks; bool m_finished; int m_particlesPerSecond, m_createdParticles; - std::list m_particles; + std::list m_particles; + + // particles size + Size m_pMinSize, m_pMaxSize; // particles initial position related to emitter position - float positionMinRadius, positionMaxRadius; - float positionMinAngle, positionMaxAngle; + float m_pPositionMinRadius, m_pPositionMaxRadius; + float m_pPositionMinAngle, m_pPositionMaxAngle; // particles initial velocity float minVelocity, maxVelocity; @@ -58,16 +62,20 @@ private: float minAcceleration, maxAcceleration; float minAccelerationAngle, maxAccelerationAngle; + // particles duration + float m_pMinDuration, m_pMaxDuration; + // color ralated Color color; // texture related }; +typedef std::shared_ptr ParticleEmitterPtr; class Affector { public: - virtual void update() {}; + virtual void update() {} }; class Gravity270Affector : public Affector { @@ -79,12 +87,12 @@ public: class ParticlesSystem { public: - void add(Emitter emitter); + void add(const ParticleEmitterPtr& emitter); void render(); void update(); private: - std::list m_emitters; + std::list m_emitters; std::list m_affectors; }; diff --git a/src/otclient/net/protocolgameparse.cpp b/src/otclient/net/protocolgameparse.cpp index 4ed5c4d5..45d9b3d4 100644 --- a/src/otclient/net/protocolgameparse.cpp +++ b/src/otclient/net/protocolgameparse.cpp @@ -532,8 +532,7 @@ void ProtocolGame::parseMagicEffect(InputMessage& msg) // test particles ParticlesSystem particlesSystem; - Emitter emitter = Emitter(Point(100, 100), 5, 1); - particlesSystem.add(emitter); + particlesSystem.add(ParticleEmitterPtr(new ParticleEmitter(Point(100, 100), -1, 40))); g_particlesManager.add(particlesSystem); }