[+] Added drawlevel sorting for particles

This commit is contained in:
cybermind 2013-05-09 11:07:50 +06:00
parent b9fb1bfd1b
commit a63a4fff61
8 changed files with 118 additions and 41 deletions

View file

@ -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<CParticle *> &table);
void endDraw();
void update();
void add(CParticle *particle);

View file

@ -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<CUnit *> unittable;
std::vector<Missile *> missiletable;
std::vector<CParticle *> 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) {
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,9 +401,11 @@ 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();

View file

@ -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;
}
//@}

View file

@ -34,6 +34,8 @@
#include "ui.h"
#include "video.h"
#include <algorithm>
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<CParticle *> &table)
{
this->vp = &vp;
std::vector<CParticle *>::iterator i;
for (i = particles.begin(); i != particles.end(); ++i) {
if ((*i)->isVisible(vp)) {
(*i)->draw();
for (std::vector<CParticle *>::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;
}

View file

@ -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;
}

View file

@ -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);
}
//@}

View file

@ -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;
}

View file

@ -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