diff --git a/src/include/particle.h b/src/include/particle.h index 9338377fa..cfee2019f 100644 --- a/src/include/particle.h +++ b/src/include/particle.h @@ -77,8 +77,8 @@ public: class CParticle { public: - CParticle(CPosition position) : - pos(position), destroyed(false) + CParticle(CPosition position, int drawlevel = 0) : + pos(position), destroyed(false), drawLevel(drawlevel) {} virtual ~CParticle() {} @@ -91,16 +91,20 @@ public: virtual CParticle *clone() = 0; + int getDrawLevel() const { return drawLevel; } + void setDrawLevel(int value) { drawLevel = value; } + protected: CPosition pos; bool destroyed; + int drawLevel; }; class StaticParticle : public CParticle { public: - StaticParticle(CPosition position, GraphicAnimation *flame); + StaticParticle(CPosition position, GraphicAnimation *flame, int drawlevel = 0); virtual ~StaticParticle(); virtual bool isVisible(const CViewport &vp) const; @@ -120,13 +124,17 @@ public: CChunkParticle(CPosition position, GraphicAnimation *smokeAnimation, GraphicAnimation *debrisAnimation, GraphicAnimation *destroyAnimation, int minVelocity = 0, int maxVelocity = 400, - int minTrajectoryAngle = 77, int maxTTL = 0); + int minTrajectoryAngle = 77, int maxTTL = 0, int drawlevel = 0); virtual ~CChunkParticle(); virtual bool isVisible(const CViewport &vp) const; virtual void draw(); virtual void update(int ticks); virtual CParticle *clone(); + int getSmokeDrawLevel() const { return smokeDrawLevel; } + int getDestroyDrawLevel() const { return destroyDrawLevel; } + void setSmokeDrawLevel(int value) { smokeDrawLevel = value; } + void setDestroyDrawLevel(int value) { destroyDrawLevel = value; } protected: CPosition initialPos; @@ -140,6 +148,8 @@ protected: int maxVelocity; int minTrajectoryAngle; float height; + int smokeDrawLevel; + int destroyDrawLevel; GraphicAnimation *debrisAnimation; GraphicAnimation *smokeAnimation; GraphicAnimation *destroyAnimation; @@ -155,7 +165,7 @@ protected: class CSmokeParticle : public CParticle { public: - CSmokeParticle(CPosition position, GraphicAnimation *animation, float speedx = 0, float speedy = -22.0f); + CSmokeParticle(CPosition position, GraphicAnimation *animation, float speedx = 0, float speedy = -22.0f, int drawlevel = 0); virtual ~CSmokeParticle(); virtual bool isVisible(const CViewport &vp) const; @@ -174,7 +184,7 @@ protected: class CRadialParticle : public CParticle { public: - CRadialParticle(CPosition position, GraphicAnimation *animation, int maxSpeed); + CRadialParticle(CPosition position, GraphicAnimation *animation, int maxSpeed, int drawlevel = 0); virtual ~CRadialParticle(); virtual bool isVisible(const CViewport &vp) const; @@ -199,7 +209,9 @@ public: static void init(); static void exit(); - void draw(const CViewport &vp); + void prepareToDraw(const CViewport &vp, std::vector &table); + void endDraw(); + void update(); void add(CParticle *particle); diff --git a/src/map/map_draw.cpp b/src/map/map_draw.cpp index dd3da8fbe..496e59798 100644 --- a/src/map/map_draw.cpp +++ b/src/map/map_draw.cpp @@ -332,25 +332,68 @@ void CViewport::Draw() const CurrentViewport = this; { + // Now we need to sort units, missiles, particles by draw level and draw them std::vector unittable; std::vector missiletable; + std::vector particletable; - // We find and sort units after draw level. FindAndSortUnits(*this, unittable); const size_t nunits = unittable.size(); FindAndSortMissiles(*this, missiletable); const size_t nmissiles = missiletable.size(); + ParticleManager.prepareToDraw(*this, particletable); + const size_t nparticles = particletable.size(); + size_t i = 0; size_t j = 0; + size_t k = 0; - while (i < nunits && j < nmissiles) { - if (unittable[i]->Type->DrawLevel <= missiletable[j]->Type->DrawLevel) { - unittable[i]->Draw(*this); - ++i; - } else { - missiletable[j]->DrawMissile(*this); - ++j; - } + + while ((i < nunits && j < nmissiles) || (i < nunits && k < nparticles) + || (j < nmissiles && k < nparticles)) { + if (i == nunits) { + if (missiletable[j]->Type->DrawLevel < particletable[k]->getDrawLevel()) { + missiletable[j]->DrawMissile(*this); + ++j; + } else { + particletable[k]->draw(); + ++k; + } + } else if (j == nmissiles) { + if (unittable[i]->Type->DrawLevel < particletable[k]->getDrawLevel()) { + unittable[i]->Draw(*this); + ++i; + } else { + particletable[k]->draw(); + ++k; + } + } else if (k == nparticles) { + if (unittable[i]->Type->DrawLevel < missiletable[j]->Type->DrawLevel) { + unittable[i]->Draw(*this); + ++i; + } else { + missiletable[j]->DrawMissile(*this); + ++j; + } + } else { + if (unittable[i]->Type->DrawLevel <= missiletable[j]->Type->DrawLevel) { + if (unittable[i]->Type->DrawLevel < particletable[k]->getDrawLevel()) { + unittable[i]->Draw(*this); + ++i; + } else { + particletable[k]->draw(); + ++k; + } + } else { + if (missiletable[j]->Type->DrawLevel < particletable[k]->getDrawLevel()) { + missiletable[j]->DrawMissile(*this); + ++j; + } else { + particletable[k]->draw(); + ++k; + } + } + } } for (; i < nunits; ++i) { unittable[i]->Draw(*this); @@ -358,10 +401,12 @@ void CViewport::Draw() const for (; j < nmissiles; ++j) { missiletable[j]->DrawMissile(*this); } + for (; k < nparticles; ++k) { + particletable[k]->draw(); + } + ParticleManager.endDraw(); } - ParticleManager.draw(*this); - this->DrawMapFogOfWar(); // diff --git a/src/particle/chunkparticle.cpp b/src/particle/chunkparticle.cpp index e858974a5..b886c5efa 100644 --- a/src/particle/chunkparticle.cpp +++ b/src/particle/chunkparticle.cpp @@ -46,8 +46,8 @@ static inline float deg2rad(int degrees) CChunkParticle::CChunkParticle(CPosition position, GraphicAnimation *smokeAnimation, GraphicAnimation *debrisAnimation, GraphicAnimation *destroyAnimation, - int minVelocity, int maxVelocity, int minTrajectoryAngle, int maxTTL) : - CParticle(position), initialPos(position), maxTTL(maxTTL), nextSmokeTicks(0), + int minVelocity, int maxVelocity, int minTrajectoryAngle, int maxTTL, int drawlevel) : + CParticle(position, drawlevel), initialPos(position), maxTTL(maxTTL), nextSmokeTicks(0), age(0), height(0.f) { float radians = deg2rad(MyRand() % 360); @@ -112,7 +112,7 @@ void CChunkParticle::update(int ticks) if (destroyAnimation) { CPosition p(pos.x, calculateScreenPos(pos.y, height)); GraphicAnimation *destroyanimation = destroyAnimation->clone(); - StaticParticle *destroy = new StaticParticle(p, destroyanimation); + StaticParticle *destroy = new StaticParticle(p, destroyanimation, destroyDrawLevel); ParticleManager.add(destroy); } @@ -126,7 +126,7 @@ void CChunkParticle::update(int ticks) if (age > nextSmokeTicks) { CPosition p(pos.x, calculateScreenPos(pos.y, height)); GraphicAnimation *smokeanimation = smokeAnimation->clone(); - CSmokeParticle *smoke = new CSmokeParticle(p, smokeanimation); + CSmokeParticle *smoke = new CSmokeParticle(p, smokeanimation, 0, -22.0f, smokeDrawLevel); ParticleManager.add(smoke); nextSmokeTicks += MyRand() % randSmokeTicks + minSmokeTicks; @@ -151,7 +151,10 @@ void CChunkParticle::update(int ticks) CParticle *CChunkParticle::clone() { - return new CChunkParticle(pos, smokeAnimation, debrisAnimation, destroyAnimation, minVelocity, maxVelocity, minTrajectoryAngle, maxTTL); + CChunkParticle *particle = new CChunkParticle(pos, smokeAnimation, debrisAnimation, destroyAnimation, minVelocity, maxVelocity, minTrajectoryAngle, maxTTL, drawLevel); + particle->smokeDrawLevel = smokeDrawLevel; + particle->destroyDrawLevel = destroyDrawLevel; + return particle; } //@} diff --git a/src/particle/particlemanager.cpp b/src/particle/particlemanager.cpp index 8025f3394..8e1e12270 100644 --- a/src/particle/particlemanager.cpp +++ b/src/particle/particlemanager.cpp @@ -34,6 +34,8 @@ #include "ui.h" #include "video.h" +#include + CParticleManager ParticleManager; @@ -70,17 +72,27 @@ void CParticleManager::clear() new_particles.clear(); } -void CParticleManager::draw(const CViewport &vp) +static inline bool DrawLevelCompare(const CParticle *lhs, const CParticle *rhs) +{ + return lhs->getDrawLevel() < rhs->getDrawLevel(); +} + +void CParticleManager::prepareToDraw(const CViewport &vp, std::vector &table) { this->vp = &vp; - std::vector::iterator i; - for (i = particles.begin(); i != particles.end(); ++i) { - if ((*i)->isVisible(vp)) { - (*i)->draw(); + for (std::vector::iterator it = particles.begin(); it != particles.end(); ++it) { + CParticle &particle = **it; + if (particle.isVisible(vp)) { + table.push_back(&particle); } } + std::sort(table.begin(), table.end(), DrawLevelCompare); +} + +void CParticleManager::endDraw() +{ this->vp = NULL; } diff --git a/src/particle/radialparticle.cpp b/src/particle/radialparticle.cpp index e27008312..20cfb008e 100644 --- a/src/particle/radialparticle.cpp +++ b/src/particle/radialparticle.cpp @@ -34,8 +34,8 @@ #include "stratagus.h" #include "particle.h" -CRadialParticle::CRadialParticle(CPosition position, GraphicAnimation *animation, int maxSpeed) : - CParticle(position) +CRadialParticle::CRadialParticle(CPosition position, GraphicAnimation *animation, int maxSpeed, int drawlevel) : + CParticle(position, drawlevel) { Assert(animation); this->animation = animation->clone(); @@ -76,7 +76,7 @@ void CRadialParticle::update(int ticks) CParticle *CRadialParticle::clone() { - CParticle *p = new CRadialParticle(pos, animation, maxSpeed); + CParticle *p = new CRadialParticle(pos, animation, maxSpeed, drawLevel); return p; } diff --git a/src/particle/smokeparticle.cpp b/src/particle/smokeparticle.cpp index e0cbdac18..b735ebaff 100644 --- a/src/particle/smokeparticle.cpp +++ b/src/particle/smokeparticle.cpp @@ -36,8 +36,8 @@ CSmokeParticle::CSmokeParticle(CPosition position, GraphicAnimation *smoke, - float speedx, float speedy) : - CParticle(position) + float speedx, float speedy, int drawlevel) : + CParticle(position, drawlevel) { Assert(smoke); this->puff = smoke->clone(); @@ -77,7 +77,7 @@ void CSmokeParticle::update(int ticks) CParticle *CSmokeParticle::clone() { - return new CSmokeParticle(pos, puff, speedVector.x, speedVector.y); + return new CSmokeParticle(pos, puff, speedVector.x, speedVector.y, drawLevel); } //@} diff --git a/src/particle/staticparticle.cpp b/src/particle/staticparticle.cpp index e0cfa6f54..a2c32d880 100644 --- a/src/particle/staticparticle.cpp +++ b/src/particle/staticparticle.cpp @@ -33,8 +33,8 @@ #include "particle.h" -StaticParticle::StaticParticle(CPosition position, GraphicAnimation *animation) : - CParticle(position) +StaticParticle::StaticParticle(CPosition position, GraphicAnimation *animation, int drawlevel) : + CParticle(position, drawlevel) { Assert(animation); this->animation = animation->clone(); @@ -66,7 +66,7 @@ void StaticParticle::update(int ticks) CParticle *StaticParticle::clone() { - CParticle *p = new StaticParticle(pos, animation); + CParticle *p = new StaticParticle(pos, animation, drawLevel); return p; } diff --git a/src/tolua/particle.pkg b/src/tolua/particle.pkg index 3d157495d..db7d6172a 100644 --- a/src/tolua/particle.pkg +++ b/src/tolua/particle.pkg @@ -16,30 +16,35 @@ class GraphicAnimation class CParticle { virtual CParticle* clone(); + void setDrawLevel(int value); }; class StaticParticle : public CParticle { public: - StaticParticle(CPosition position, GraphicAnimation *animation); + StaticParticle(CPosition position, GraphicAnimation *animation, int drawlevel = 0); }; class CChunkParticle : public CParticle { public: - CChunkParticle(CPosition position, GraphicAnimation *smokeAnimation, GraphicAnimation *debrisAnimation, GraphicAnimation *destroyAnimation, int minVelocity = 0, int maxVelocity = 400, int minTrajectoryAngle = 77, int maxTTL = 0); + CChunkParticle(CPosition position, GraphicAnimation *smokeAnimation, GraphicAnimation *debrisAnimation, GraphicAnimation *destroyAnimation, int minVelocity = 0, int maxVelocity = 400, int minTrajectoryAngle = 77, int maxTTL = 0, int drawlevel = 0); + int getSmokeDrawLevel() const; + int getDestroyDrawLevel() const; + void setSmokeDrawLevel(int value); + void setDestroyDrawLevel(int value); }; class CSmokeParticle : public CParticle { public: - CSmokeParticle(CPosition position, GraphicAnimation *animation, float speedx = 0, float speedy = -22.0); + CSmokeParticle(CPosition position, GraphicAnimation *animation, float speedx = 0, float speedy = -22.0, int drawlevel = 0); }; class CRadialParticle : public CParticle { public: - CRadialParticle(CPosition position, GraphicAnimation *smokeAnimation, int maxSpeed); + CRadialParticle(CPosition position, GraphicAnimation *smokeAnimation, int maxSpeed, int drawlevel = 0); }; class CParticleManager